Skip to content

Commit

Permalink
Merge pull request #1134 from ziglang/no-explicit-casting
Browse files Browse the repository at this point in the history
remove "cast harder" casting syntax; add new casting builtins
  • Loading branch information
andrewrk committed Jun 19, 2018
2 parents 1ca90b5 + a3ddd08 commit 9f23243
Show file tree
Hide file tree
Showing 24 changed files with 697 additions and 222 deletions.
150 changes: 122 additions & 28 deletions doc/langref.html.in
Expand Up @@ -1456,8 +1456,7 @@ test "pointer array access" {
// Taking an address of an individual element gives a
// pointer to a single item. This kind of pointer
// does not support pointer arithmetic.

var array = []u8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
var array = []u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const ptr = &array[2];
assert(@typeOf(ptr) == *u8);

Expand All @@ -1469,7 +1468,7 @@ test "pointer array access" {
test "pointer slicing" {
// In Zig, we prefer using slices over null-terminated pointers.
// You can turn an array into a slice using slice syntax:
var array = []u8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
var array = []u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const slice = array[2..4];
assert(slice.len == 2);

Expand Down Expand Up @@ -1541,13 +1540,13 @@ test "pointer casting" {
// To convert one pointer type to another, use @ptrCast. This is an unsafe
// operation that Zig cannot protect you against. Use @ptrCast only when other
// conversions are not possible.
const bytes align(@alignOf(u32)) = []u8{0x12, 0x12, 0x12, 0x12};
const bytes align(@alignOf(u32)) = []u8{ 0x12, 0x12, 0x12, 0x12 };
const u32_ptr = @ptrCast(*const u32, &bytes[0]);
assert(u32_ptr.* == 0x12121212);

// Even this example is contrived - there are better ways to do the above than
// pointer casting. For example, using a slice narrowing cast:
const u32_value = ([]const u32)(bytes[0..])[0];
const u32_value = @bytesToSlice(u32, bytes[0..])[0];
assert(u32_value == 0x12121212);

// And even another way, the most straightforward way to do it:
Expand Down Expand Up @@ -1630,13 +1629,13 @@ test "function alignment" {
const assert = @import("std").debug.assert;

test "pointer alignment safety" {
var array align(4) = []u32{0x11111111, 0x11111111};
const bytes = ([]u8)(array[0..]);
var array align(4) = []u32{ 0x11111111, 0x11111111 };
const bytes = @sliceToBytes(array[0..]);
assert(foo(bytes) == 0x11111111);
}
fn foo(bytes: []u8) u32 {
const slice4 = bytes[1..5];
const int_slice = ([]u32)(@alignCast(4, slice4));
const int_slice = @bytesToSlice(u32, @alignCast(4, slice4));
return int_slice[0];
}
{#code_end#}
Expand Down Expand Up @@ -1728,8 +1727,8 @@ test "slice pointer" {
test "slice widening" {
// Zig supports slice widening and slice narrowing. Cast a slice of u8
// to a slice of anything else, and Zig will perform the length conversion.
const array align(@alignOf(u32)) = []u8{0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13};
const slice = ([]const u32)(array[0..]);
const array align(@alignOf(u32)) = []u8{ 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13 };
const slice = @bytesToSlice(u32, array[0..]);
assert(slice.len == 2);
assert(slice[0] == 0x12121212);
assert(slice[1] == 0x13131313);
Expand Down Expand Up @@ -1901,9 +1900,9 @@ const Value = enum(u2) {
// Now you can cast between u2 and Value.
// The ordinal value starts from 0, counting up for each member.
test "enum ordinal value" {
assert(u2(Value.Zero) == 0);
assert(u2(Value.One) == 1);
assert(u2(Value.Two) == 2);
assert(@enumToInt(Value.Zero) == 0);
assert(@enumToInt(Value.One) == 1);
assert(@enumToInt(Value.Two) == 2);
}

// You can override the ordinal value for an enum.
Expand All @@ -1913,9 +1912,9 @@ const Value2 = enum(u32) {
Million = 1000000,
};
test "set enum ordinal value" {
assert(u32(Value2.Hundred) == 100);
assert(u32(Value2.Thousand) == 1000);
assert(u32(Value2.Million) == 1000000);
assert(@enumToInt(Value2.Hundred) == 100);
assert(@enumToInt(Value2.Thousand) == 1000);
assert(@enumToInt(Value2.Million) == 1000000);
}

// Enums can have methods, the same as structs and unions.
Expand Down Expand Up @@ -4651,6 +4650,18 @@ comptime {
</p>
{#header_close#}

{#header_open|@bytesToSlice#}
<pre><code class="zig">@bytesToSlice(comptime Element: type, bytes: []u8) []Element</code></pre>
<p>
Converts a slice of bytes or array of bytes into a slice of <code>Element</code>.
The resulting slice has the same {#link|pointer|Pointers#} properties as the parameter.
</p>
<p>
Attempting to convert a number of bytes with a length that does not evenly divide into a slice of
elements results in safety-protected {#link|Undefined Behavior#}.
</p>
{#header_close#}

{#header_open|@cDefine#}
<pre><code class="zig">@cDefine(comptime name: []u8, value)</code></pre>
<p>
Expand Down Expand Up @@ -4919,12 +4930,23 @@ test "main" {
</p>
{#see_also|@import#}
{#header_close#}
{#header_open|@export#}
<pre><code class="zig">@export(comptime name: []const u8, target: var, linkage: builtin.GlobalLinkage) []const u8</code></pre>

{#header_open|@enumToInt#}
<pre><code class="zig">@enumToInt(enum_value: var) var</code></pre>
<p>
Creates a symbol in the output object file.
Converts an enumeration value into its integer tag type.
</p>
{#see_also|@intToEnum#}
{#header_close#}

{#header_open|@errSetCast#}
<pre><code class="zig">@errSetCast(comptime T: DestType, value: var) DestType</code></pre>
<p>
Converts an error value from one error set to another error set. Attempting to convert an error
which is not in the destination error set results in safety-protected {#link|Undefined Behavior#}.
</p>
{#header_close#}

{#header_open|@errorName#}
<pre><code class="zig">@errorName(err: error) []u8</code></pre>
<p>
Expand All @@ -4941,6 +4963,7 @@ test "main" {
error name table will be generated.
</p>
{#header_close#}

{#header_open|@errorReturnTrace#}
<pre><code class="zig">@errorReturnTrace() ?*builtin.StackTrace</code></pre>
<p>
Expand All @@ -4949,6 +4972,33 @@ test "main" {
stack trace object. Otherwise returns `null`.
</p>
{#header_close#}

{#header_open|@errorToInt#}
<pre><code class="zig">@errorToInt(err: var) @IntType(false, @sizeOf(error) * 8)</code></pre>
<p>
Supports the following types:
</p>
<ul>
<li>error unions</li>
<li><code>E!void</code></li>
</ul>
<p>
Converts an error to the integer representation of an error.
</p>
<p>
It is generally recommended to avoid this
cast, as the integer representation of an error is not stable across source code changes.
</p>
{#see_also|@intToError#}
{#header_close#}

{#header_open|@export#}
<pre><code class="zig">@export(comptime name: []const u8, target: var, linkage: builtin.GlobalLinkage) []const u8</code></pre>
<p>
Creates a symbol in the output object file.
</p>
{#header_close#}

{#header_open|@fence#}
<pre><code class="zig">@fence(order: AtomicOrder)</code></pre>
<p>
Expand Down Expand Up @@ -5049,8 +5099,36 @@ fn add(a: i32, b: i32) i32 { return a + b; }
<p>
Converts an integer to another integer while keeping the same numerical value.
Attempting to convert a number which is out of range of the destination type results in
{#link|Undefined Behavior#}.
safety-protected {#link|Undefined Behavior#}.
</p>
{#header_close#}

{#header_open|@intToEnum#}
<pre><code class="zig">@intToEnum(comptime DestType: type, int_value: @TagType(DestType)) DestType</code></pre>
<p>
Converts an integer into an {#link|enum#} value.
</p>
<p>
Attempting to convert an integer which represents no value in the chosen enum type invokes
safety-checked {#link|Undefined Behavior#}.
</p>
{#see_also|@enumToInt#}
{#header_close#}

{#header_open|@intToError#}
<pre><code class="zig">@intToError(value: @IntType(false, @sizeOf(error) * 8)) error</code></pre>
<p>
Converts from the integer representation of an error into the global error set type.
</p>
<p>
It is generally recommended to avoid this
cast, as the integer representation of an error is not stable across source code changes.
</p>
<p>
Attempting to convert an integer that does not correspond to any error results in
safety-protected {#link|Undefined Behavior#}.
</p>
{#see_also|@errorToInt#}
{#header_close#}

{#header_open|@intToFloat#}
Expand Down Expand Up @@ -5456,15 +5534,25 @@ pub const FloatMode = enum {
</p>
{#see_also|@shlExact|@shlWithOverflow#}
{#header_close#}

{#header_open|@sizeOf#}
<pre><code class="zig">@sizeOf(comptime T: type) (number literal)</code></pre>
<pre><code class="zig">@sizeOf(comptime T: type) comptime_int</code></pre>
<p>
This function returns the number of bytes it takes to store <code>T</code> in memory.
</p>
<p>
The result is a target-specific compile time constant.
</p>
{#header_close#}

{#header_open|@sliceToBytes#}
<pre><code class="zig">@sliceToBytes(value: var) []u8</code></pre>
<p>
Converts a slice or array to a slice of <code>u8</code>. The resulting slice has the same
{#link|pointer|Pointers#} properties as the parameter.
</p>
{#header_close#}

{#header_open|@sqrt#}
<pre><code class="zig">@sqrt(comptime T: type, value: T) T</code></pre>
<p>
Expand Down Expand Up @@ -5817,10 +5905,10 @@ pub fn build(b: &Builder) void {
{#header_open|Undefined Behavior#}
<p>
Zig has many instances of undefined behavior. If undefined behavior is
detected at compile-time, Zig emits an error. Most undefined behavior that
cannot be detected at compile-time can be detected at runtime. In these cases,
Zig has safety checks. Safety checks can be disabled on a per-block basis
with {#link|setRuntimeSafety#}. The {#link|ReleaseFast#}
detected at compile-time, Zig emits a compile error and refuses to continue.
Most undefined behavior that cannot be detected at compile-time can be detected
at runtime. In these cases, Zig has safety checks. Safety checks can be disabled
on a per-block basis with {#link|setRuntimeSafety#}. The {#link|ReleaseFast#}
build mode disables all safety checks in order to facilitate optimizations.
</p>
<p>
Expand Down Expand Up @@ -6091,8 +6179,8 @@ fn getNumberOrFail() !i32 {
{#code_begin|test_err|integer value 11 represents no error#}
comptime {
const err = error.AnError;
const number = u32(err) + 10;
const invalid_err = error(number);
const number = @errorToInt(err) + 10;
const invalid_err = @intToError(number);
}
{#code_end#}
<p>At runtime crashes with the message <code>invalid error code</code> and a stack trace.</p>
Expand All @@ -6101,6 +6189,11 @@ comptime {
<p>TODO</p>

{#header_close#}

{#header_open|Invalid Error Set Cast#}
<p>TODO</p>
{#header_close#}

{#header_open|Incorrect Pointer Alignment#}
<p>TODO</p>

Expand All @@ -6109,6 +6202,7 @@ comptime {
<p>TODO</p>

{#header_close#}

{#header_close#}
{#header_open|Memory#}
<p>TODO: explain no default allocator in zig</p>
Expand Down Expand Up @@ -6793,7 +6887,7 @@ hljs.registerLanguage("zig", function(t) {
a = t.IR + "\\s*\\(",
c = {
keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong resume cancel await async orelse",
built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic ptrCast intCast floatCast intToFloat floatToInt boolToInt bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo typeName newStackCall",
built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic ptrCast intCast floatCast intToFloat floatToInt boolToInt bytesToSlice sliceToBytes errSetCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo typeName newStackCall errorToInt intToError enumToInt intToEnum",
literal: "true false null undefined"
},
n = [e, t.CLCM, t.CBCM, s, r];
Expand Down
49 changes: 49 additions & 0 deletions src/all_types.hpp
Expand Up @@ -234,6 +234,16 @@ enum RuntimeHintPtr {
RuntimeHintPtrNonStack,
};

enum RuntimeHintSliceId {
RuntimeHintSliceIdUnknown,
RuntimeHintSliceIdLen,
};

struct RuntimeHintSlice {
enum RuntimeHintSliceId id;
uint64_t len;
};

struct ConstGlobalRefs {
LLVMValueRef llvm_value;
LLVMValueRef llvm_global;
Expand Down Expand Up @@ -270,6 +280,7 @@ struct ConstExprValue {
RuntimeHintErrorUnion rh_error_union;
RuntimeHintOptional rh_maybe;
RuntimeHintPtr rh_ptr;
RuntimeHintSlice rh_slice;
} data;
};

Expand Down Expand Up @@ -1359,9 +1370,16 @@ enum BuiltinFnId {
BuiltinFnIdTruncate,
BuiltinFnIdIntCast,
BuiltinFnIdFloatCast,
BuiltinFnIdErrSetCast,
BuiltinFnIdToBytes,
BuiltinFnIdFromBytes,
BuiltinFnIdIntToFloat,
BuiltinFnIdFloatToInt,
BuiltinFnIdBoolToInt,
BuiltinFnIdErrToInt,
BuiltinFnIdIntToErr,
BuiltinFnIdEnumToInt,
BuiltinFnIdIntToEnum,
BuiltinFnIdIntType,
BuiltinFnIdSetCold,
BuiltinFnIdSetRuntimeSafety,
Expand Down Expand Up @@ -2076,6 +2094,7 @@ enum IrInstructionId {
IrInstructionIdIntToPtr,
IrInstructionIdPtrToInt,
IrInstructionIdIntToEnum,
IrInstructionIdEnumToInt,
IrInstructionIdIntToErr,
IrInstructionIdErrToInt,
IrInstructionIdCheckSwitchProngs,
Expand Down Expand Up @@ -2121,6 +2140,9 @@ enum IrInstructionId {
IrInstructionIdMergeErrRetTraces,
IrInstructionIdMarkErrRetTracePtr,
IrInstructionIdSqrt,
IrInstructionIdErrSetCast,
IrInstructionIdToBytes,
IrInstructionIdFromBytes,
};

struct IrInstruction {
Expand Down Expand Up @@ -2656,6 +2678,26 @@ struct IrInstructionFloatCast {
IrInstruction *target;
};

struct IrInstructionErrSetCast {
IrInstruction base;

IrInstruction *dest_type;
IrInstruction *target;
};

struct IrInstructionToBytes {
IrInstruction base;

IrInstruction *target;
};

struct IrInstructionFromBytes {
IrInstruction base;

IrInstruction *dest_child_type;
IrInstruction *target;
};

struct IrInstructionIntToFloat {
IrInstruction base;

Expand Down Expand Up @@ -2866,6 +2908,13 @@ struct IrInstructionIntToPtr {
struct IrInstructionIntToEnum {
IrInstruction base;

IrInstruction *dest_type;
IrInstruction *target;
};

struct IrInstructionEnumToInt {
IrInstruction base;

IrInstruction *target;
};

Expand Down

0 comments on commit 9f23243

Please sign in to comment.