Commit d9e01be973

Andrew Kelley <andrew@ziglang.org>
2019-02-11 20:56:59
translate-c: use C pointer type everywhere
See #1059
1 parent 4a1b910
src/analyze.cpp
@@ -6872,3 +6872,12 @@ Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_no
 
     return ErrorNone;
 }
+
+const char *container_string(ContainerKind kind) {
+    switch (kind) {
+        case ContainerKindEnum: return "enum";
+        case ContainerKindStruct: return "struct";
+        case ContainerKindUnion: return "union";
+    }
+    zig_unreachable();
+}
src/analyze.hpp
@@ -215,6 +215,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk);
 X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty);
 bool type_is_c_abi_int(CodeGen *g, ZigType *ty);
 bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id);
+const char *container_string(ContainerKind kind);
 
 uint32_t get_host_int_bytes(CodeGen *g, ZigType *struct_type, TypeStructField *field);
 
src/ast_render.cpp
@@ -136,13 +136,19 @@ static const char *thread_local_string(Token *tok) {
     return (tok == nullptr) ? "" : "threadlocal ";
 }
 
-const char *container_string(ContainerKind kind) {
-    switch (kind) {
-        case ContainerKindEnum: return "enum";
-        case ContainerKindStruct: return "struct";
-        case ContainerKindUnion: return "union";
+static const char *token_to_ptr_len_str(Token *tok) {
+    assert(tok != nullptr);
+    switch (tok->id) {
+        case TokenIdStar:
+        case TokenIdStarStar:
+            return "*";
+        case TokenIdBracketStarBracket:
+            return "[*]";
+        case TokenIdBracketStarCBracket:
+            return "[*c]";
+        default:
+            zig_unreachable();
     }
-    zig_unreachable();
 }
 
 static const char *node_type_str(NodeType node_type) {
@@ -644,13 +650,8 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
         case NodeTypePointerType:
             {
                 if (!grouped) fprintf(ar->f, "(");
-                const char *star = "[*]";
-                if (node->data.pointer_type.star_token != nullptr &&
-                    (node->data.pointer_type.star_token->id == TokenIdStar || node->data.pointer_type.star_token->id == TokenIdStarStar))
-                {
-                    star = "*";
-                }
-                fprintf(ar->f, "%s", star);
+                const char *ptr_len_str = token_to_ptr_len_str(node->data.pointer_type.star_token);
+                fprintf(ar->f, "%s", ptr_len_str);
                 if (node->data.pointer_type.align_expr != nullptr) {
                     fprintf(ar->f, "align(");
                     render_node_grouped(ar, node->data.pointer_type.align_expr);
src/ast_render.hpp
@@ -17,7 +17,4 @@ void ast_print(FILE *f, AstNode *node, int indent);
 
 void ast_render(CodeGen *codegen, FILE *f, AstNode *node, int indent_size);
 
-const char *container_string(ContainerKind kind);
-
 #endif
-
src/translate_c.cpp
@@ -291,11 +291,22 @@ static AstNode *maybe_suppress_result(Context *c, ResultUsed result_used, AstNod
         node);
 }
 
+static TokenId ptr_len_to_token_id(PtrLen ptr_len) {
+    switch (ptr_len) {
+        case PtrLenSingle:
+            return TokenIdStar;
+        case PtrLenUnknown:
+            return TokenIdBracketStarBracket;
+        case PtrLenC:
+            return TokenIdBracketStarCBracket;
+    }
+    zig_unreachable();
+}
+
 static AstNode *trans_create_node_ptr_type(Context *c, bool is_const, bool is_volatile, AstNode *child_node, PtrLen ptr_len) {
     AstNode *node = trans_create_node(c, NodeTypePointerType);
     node->data.pointer_type.star_token = allocate<ZigToken>(1);
-    node->data.pointer_type.star_token->id = (ptr_len == PtrLenSingle) ? TokenIdStar: TokenIdBracketStarBracket;
-    node->data.pointer_type.is_const = is_const;
+    node->data.pointer_type.star_token->id = ptr_len_to_token_id(ptr_len);
     node->data.pointer_type.is_const = is_const;
     node->data.pointer_type.is_volatile = is_volatile;
     node->data.pointer_type.op_expr = child_node;
@@ -752,30 +763,6 @@ 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<const BuiltinType*>(ty);
-            return builtin_ty->getKind() == BuiltinType::Void;
-        }
-        case Type::Record: {
-            const RecordType *record_ty = static_cast<const RecordType*>(ty);
-            return record_ty->getDecl()->getDefinition() == nullptr;
-        }
-        case Type::Elaborated: {
-            const ElaboratedType *elaborated_ty = static_cast<const ElaboratedType*>(ty);
-            return type_is_opaque(c, elaborated_ty->getNamedType().getTypePtr(), source_loc);
-        }
-        case Type::Typedef: {
-            const TypedefType *typedef_ty = static_cast<const TypedefType*>(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:
@@ -925,11 +912,8 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou
                     return trans_create_node_prefix_op(c, PrefixOpOptional, child_node);
                 }
 
-                PtrLen ptr_len = type_is_opaque(c, child_qt.getTypePtr(), source_loc) ? PtrLenSingle : PtrLenUnknown;
-
-                AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(),
-                        child_qt.isVolatileQualified(), child_node, ptr_len);
-                return trans_create_node_prefix_op(c, PrefixOpOptional, pointer_node);
+                return trans_create_node_ptr_type(c, child_qt.isConstQualified(),
+                        child_qt.isVolatileQualified(), child_node, PtrLenC);
             }
         case Type::Typedef:
             {
@@ -1113,7 +1097,7 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou
                     return nullptr;
                 }
                 AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(),
-                        child_qt.isVolatileQualified(), child_type_node, PtrLenUnknown);
+                        child_qt.isVolatileQualified(), child_type_node, PtrLenC);
                 return pointer_node;
             }
         case Type::BlockPointer:
