zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit b92fac329e73280ea5d49af675fea84e777b7f0a (tree)
parent ecc54640243ba84ffa3656b73aa7dd6b53474462
Author: Andrew Kelley <superjoe30@gmail.com>
Date:   Mon, 27 Aug 2018 18:31:41 -0400

Merge branch 'raulgrell-CastToCVoid'

Diffstat:
Mdoc/langref.html.in | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/ir.cpp | 20++++++++++++++++----
Mtest/cases/cast.zig | 42++++++++++++++++++++++++++++++++----------
3 files changed, 103 insertions(+), 14 deletions(-)

diff --git a/doc/langref.html.in b/doc/langref.html.in @@ -7058,6 +7058,61 @@ const c = @cImport({ {#code_end#} {#see_also|@cImport|@cInclude|@cDefine|@cUndef|@import#} {#header_close#} + {#header_open|Exporting a C Library#} + <p> + One of the primary use cases for Zig is exporting a library with the C ABI for other programming languages + to call into. The <code>export</code> keyword in front of functions, variables, and types causes them to + be part of the library API: + </p> + <p class="file">mathtest.zig</p> + {#code_begin|syntax#} +export fn add(a: i32, b: i32) i32 { + return a + b; +} + {#code_end#} + <p>To make a shared library:</p> + <pre><code class="shell">$ zig build-lib mathtest.zig +</code></pre> + <p>To make a static library:</p> + <pre><code class="shell">$ zig build-lib mathtest.zig --static +</code></pre> + <p>Here is an example with the {#link|Zig Build System#}:</p> + <p class="file">test.c</p> + <pre><code class="cpp">// This header is generated by zig from mathtest.zig +#include "mathtest.h" +#include &lt;assert.h&gt; + +int main(int argc, char **argv) { + assert(add(42, 1337) == 1379); + return 0; +}</code></pre> + <p class="file">build.zig</p> + {#code_begin|syntax#} +const Builder = @import("std").build.Builder; + +pub fn build(b: *Builder) void { + const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0)); + + const exe = b.addCExecutable("test"); + exe.addCompileFlags([][]const u8{"-std=c99"}); + exe.addSourceFile("test.c"); + exe.linkLibrary(lib); + + b.default_step.dependOn(&exe.step); + + const run_cmd = b.addCommand(".", b.env_map, [][]const u8{exe.getOutputPath()}); + run_cmd.step.dependOn(&exe.step); + + const test_step = b.step("test", "Test the program"); + test_step.dependOn(&run_cmd.step); +} + {#code_end#} + <p class="file">terminal</p> + <pre><code class="shell">$ zig build +$ ./test +$ echo $? +0</code></pre> + {#header_close#} {#header_open|Mixing Object Files#} <p> You can mix Zig object files with any other object files that respect the C ABI. Example: diff --git a/src/ir.cpp b/src/ir.cpp @@ -60,7 +60,7 @@ enum ConstCastResultId { ConstCastResultIdType, ConstCastResultIdUnresolvedInferredErrSet, ConstCastResultIdAsyncAllocatorType, - ConstCastResultIdNullWrapPtr, + ConstCastResultIdNullWrapPtr }; struct ConstCastOnly; @@ -8471,9 +8471,9 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry if (wanted_type == actual_type) return result; - // * and [*] can do a const-cast-only to ?* and ?[*], respectively - // but not if there is a mutable parent pointer - // and not if the pointer is zero bits + // *T and [*]T may const-cast-only to ?*U and ?[*]U, respectively + // but not if we want a mutable pointer + // and not if the actual pointer has zero bits if (!wanted_is_mutable && wanted_type->id == TypeTableEntryIdOptional && wanted_type->data.maybe.child_type->id == TypeTableEntryIdPointer && actual_type->id == TypeTableEntryIdPointer && type_has_bits(actual_type)) @@ -8488,6 +8488,18 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry return result; } + // *T and [*]T can always cast to *c_void + if (wanted_type->id == TypeTableEntryIdPointer && + wanted_type->data.pointer.ptr_len == PtrLenSingle && + wanted_type->data.pointer.child_type == g->builtin_types.entry_c_void && + actual_type->id == TypeTableEntryIdPointer && + (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) && + (!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile)) + { + assert(actual_type->data.pointer.alignment >= wanted_type->data.pointer.alignment); + return result; + } + // pointer const if (wanted_type->id == TypeTableEntryIdPointer && actual_type->id == TypeTableEntryIdPointer) { ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, diff --git a/test/cases/cast.zig b/test/cases/cast.zig @@ -487,12 +487,35 @@ fn MakeType(comptime T: type) type { } test "implicit cast from *[N]T to ?[*]T" { - var x: ?[*]u16 = null; - var y: [4]u16 = [4]u16 {0, 1, 2, 3}; - - x = &y; - assert(std.mem.eql(u16, x.?[0..4], y[0..4])); - x.?[0] = 8; - y[3] = 6; - assert(std.mem.eql(u16, x.?[0..4], y[0..4])); -} -\ No newline at end of file + var x: ?[*]u16 = null; + var y: [4]u16 = [4]u16{ 0, 1, 2, 3 }; + + x = &y; + assert(std.mem.eql(u16, x.?[0..4], y[0..4])); + x.?[0] = 8; + y[3] = 6; + assert(std.mem.eql(u16, x.?[0..4], y[0..4])); +} + +test "implicit cast from *T to ?*c_void" { + var a: u8 = 1; + incrementVoidPtrValue(&a); + std.debug.assert(a == 2); +} + +fn incrementVoidPtrValue(value: ?*c_void) void { + @ptrCast(*u8, value.?).* += 1; +} + +test "implicit cast from [*]T to ?*c_void" { + var a = []u8{ 3, 2, 1 }; + incrementVoidPtrArray(a[0..].ptr, 3); + assert(std.mem.eql(u8, a, []u8{ 4, 3, 2 })); +} + +fn incrementVoidPtrArray(array: ?*c_void, len: usize) void { + var n: usize = 0; + while (n < len) : (n += 1) { + @ptrCast([*]u8, array.?)[n] += 1; + } +}