From d6e0d82c328b4f9d733364382cce0941a601e91a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 23:09:12 -0500 Subject: [PATCH] translate-c: back to *c_void for opaque types See #1059 --- src/analyze.cpp | 2 +- src/ir.cpp | 13 +++++++++---- src/translate_c.cpp | 34 ++++++++++++++++++++++++++++++++-- test/compile_errors.zig | 10 ++++++++++ test/translate_c.zig | 20 ++++++++++---------- 5 files changed, 62 insertions(+), 17 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 55deafb3a8..1917784511 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -437,7 +437,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons // move this to a parameter bool allow_zero = (ptr_len == PtrLenC); assert(!type_is_invalid(child_type)); - assert(ptr_len != PtrLenUnknown || child_type->id != ZigTypeIdOpaque); + assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque); if (byte_alignment != 0) { uint32_t abi_alignment = get_abi_alignment(g, child_type); diff --git a/src/ir.cpp b/src/ir.cpp index 7c46b21717..707eac0181 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -21205,10 +21205,15 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct } else if (child_type->id == ZigTypeIdOpaque && instruction->ptr_len == PtrLenUnknown) { ir_add_error(ira, &instruction->base, buf_sprintf("unknown-length pointer to opaque")); return ira->codegen->invalid_instruction; - } else if (instruction->ptr_len == PtrLenC && !type_allowed_in_extern(ira->codegen, child_type)) { - ir_add_error(ira, &instruction->base, - buf_sprintf("C pointers cannot point to non-C-ABI-compatible type '%s'", buf_ptr(&child_type->name))); - return ira->codegen->invalid_instruction; + } else if (instruction->ptr_len == PtrLenC) { + if (!type_allowed_in_extern(ira->codegen, child_type)) { + ir_add_error(ira, &instruction->base, + buf_sprintf("C pointers cannot point to non-C-ABI-compatible type '%s'", buf_ptr(&child_type->name))); + return ira->codegen->invalid_instruction; + } else if (child_type->id == ZigTypeIdOpaque) { + ir_add_error(ira, &instruction->base, buf_sprintf("C pointers cannot point opaque types")); + return ira->codegen->invalid_instruction; + } } uint32_t align_bytes; diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 63f04dae6c..42a7ab436d 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -763,6 +763,30 @@ static bool qual_type_has_wrapping_overflow(Context *c, QualType qt) { } } +static bool type_is_opaque(Context *c, const Type *ty, const SourceLocation &source_loc) { + switch (ty->getTypeClass()) { + case Type::Builtin: { + const BuiltinType *builtin_ty = static_cast(ty); + return builtin_ty->getKind() == BuiltinType::Void; + } + case Type::Record: { + const RecordType *record_ty = static_cast(ty); + return record_ty->getDecl()->getDefinition() == nullptr; + } + case Type::Elaborated: { + const ElaboratedType *elaborated_ty = static_cast(ty); + return type_is_opaque(c, elaborated_ty->getNamedType().getTypePtr(), source_loc); + } + case Type::Typedef: { + const TypedefType *typedef_ty = static_cast(ty); + const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); + return type_is_opaque(c, typedef_decl->getUnderlyingType().getTypePtr(), source_loc); + } + default: + return false; + } +} + static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &source_loc) { switch (ty->getTypeClass()) { case Type::Builtin: @@ -912,8 +936,14 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou return trans_create_node_prefix_op(c, PrefixOpOptional, child_node); } - return trans_create_node_ptr_type(c, child_qt.isConstQualified(), - child_qt.isVolatileQualified(), child_node, PtrLenC); + if (type_is_opaque(c, child_qt.getTypePtr(), source_loc)) { + AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(), + child_qt.isVolatileQualified(), child_node, PtrLenSingle); + return trans_create_node_prefix_op(c, PrefixOpOptional, pointer_node); + } else { + return trans_create_node_ptr_type(c, child_qt.isConstQualified(), + child_qt.isVolatileQualified(), child_node, PtrLenC); + } } case Type::Typedef: { diff --git a/test/compile_errors.zig b/test/compile_errors.zig index a2fd901197..1f641a9052 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,16 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest( + "C pointer to c_void", + \\export fn a() void { + \\ var x: *c_void = undefined; + \\ var y: [*c]c_void = x; + \\} + , + ".tmp_source.zig:3:12: error: C pointers cannot point opaque types", + ); + cases.addTest( "directly embedding opaque type in struct and union", \\const O = @OpaqueType(); diff --git a/test/translate_c.zig b/test/translate_c.zig index b87b962edc..7385427dbe 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -202,7 +202,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { cases.add("restrict -> noalias", \\void foo(void *restrict bar, void *restrict); , - \\pub extern fn foo(noalias bar: [*c]c_void, noalias arg1: [*c]c_void) void; + \\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void; ); cases.add("simple struct", @@ -275,7 +275,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , \\pub const struct_Foo = @OpaqueType(); , - \\pub extern fn some_func(foo: [*c]struct_Foo, x: c_int) [*c]struct_Foo; + \\pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo; , \\pub const Foo = struct_Foo; ); @@ -336,7 +336,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , \\pub const Foo = c_void; , - \\pub extern fn fun(a: [*c]Foo) Foo; + \\pub extern fn fun(a: ?*Foo) Foo; ); cases.add("generate inline func for #define global extern fn", @@ -608,7 +608,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return 6; \\} , - \\pub export fn and_or_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int { + \\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?*c_void) c_int { \\ if ((a != 0) and (b != 0)) return 0; \\ if ((b != 0) and (c != 0)) return 1; \\ if ((a != 0) and (c != 0)) return 2; @@ -756,8 +756,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return x; \\} , - \\pub export fn foo(x: [*c]c_ushort) [*c]c_void { - \\ return @ptrCast([*c]c_void, x); + \\pub export fn foo(x: [*c]c_ushort) ?*c_void { + \\ return @ptrCast(?*c_void, x); \\} ); @@ -1276,7 +1276,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return !c; \\} , - \\pub fn foo(a: c_int, b: f32, c: [*c]c_void) c_int { + \\pub fn foo(a: c_int, b: f32, c: ?*c_void) c_int { \\ return !(a == 0); \\ return !(a != 0); \\ return !(b != 0); @@ -1334,7 +1334,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ B, \\ C, \\}; - \\pub fn if_none_bool(a: c_int, b: f32, c: [*c]c_void, d: enum_SomeEnum) c_int { + \\pub fn if_none_bool(a: c_int, b: f32, c: ?*c_void, d: enum_SomeEnum) c_int { \\ if (a != 0) return 0; \\ if (b != 0) return 1; \\ if (c != 0) return 2; @@ -1351,7 +1351,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return 3; \\} , - \\pub fn while_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int { + \\pub fn while_none_bool(a: c_int, b: f32, c: ?*c_void) c_int { \\ while (a != 0) return 0; \\ while (b != 0) return 1; \\ while (c != 0) return 2; @@ -1367,7 +1367,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return 3; \\} , - \\pub fn for_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int { + \\pub fn for_none_bool(a: c_int, b: f32, c: ?*c_void) c_int { \\ while (a != 0) return 0; \\ while (b != 0) return 1; \\ while (c != 0) return 2;