@@ -4568,7 +4552,7 @@ static AstNode *parse_ctok_suffix_op_expr(Context *c, CTokenize *ctok, size_t *t
         } else if (first_tok->id == CTokIdAsterisk) {
             *tok_i += 1;
 
-            node = trans_create_node_ptr_type(c, false, false, node, PtrLenUnknown);
+            node = trans_create_node_ptr_type(c, false, false, node, PtrLenC);
         } else {
             return node;
         }
test/translate_c.zig
@@ -117,11 +117,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\};
     ,
         \\pub const struct_Foo = extern struct {
-        \\    a: ?[*]Foo,
+        \\    a: [*c]Foo,
         \\};
         \\pub const Foo = struct_Foo;
         \\pub const struct_Bar = extern struct {
-        \\    a: ?[*]Foo,
+        \\    a: [*c]Foo,
         \\};
     );
 
@@ -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_void, noalias arg1: ?*c_void) void;
+        \\pub extern fn foo(noalias bar: [*c]c_void, noalias arg1: [*c]c_void) void;
     );
 
     cases.add("simple struct",
@@ -213,7 +213,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
     ,
         \\const struct_Foo = extern struct {
         \\    x: c_int,
-        \\    y: ?[*]u8,
+        \\    y: [*c]u8,
         \\};
     ,
         \\pub const Foo = struct_Foo;
@@ -244,7 +244,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
     ,
         \\pub const BarB = enum_Bar.B;
     ,
-        \\pub extern fn func(a: ?[*]struct_Foo, b: ?[*](?[*]enum_Bar)) void;
+        \\pub extern fn func(a: [*c]struct_Foo, b: [*c]([*c]enum_Bar)) void;
     ,
         \\pub const Foo = struct_Foo;
     ,
@@ -254,7 +254,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
     cases.add("constant size array",
         \\void func(int array[20]);
     ,
-        \\pub extern fn func(array: ?[*]c_int) void;
+        \\pub extern fn func(array: [*c]c_int) void;
     );
 
     cases.add("self referential struct with function pointer",
@@ -263,7 +263,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\};
     ,
         \\pub const struct_Foo = extern struct {
-        \\    derp: ?extern fn(?[*]struct_Foo) void,
+        \\    derp: ?extern fn([*c]struct_Foo) void,
         \\};
     ,
         \\pub const Foo = struct_Foo;
@@ -275,7 +275,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
     ,
         \\pub const struct_Foo = @OpaqueType();
     ,
-        \\pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo;
+        \\pub extern fn some_func(foo: [*c]struct_Foo, x: c_int) [*c]struct_Foo;
     ,
         \\pub const Foo = struct_Foo;
     );
@@ -322,11 +322,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\};
     ,
         \\pub const struct_Bar = extern struct {
-        \\    next: ?[*]struct_Foo,
+        \\    next: [*c]struct_Foo,
         \\};
     ,
         \\pub const struct_Foo = extern struct {
-        \\    next: ?[*]struct_Bar,
+        \\    next: [*c]struct_Bar,
         \\};
     );
 
@@ -336,7 +336,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
     ,
         \\pub const Foo = c_void;
     ,
