| author | |
| committer | |
| log | d6e0d82c328b4f9d733364382cce0941a601e91a |
| tree | ba5848ece64d705fa436fa4924b8e59a1a9a3dce |
| parent | d5bbd748711abc82272199869cf70faf1ea30f52 |
| signature | Commit is signed but in an unrecognized format. |
See #10595 files changed, 62 insertions(+), 17 deletions(-)
src/analyze.cpp+1-1| ... | @@ -437,7 +437,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons | ... | @@ -437,7 +437,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons |
| 437 | // move this to a parameter | 437 | // move this to a parameter |
| 438 | bool allow_zero = (ptr_len == PtrLenC); | 438 | bool allow_zero = (ptr_len == PtrLenC); |
| 439 | assert(!type_is_invalid(child_type)); | 439 | assert(!type_is_invalid(child_type)); |
| 440 | assert(ptr_len != PtrLenUnknown || child_type->id != ZigTypeIdOpaque); | 440 | assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque); |
| 441 | 441 | ||
| 442 | if (byte_alignment != 0) { | 442 | if (byte_alignment != 0) { |
| 443 | uint32_t abi_alignment = get_abi_alignment(g, child_type); | 443 | uint32_t abi_alignment = get_abi_alignment(g, child_type); |
src/ir.cpp+9-4| ... | @@ -21205,10 +21205,15 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct | ... | @@ -21205,10 +21205,15 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct |
| 21205 | } else if (child_type->id == ZigTypeIdOpaque && instruction->ptr_len == PtrLenUnknown) { | 21205 | } else if (child_type->id == ZigTypeIdOpaque && instruction->ptr_len == PtrLenUnknown) { |
| 21206 | ir_add_error(ira, &instruction->base, buf_sprintf("unknown-length pointer to opaque")); | 21206 | ir_add_error(ira, &instruction->base, buf_sprintf("unknown-length pointer to opaque")); |
| 21207 | return ira->codegen->invalid_instruction; | 21207 | return ira->codegen->invalid_instruction; |
| 21208 | } else if (instruction->ptr_len == PtrLenC && !type_allowed_in_extern(ira->codegen, child_type)) { | 21208 | } else if (instruction->ptr_len == PtrLenC) { |
| 21209 | ir_add_error(ira, &instruction->base, | 21209 | if (!type_allowed_in_extern(ira->codegen, child_type)) { |
| 21210 | buf_sprintf("C pointers cannot point to non-C-ABI-compatible type '%s'", buf_ptr(&child_type->name))); | 21210 | ir_add_error(ira, &instruction->base, |
| 21211 | return ira->codegen->invalid_instruction; | 21211 | buf_sprintf("C pointers cannot point to non-C-ABI-compatible type '%s'", buf_ptr(&child_type->name))); |
| 21212 | return ira->codegen->invalid_instruction; | ||
| 21213 | } else if (child_type->id == ZigTypeIdOpaque) { | ||
| 21214 | ir_add_error(ira, &instruction->base, buf_sprintf("C pointers cannot point opaque types")); | ||
| 21215 | return ira->codegen->invalid_instruction; | ||
| 21216 | } | ||
| 21212 | } | 21217 | } |
| 21213 | 21218 | ||
| 21214 | uint32_t align_bytes; | 21219 | uint32_t align_bytes; |
src/translate_c.cpp+32-2| ... | @@ -763,6 +763,30 @@ static bool qual_type_has_wrapping_overflow(Context *c, QualType qt) { | ... | @@ -763,6 +763,30 @@ static bool qual_type_has_wrapping_overflow(Context *c, QualType qt) { |
| 763 | } | 763 | } |
| 764 | } | 764 | } |
| 765 | 765 | ||
| 766 | static bool type_is_opaque(Context *c, const Type *ty, const SourceLocation &source_loc) { | ||
| 767 | switch (ty->getTypeClass()) { | ||
| 768 | case Type::Builtin: { | ||
| 769 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(ty); | ||
| 770 | return builtin_ty->getKind() == BuiltinType::Void; | ||
| 771 | } | ||
| 772 | case Type::Record: { | ||
| 773 | const RecordType *record_ty = static_cast<const RecordType*>(ty); | ||
| 774 | return record_ty->getDecl()->getDefinition() == nullptr; | ||
| 775 | } | ||
| 776 | case Type::Elaborated: { | ||
| 777 | const ElaboratedType *elaborated_ty = static_cast<const ElaboratedType*>(ty); | ||
| 778 | return type_is_opaque(c, elaborated_ty->getNamedType().getTypePtr(), source_loc); | ||
| 779 | } | ||
| 780 | case Type::Typedef: { | ||
| 781 | const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty); | ||
| 782 | const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); | ||
| 783 | return type_is_opaque(c, typedef_decl->getUnderlyingType().getTypePtr(), source_loc); | ||
| 784 | } | ||
| 785 | default: | ||
| 786 | return false; | ||
| 787 | } | ||
| 788 | } | ||
| 789 | |||
| 766 | static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &source_loc) { | 790 | static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &source_loc) { |
| 767 | switch (ty->getTypeClass()) { | 791 | switch (ty->getTypeClass()) { |
| 768 | case Type::Builtin: | 792 | case Type::Builtin: |
| ... | @@ -912,8 +936,14 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou | ... | @@ -912,8 +936,14 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou |
| 912 | return trans_create_node_prefix_op(c, PrefixOpOptional, child_node); | 936 | return trans_create_node_prefix_op(c, PrefixOpOptional, child_node); |
| 913 | } | 937 | } |
| 914 | 938 | ||
| 915 | return trans_create_node_ptr_type(c, child_qt.isConstQualified(), | 939 | if (type_is_opaque(c, child_qt.getTypePtr(), source_loc)) { |
| 916 | child_qt.isVolatileQualified(), child_node, PtrLenC); | 940 | AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(), |
| 941 | child_qt.isVolatileQualified(), child_node, PtrLenSingle); | ||
| 942 | return trans_create_node_prefix_op(c, PrefixOpOptional, pointer_node); | ||
| 943 | } else { | ||
| 944 | return trans_create_node_ptr_type(c, child_qt.isConstQualified(), | ||
| 945 | child_qt.isVolatileQualified(), child_node, PtrLenC); | ||
| 946 | } | ||
| 917 | } | 947 | } |
| 918 | case Type::Typedef: | 948 | case Type::Typedef: |
| 919 | { | 949 | { |
test/compile_errors.zig+10| ... | @@ -1,6 +1,16 @@ | ... | @@ -1,6 +1,16 @@ |
| 1 | const tests = @import("tests.zig"); | 1 | const tests = @import("tests.zig"); |
| 2 | 2 | ||
| 3 | pub fn addCases(cases: *tests.CompileErrorContext) void { | 3 | pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4 | cases.addTest( | ||
| 5 | "C pointer to c_void", | ||
| 6 | \\export fn a() void { | ||
| 7 | \\ var x: *c_void = undefined; | ||
| 8 | \\ var y: [*c]c_void = x; | ||
| 9 | \\} | ||
| 10 | , | ||
| 11 | ".tmp_source.zig:3:12: error: C pointers cannot point opaque types", | ||
| 12 | ); | ||
| 13 | |||
| 4 | cases.addTest( | 14 | cases.addTest( |
| 5 | "directly embedding opaque type in struct and union", | 15 | "directly embedding opaque type in struct and union", |
| 6 | \\const O = @OpaqueType(); | 16 | \\const O = @OpaqueType(); |
test/translate_c.zig+10-10| ... | @@ -202,7 +202,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -202,7 +202,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 202 | cases.add("restrict -> noalias", | 202 | cases.add("restrict -> noalias", |
| 203 | \\void foo(void *restrict bar, void *restrict); | 203 | \\void foo(void *restrict bar, void *restrict); |
| 204 | , | 204 | , |
| 205 | \\pub extern fn foo(noalias bar: [*c]c_void, noalias arg1: [*c]c_void) void; | 205 | \\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void; |
| 206 | ); | 206 | ); |
| 207 | 207 | ||
| 208 | cases.add("simple struct", | 208 | cases.add("simple struct", |
| ... | @@ -275,7 +275,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -275,7 +275,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 275 | , | 275 | , |
| 276 | \\pub const struct_Foo = @OpaqueType(); | 276 | \\pub const struct_Foo = @OpaqueType(); |
| 277 | , | 277 | , |
| 278 | \\pub extern fn some_func(foo: [*c]struct_Foo, x: c_int) [*c]struct_Foo; | 278 | \\pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo; |
| 279 | , | 279 | , |
| 280 | \\pub const Foo = struct_Foo; | 280 | \\pub const Foo = struct_Foo; |
| 281 | ); | 281 | ); |
| ... | @@ -336,7 +336,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -336,7 +336,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 336 | , | 336 | , |
| 337 | \\pub const Foo = c_void; | 337 | \\pub const Foo = c_void; |
| 338 | , | 338 | , |
| 339 | \\pub extern fn fun(a: [*c]Foo) Foo; | 339 | \\pub extern fn fun(a: ?*Foo) Foo; |
| 340 | ); | 340 | ); |
| 341 | 341 | ||
| 342 | cases.add("generate inline func for #define global extern fn", | 342 | cases.add("generate inline func for #define global extern fn", |
| ... | @@ -608,7 +608,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -608,7 +608,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 608 | \\ return 6; | 608 | \\ return 6; |
| 609 | \\} | 609 | \\} |
| 610 | , | 610 | , |
| 611 | \\pub export fn and_or_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int { | 611 | \\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?*c_void) c_int { |
| 612 | \\ if ((a != 0) and (b != 0)) return 0; | 612 | \\ if ((a != 0) and (b != 0)) return 0; |
| 613 | \\ if ((b != 0) and (c != 0)) return 1; | 613 | \\ if ((b != 0) and (c != 0)) return 1; |
| 614 | \\ if ((a != 0) and (c != 0)) return 2; | 614 | \\ if ((a != 0) and (c != 0)) return 2; |
| ... | @@ -756,8 +756,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -756,8 +756,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 756 | \\ return x; | 756 | \\ return x; |
| 757 | \\} | 757 | \\} |
| 758 | , | 758 | , |
| 759 | \\pub export fn foo(x: [*c]c_ushort) [*c]c_void { | 759 | \\pub export fn foo(x: [*c]c_ushort) ?*c_void { |
| 760 | \\ return @ptrCast([*c]c_void, x); | 760 | \\ return @ptrCast(?*c_void, x); |
| 761 | \\} | 761 | \\} |
| 762 | ); | 762 | ); |
| 763 | 763 | ||
| ... | @@ -1276,7 +1276,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -1276,7 +1276,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1276 | \\ return !c; | 1276 | \\ return !c; |
| 1277 | \\} | 1277 | \\} |
| 1278 | , | 1278 | , |
| 1279 | \\pub fn foo(a: c_int, b: f32, c: [*c]c_void) c_int { | 1279 | \\pub fn foo(a: c_int, b: f32, c: ?*c_void) c_int { |
| 1280 | \\ return !(a == 0); | 1280 | \\ return !(a == 0); |
| 1281 | \\ return !(a != 0); | 1281 | \\ return !(a != 0); |
| 1282 | \\ return !(b != 0); | 1282 | \\ return !(b != 0); |
| ... | @@ -1334,7 +1334,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -1334,7 +1334,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1334 | \\ B, | 1334 | \\ B, |
| 1335 | \\ C, | 1335 | \\ C, |
| 1336 | \\}; | 1336 | \\}; |
| 1337 | \\pub fn if_none_bool(a: c_int, b: f32, c: [*c]c_void, d: enum_SomeEnum) c_int { | 1337 | \\pub fn if_none_bool(a: c_int, b: f32, c: ?*c_void, d: enum_SomeEnum) c_int { |
| 1338 | \\ if (a != 0) return 0; | 1338 | \\ if (a != 0) return 0; |
| 1339 | \\ if (b != 0) return 1; | 1339 | \\ if (b != 0) return 1; |
| 1340 | \\ if (c != 0) return 2; | 1340 | \\ if (c != 0) return 2; |
| ... | @@ -1351,7 +1351,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -1351,7 +1351,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1351 | \\ return 3; | 1351 | \\ return 3; |
| 1352 | \\} | 1352 | \\} |
| 1353 | , | 1353 | , |
| 1354 | \\pub fn while_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int { | 1354 | \\pub fn while_none_bool(a: c_int, b: f32, c: ?*c_void) c_int { |
| 1355 | \\ while (a != 0) return 0; | 1355 | \\ while (a != 0) return 0; |
| 1356 | \\ while (b != 0) return 1; | 1356 | \\ while (b != 0) return 1; |
| 1357 | \\ while (c != 0) return 2; | 1357 | \\ while (c != 0) return 2; |
| ... | @@ -1367,7 +1367,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -1367,7 +1367,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1367 | \\ return 3; | 1367 | \\ return 3; |
| 1368 | \\} | 1368 | \\} |
| 1369 | , | 1369 | , |
| 1370 | \\pub fn for_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int { | 1370 | \\pub fn for_none_bool(a: c_int, b: f32, c: ?*c_void) c_int { |
| 1371 | \\ while (a != 0) return 0; | 1371 | \\ while (a != 0) return 0; |
| 1372 | \\ while (b != 0) return 1; | 1372 | \\ while (b != 0) return 1; |
| 1373 | \\ while (c != 0) return 2; | 1373 | \\ while (c != 0) return 2; |