authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-08-27 18:31:41-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-08-27 18:31:41-04:00
logb92fac329e73280ea5d49af675fea84e777b7f0a
tree647c64025db7bd7c5948f8d5493befdf566c0071
parentecc54640243ba84ffa3656b73aa7dd6b53474462
parent45d9d9f953df2167b35878ea02551d9c86ad8a0f
signaturelock-open Commit is signed but in an unrecognized format.

Merge branch 'raulgrell-CastToCVoid'


3 files changed, 103 insertions(+), 13 deletions(-)

doc/langref.html.in+55
...@@ -7057,6 +7057,61 @@ const c = @cImport({...@@ -7057,6 +7057,61 @@ const c = @cImport({
7057});7057});
7058 {#code_end#}7058 {#code_end#}
7059 {#see_also|@cImport|@cInclude|@cDefine|@cUndef|@import#}7059 {#see_also|@cImport|@cInclude|@cDefine|@cUndef|@import#}
7060 {#header_close#}
7061 {#header_open|Exporting a C Library#}
7062 <p>
7063 One of the primary use cases for Zig is exporting a library with the C ABI for other programming languages
7064 to call into. The <code>export</code> keyword in front of functions, variables, and types causes them to
7065 be part of the library API:
7066 </p>
7067 <p class="file">mathtest.zig</p>
7068 {#code_begin|syntax#}
7069export fn add(a: i32, b: i32) i32 {
7070 return a + b;
7071}
7072 {#code_end#}
7073 <p>To make a shared library:</p>
7074 <pre><code class="shell">$ zig build-lib mathtest.zig
7075</code></pre>
7076 <p>To make a static library:</p>
7077 <pre><code class="shell">$ zig build-lib mathtest.zig --static
7078</code></pre>
7079 <p>Here is an example with the {#link|Zig Build System#}:</p>
7080 <p class="file">test.c</p>
7081 <pre><code class="cpp">// This header is generated by zig from mathtest.zig
7082#include "mathtest.h"
7083#include &lt;assert.h&gt;
7084
7085int main(int argc, char **argv) {
7086 assert(add(42, 1337) == 1379);
7087 return 0;
7088}</code></pre>
7089 <p class="file">build.zig</p>
7090 {#code_begin|syntax#}
7091const Builder = @import("std").build.Builder;
7092
7093pub fn build(b: *Builder) void {
7094 const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));
7095
7096 const exe = b.addCExecutable("test");
7097 exe.addCompileFlags([][]const u8{"-std=c99"});
7098 exe.addSourceFile("test.c");
7099 exe.linkLibrary(lib);
7100
7101 b.default_step.dependOn(&exe.step);
7102
7103 const run_cmd = b.addCommand(".", b.env_map, [][]const u8{exe.getOutputPath()});
7104 run_cmd.step.dependOn(&exe.step);
7105
7106 const test_step = b.step("test", "Test the program");
7107 test_step.dependOn(&run_cmd.step);
7108}
7109 {#code_end#}
7110 <p class="file">terminal</p>
7111 <pre><code class="shell">$ zig build
7112$ ./test
7113$ echo $?
71140</code></pre>
7060 {#header_close#}7115 {#header_close#}
7061 {#header_open|Mixing Object Files#}7116 {#header_open|Mixing Object Files#}
7062 <p>7117 <p>
src/ir.cpp+16-4
...@@ -60,7 +60,7 @@ enum ConstCastResultId {...@@ -60,7 +60,7 @@ enum ConstCastResultId {
60 ConstCastResultIdType,60 ConstCastResultIdType,
61 ConstCastResultIdUnresolvedInferredErrSet,61 ConstCastResultIdUnresolvedInferredErrSet,
62 ConstCastResultIdAsyncAllocatorType,62 ConstCastResultIdAsyncAllocatorType,
63 ConstCastResultIdNullWrapPtr,63 ConstCastResultIdNullWrapPtr
64};64};
6565
66struct ConstCastOnly;66struct ConstCastOnly;
...@@ -8471,9 +8471,9 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry...@@ -8471,9 +8471,9 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
8471 if (wanted_type == actual_type)8471 if (wanted_type == actual_type)
8472 return result;8472 return result;
84738473
8474 // * and [*] can do a const-cast-only to ?* and ?[*], respectively8474 // *T and [*]T may const-cast-only to ?*U and ?[*]U, respectively
8475 // but not if there is a mutable parent pointer8475 // but not if we want a mutable pointer
8476 // and not if the pointer is zero bits8476 // and not if the actual pointer has zero bits
8477 if (!wanted_is_mutable && wanted_type->id == TypeTableEntryIdOptional &&8477 if (!wanted_is_mutable && wanted_type->id == TypeTableEntryIdOptional &&
8478 wanted_type->data.maybe.child_type->id == TypeTableEntryIdPointer &&8478 wanted_type->data.maybe.child_type->id == TypeTableEntryIdPointer &&
8479 actual_type->id == TypeTableEntryIdPointer && type_has_bits(actual_type))8479 actual_type->id == TypeTableEntryIdPointer && type_has_bits(actual_type))
...@@ -8488,6 +8488,18 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry...@@ -8488,6 +8488,18 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
8488 return result;8488 return result;
8489 }8489 }
84908490
8491 // *T and [*]T can always cast to *c_void
8492 if (wanted_type->id == TypeTableEntryIdPointer &&
8493 wanted_type->data.pointer.ptr_len == PtrLenSingle &&
8494 wanted_type->data.pointer.child_type == g->builtin_types.entry_c_void &&
8495 actual_type->id == TypeTableEntryIdPointer &&
8496 (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) &&
8497 (!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile))
8498 {
8499 assert(actual_type->data.pointer.alignment >= wanted_type->data.pointer.alignment);
8500 return result;
8501 }
8502
8491 // pointer const8503 // pointer const
8492 if (wanted_type->id == TypeTableEntryIdPointer && actual_type->id == TypeTableEntryIdPointer) {8504 if (wanted_type->id == TypeTableEntryIdPointer && actual_type->id == TypeTableEntryIdPointer) {
8493 ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,8505 ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
test/cases/cast.zig+32-9
...@@ -487,12 +487,35 @@ fn MakeType(comptime T: type) type {...@@ -487,12 +487,35 @@ fn MakeType(comptime T: type) type {
487}487}
488488
489test "implicit cast from *[N]T to ?[*]T" {489test "implicit cast from *[N]T to ?[*]T" {
490 var x: ?[*]u16 = null;
491 var y: [4]u16 = [4]u16 {0, 1, 2, 3};
492
493 x = &y;
494 assert(std.mem.eql(u16, x.?[0..4], y[0..4]));
495 x.?[0] = 8;
496 y[3] = 6;
497 assert(std.mem.eql(u16, x.?[0..4], y[0..4]));
498}
\ No newline at end of file
490 var x: ?[*]u16 = null;
491 var y: [4]u16 = [4]u16{ 0, 1, 2, 3 };
492
493 x = &y;
494 assert(std.mem.eql(u16, x.?[0..4], y[0..4]));
495 x.?[0] = 8;
496 y[3] = 6;
497 assert(std.mem.eql(u16, x.?[0..4], y[0..4]));
498}
499
500test "implicit cast from *T to ?*c_void" {
501 var a: u8 = 1;
502 incrementVoidPtrValue(&a);
503 std.debug.assert(a == 2);
504}
505
506fn incrementVoidPtrValue(value: ?*c_void) void {
507 @ptrCast(*u8, value.?).* += 1;
508}
509
510test "implicit cast from [*]T to ?*c_void" {
511 var a = []u8{ 3, 2, 1 };
512 incrementVoidPtrArray(a[0..].ptr, 3);
513 assert(std.mem.eql(u8, a, []u8{ 4, 3, 2 }));
514}
515
516fn incrementVoidPtrArray(array: ?*c_void, len: usize) void {
517 var n: usize = 0;
518 while (n < len) : (n += 1) {
519 @ptrCast([*]u8, array.?)[n] += 1;
520 }
521}