-        \\pub extern fn fun(a: ?*Foo) Foo;
+        \\pub extern fn fun(a: [*c]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_void) c_int {
+        \\pub export fn and_or_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int {
         \\    if ((a != 0) and (b != 0)) return 0;
         \\    if ((b != 0) and (c != null)) return 1;
         \\    if ((a != 0) and (c != null)) return 2;
@@ -710,7 +710,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub const struct_Foo = extern struct {
         \\    field: c_int,
         \\};
-        \\pub export fn read_field(foo: ?[*]struct_Foo) c_int {
+        \\pub export fn read_field(foo: [*c]struct_Foo) c_int {
         \\    return foo.?.field;
         \\}
     );
@@ -756,8 +756,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    return x;
         \\}
     ,
-        \\pub export fn foo(x: ?[*]c_ushort) ?*c_void {
-        \\    return @ptrCast(?*c_void, x);
+        \\pub export fn foo(x: [*c]c_ushort) [*c]c_void {
+        \\    return @ptrCast([*c]c_void, x);
         \\}
     );
 
@@ -777,7 +777,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    return 0;
         \\}
     ,
-        \\pub export fn foo() ?[*]c_int {
+        \\pub export fn foo() [*c]c_int {
         \\    return null;
         \\}
     );
@@ -1086,7 +1086,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    *x = 1;
         \\}
     ,
-        \\pub export fn foo(x: ?[*]c_int) void {
+        \\pub export fn foo(x: [*c]c_int) void {
         \\    x.?.* = 1;
         \\}
     );
@@ -1114,7 +1114,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
     ,
         \\pub fn foo() c_int {
         \\    var x: c_int = 1234;
-        \\    var ptr: ?[*]c_int = &x;
+        \\    var ptr: [*c]c_int = &x;
         \\    return ptr.?.*;
         \\}
     );
@@ -1124,7 +1124,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    return "bar";
         \\}
     ,
-        \\pub fn foo() ?[*]const u8 {
+        \\pub fn foo() [*c]const u8 {
         \\    return c"bar";
         \\}
     );
@@ -1253,8 +1253,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    return (float *)a;
         \\}
     ,
-        \\fn ptrcast(a: ?[*]c_int) ?[*]f32 {
-        \\    return @ptrCast(?[*]f32, a);
+        \\fn ptrcast(a: [*c]c_int) [*c]f32 {
+        \\    return @ptrCast([*c]f32, a);
         \\}
     );
 
@@ -1276,7 +1276,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    return !c;
         \\}
     ,
-        \\pub fn foo(a: c_int, b: f32, c: ?*c_void) c_int {
+        \\pub fn foo(a: c_int, b: f32, c: [*c]c_void) c_int {
         \\    return !(a == 0);
         \\    return !(a != 0);
         \\    return !(b != 0);
@@ -1297,7 +1297,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
     cases.add("const ptr initializer",
         \\static const char *v0 = "0.0.0";
     ,
-        \\pub var v0: ?[*]const u8 = c"0.0.0";
+        \\pub var v0: [*c]const u8 = c"0.0.0";
     );
 
     cases.add("static incomplete array inside function",
@@ -1306,17 +1306,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     ,
         \\pub fn foo() void {
-        \\    const v2: [*]const u8 = c"2.2.2";
+        \\    const v2: [*c]const u8 = c"2.2.2";
         \\}
     );
 
     cases.add("macro pointer cast",
         \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
     ,
-        \\pub const NRF_GPIO = if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast([*]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr([*]NRF_GPIO_Type, NRF_GPIO_BASE) else ([*]NRF_GPIO_Type)(NRF_GPIO_BASE);
+        \\pub const NRF_GPIO = if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else ([*c]NRF_GPIO_Type)(NRF_GPIO_BASE);
     );
 
-    cases.add("if on none bool",
+    cases.add("if on non-bool",
         \\enum SomeEnum { A, B, C };
         \\int if_none_bool(int a, float b, void *c, enum SomeEnum d) {
         \\    if (a) return 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_void, d: enum_SomeEnum) c_int {
+        \\pub fn if_none_bool(a: c_int, b: f32, c: [*c]c_void, d: enum_SomeEnum) c_int {
         \\    if (a != 0) return 0;
         \\    if (b != 0) return 1;
         \\    if (c != null) return 2;
@@ -1343,7 +1343,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     );
 
-    cases.add("while on none bool",
+    cases.add("while on non-bool",
         \\int while_none_bool(int a, float b, void *c) {
         \\    while (a) return 0;
         \\    while (b) return 1;
@@ -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_void) c_int {
+        \\pub fn while_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int {
         \\    while (a != 0) return 0;
         \\    while (b != 0) return 1;
         \\    while (c != null) return 2;
@@ -1359,7 +1359,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     );
 
-    cases.add("for on none bool",
+    cases.add("for on non-bool",
         \\int for_none_bool(int a, float b, void *c) {
         \\    for (;a;) return 0;
         \\    for (;b;) return 1;
@@ -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_void) c_int {
+        \\pub fn for_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int {
         \\    while (a != 0) return 0;
         \\    while (b != 0) return 1;
         \\    while (c != null) return 2;