diff --git a/src/stage1/analyze.cpp b/src/stage1/analyze.cpp index bc9d265bd1..fb1360727c 100644 --- a/src/stage1/analyze.cpp +++ b/src/stage1/analyze.cpp @@ -1754,7 +1754,7 @@ static Error emit_error_unless_type_allowed_in_packed_union(CodeGen *g, ZigType return emit_error_unless_type_allowed_in_packed_container(g, type_entry, source_node, "union"); } -Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, bool *result) { +Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, ExternPosition position, bool *result) { Error err; switch (type_entry->id) { case ZigTypeIdInvalid: @@ -1773,8 +1773,10 @@ Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, bool *result) { case ZigTypeIdAnyFrame: *result = false; return ErrorNone; - case ZigTypeIdOpaque: case ZigTypeIdUnreachable: + *result = position == ExternPositionFunctionReturn; + return ErrorNone; + case ZigTypeIdOpaque: case ZigTypeIdBool: *result = true; return ErrorNone; @@ -1792,23 +1794,27 @@ Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, bool *result) { return ErrorNone; } case ZigTypeIdVector: - return type_allowed_in_extern(g, type_entry->data.vector.elem_type, result); + return type_allowed_in_extern(g, type_entry->data.vector.elem_type, ExternPositionOther, result); case ZigTypeIdFloat: *result = true; return ErrorNone; case ZigTypeIdArray: - return type_allowed_in_extern(g, type_entry->data.array.child_type, result); + if ((err = type_allowed_in_extern(g, type_entry->data.array.child_type, ExternPositionOther, result))) + return err; + *result = *result && + position != ExternPositionFunctionParameter && + position != ExternPositionFunctionReturn; + return ErrorNone; case ZigTypeIdFn: *result = !calling_convention_allows_zig_types(type_entry->data.fn.fn_type_id.cc); return ErrorNone; case ZigTypeIdPointer: if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) return err; - if (!type_has_bits(g, type_entry)) { - *result = false; - return ErrorNone; - } - *result = true; + bool has_bits; + if ((err = type_has_bits2(g, type_entry, &has_bits))) + return err; + *result = has_bits; return ErrorNone; case ZigTypeIdStruct: *result = type_entry->data.structure.layout == ContainerLayoutExtern || @@ -1820,23 +1826,24 @@ Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, bool *result) { *result = false; return ErrorNone; } - if (!type_is_nonnull_ptr(g, child_type)) { + bool is_nonnull_ptr; + if ((err = type_is_nonnull_ptr2(g, child_type, &is_nonnull_ptr))) + return err; + if (!is_nonnull_ptr) { *result = false; return ErrorNone; } - return type_allowed_in_extern(g, child_type, result); + return type_allowed_in_extern(g, child_type, ExternPositionOther, result); } 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; - } + if (type_entry->data.enumeration.has_explicit_tag_type) + return type_allowed_in_extern(g, tag_int_type, position, result); + *result = type_entry->data.enumeration.layout == ContainerLayoutExtern || + type_entry->data.enumeration.layout == ContainerLayoutPacked; + return ErrorNone; } case ZigTypeIdUnion: *result = type_entry->data.unionation.layout == ContainerLayoutExtern || @@ -1933,7 +1940,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc if (!calling_convention_allows_zig_types(fn_type_id.cc)) { bool ok_type; - if ((err = type_allowed_in_extern(g, type_entry, &ok_type))) + if ((err = type_allowed_in_extern(g, type_entry, ExternPositionFunctionParameter, &ok_type))) return g->builtin_types.entry_invalid; if (!ok_type) { add_node_error(g, param_node->data.param_decl.type, @@ -2038,7 +2045,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc if ((err = type_resolve(g, fn_type_id.return_type, ResolveStatusSizeKnown))) return g->builtin_types.entry_invalid; bool ok_type; - if ((err = type_allowed_in_extern(g, fn_type_id.return_type, &ok_type))) + if ((err = type_allowed_in_extern(g, fn_type_id.return_type, ExternPositionFunctionReturn, &ok_type))) return g->builtin_types.entry_invalid; if (!ok_type) { add_node_error(g, fn_proto->return_type, @@ -2357,7 +2364,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { if (struct_type->data.structure.layout == ContainerLayoutExtern) { bool ok_type; - if ((err = type_allowed_in_extern(g, field_type, &ok_type))) { + if ((err = type_allowed_in_extern(g, field_type, ExternPositionOther, &ok_type))) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; } @@ -2612,7 +2619,7 @@ static Error type_is_valid_extern_enum_tag(CodeGen *g, ZigType *ty, bool *result // signed char, a signed integer or an unsigned one. But GCC/Clang allow // other integral types as a compiler extension so let's accomodate them // aswell. - return type_allowed_in_extern(g, ty, result); + return type_allowed_in_extern(g, ty, ExternPositionOther, result); } static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { diff --git a/src/stage1/analyze.hpp b/src/stage1/analyze.hpp index 07601e6dea..d7a67826d5 100644 --- a/src/stage1/analyze.hpp +++ b/src/stage1/analyze.hpp @@ -50,7 +50,13 @@ bool handle_is_ptr(CodeGen *g, ZigType *type_entry); bool type_has_bits(CodeGen *g, ZigType *type_entry); Error type_has_bits2(CodeGen *g, ZigType *type_entry, bool *result); -Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, bool *result); +enum ExternPosition { + ExternPositionFunctionParameter, + ExternPositionFunctionReturn, + ExternPositionOther, // array element, struct field, optional element, etc +}; + +Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, ExternPosition position, bool *result); bool ptr_allows_addr_zero(ZigType *ptr_type); // Deprecated, use `type_is_nonnull_ptr2` diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp index 5ab667e831..c90f5f6309 100644 --- a/src/stage1/ir.cpp +++ b/src/stage1/ir.cpp @@ -18963,7 +18963,7 @@ static IrInstGen *ir_analyze_instruction_export(IrAnalyze *ira, IrInstSrcExport break; case ZigTypeIdArray: { bool ok_type; - if ((err = type_allowed_in_extern(ira->codegen, target->value->type->data.array.child_type, &ok_type))) + if ((err = type_allowed_in_extern(ira->codegen, target->value->type->data.array.child_type, ExternPositionOther, &ok_type))) return ira->codegen->invalid_inst_gen; if (!ok_type) { @@ -32745,7 +32745,7 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { return ErrorSemanticAnalyzeFail; } else if (lazy_ptr_type->ptr_len == PtrLenC) { bool ok_type; - if ((err = type_allowed_in_extern(ira->codegen, elem_type, &ok_type))) + if ((err = type_allowed_in_extern(ira->codegen, elem_type, ExternPositionOther, &ok_type))) return err; if (!ok_type) { ir_add_error(ira, &lazy_ptr_type->elem_type->base, diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 3156876959..44ee58f002 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2,6 +2,19 @@ const tests = @import("tests.zig"); const std = @import("std"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add("array in c exported function", + \\export fn zig_array(x: [10]u8) void { + \\ expect(std.mem.eql(u8, &x, "1234567890")); + \\} + \\ + \\export fn zig_return_array() [10]u8 { + \\ return "1234567890".*; + \\} + , &[_][]const u8{ + "tmp.zig:1:24: error: parameter of type '[10]u8' not allowed in function with calling convention 'C'", + "tmp.zig:5:30: error: return type '[10]u8' not allowed in function with calling convention 'C'", + }); + cases.add("@Type for exhaustive enum with undefined tag type", \\const TypeInfo = @import("builtin").TypeInfo; \\const Tag = @Type(.{ diff --git a/test/stage1/c_abi/cfuncs.c b/test/stage1/c_abi/cfuncs.c index 0e7bd2906f..0e8204779a 100644 --- a/test/stage1/c_abi/cfuncs.c +++ b/test/stage1/c_abi/cfuncs.c @@ -28,8 +28,6 @@ void zig_ptr(void *); void zig_bool(bool); -void zig_array(uint8_t[10]); - struct BigStruct { uint64_t a; uint64_t b; @@ -97,9 +95,6 @@ void run_c_tests(void) { zig_bool(true); - uint8_t array[10] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'}; - zig_array(array); - { struct BigStruct s = {1, 2, 3, 4, 5}; zig_big_struct(s); @@ -190,19 +185,6 @@ void c_five_floats(float a, float b, float c, float d, float e) { assert_or_panic(e == 5.0); } -void c_array(uint8_t x[10]) { - assert_or_panic(x[0] == '1'); - assert_or_panic(x[1] == '2'); - assert_or_panic(x[2] == '3'); - assert_or_panic(x[3] == '4'); - assert_or_panic(x[4] == '5'); - assert_or_panic(x[5] == '6'); - assert_or_panic(x[6] == '7'); - assert_or_panic(x[7] == '8'); - assert_or_panic(x[8] == '9'); - assert_or_panic(x[9] == '0'); -} - void c_big_struct(struct BigStruct x) { assert_or_panic(x.a == 1); assert_or_panic(x.b == 2); diff --git a/test/stage1/c_abi/main.zig b/test/stage1/c_abi/main.zig index 9090bb481e..18e9858da4 100644 --- a/test/stage1/c_abi/main.zig +++ b/test/stage1/c_abi/main.zig @@ -116,17 +116,6 @@ export fn zig_bool(x: bool) void { expect(x); } -extern fn c_array([10]u8) void; - -test "C ABI array" { - var array: [10]u8 = "1234567890".*; - c_array(array); -} - -export fn zig_array(x: [10]u8) void { - expect(std.mem.eql(u8, &x, "1234567890")); -} - const BigStruct = extern struct { a: u64, b: u64,