authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-04 18:23:11-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-04 18:23:11-07:00
logbccef441963434b452a623abbb9315fd92c1e255
tree4c0ea89b8fa895b3d34749ec089e45438d79466b
parent0c06a1885fad9a9bb85342632a0b7c8a3a0733e9
parent041212a41cfaf029dc3eb9740467b721c76f406c

Merge remote-tracking branch 'origin/master' into llvm12

Syncing with master branch because I want to re-run update_clang_options.zig in the llvm12 branch.

52 files changed, 2354 insertions(+), 379 deletions(-)

CMakeLists.txt+21-20
...@@ -801,31 +801,32 @@ endif()...@@ -801,31 +801,32 @@ endif()
801801
802install(TARGETS zig DESTINATION bin)802install(TARGETS zig DESTINATION bin)
803803
804set(ZIG_INSTALL_ARGS "build"804set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL
805 --override-lib-dir "${CMAKE_SOURCE_DIR}/lib"805 "Disable copying lib/ files to install prefix during the build phase")
806 "-Dlib-files-only"806
807 --prefix "${CMAKE_INSTALL_PREFIX}"807if(NOT ZIG_SKIP_INSTALL_LIB_FILES)
808 "-Dconfig_h=${ZIG_CONFIG_H_OUT}"808 set(ZIG_INSTALL_ARGS "build"
809 install809 --override-lib-dir "${CMAKE_SOURCE_DIR}/lib"
810)810 "-Dlib-files-only"
811 --prefix "${CMAKE_INSTALL_PREFIX}"
812 "-Dconfig_h=${ZIG_CONFIG_H_OUT}"
813 install
814 )
811815
812# CODE has no effect with Visual Studio build system generator, therefore816 # CODE has no effect with Visual Studio build system generator, therefore
813# when using Visual Studio build system generator we resort to running817 # when using Visual Studio build system generator we resort to running
814# `zig build install` during the build phase.818 # `zig build install` during the build phase.
815if(MSVC)819 if(MSVC)
816 set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL
817 "Windows-only: Disable copying lib/ files to install prefix during the build phase")
818 if(NOT ZIG_SKIP_INSTALL_LIB_FILES)
819 add_custom_target(zig_install_lib_files ALL820 add_custom_target(zig_install_lib_files ALL
820 COMMAND zig ${ZIG_INSTALL_ARGS}821 COMMAND zig ${ZIG_INSTALL_ARGS}
821 DEPENDS zig822 DEPENDS zig
822 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"823 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
823 )824 )
825 else()
826 get_target_property(zig_BINARY_DIR zig BINARY_DIR)
827 install(CODE "set(zig_EXE \"${ZIG_EXECUTABLE}\")")
828 install(CODE "set(ZIG_INSTALL_ARGS \"${ZIG_INSTALL_ARGS}\")")
829 install(CODE "set(CMAKE_SOURCE_DIR \"${CMAKE_SOURCE_DIR}\")")
830 install(SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/cmake/install.cmake)
824 endif()831 endif()
825else()
826 get_target_property(zig_BINARY_DIR zig BINARY_DIR)
827 install(CODE "set(zig_EXE \"${ZIG_EXECUTABLE}\")")
828 install(CODE "set(ZIG_INSTALL_ARGS \"${ZIG_INSTALL_ARGS}\")")
829 install(CODE "set(CMAKE_SOURCE_DIR \"${CMAKE_SOURCE_DIR}\")")
830 install(SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/cmake/install.cmake)
831endif()832endif()
doc/langref.html.in+51-23
...@@ -10447,13 +10447,40 @@ fn readU32Be() u32 {}...@@ -10447,13 +10447,40 @@ fn readU32Be() u32 {}
10447 {#header_close#}10447 {#header_close#}
10448 {#header_open|Source Encoding#}10448 {#header_open|Source Encoding#}
10449 <p>Zig source code is encoded in UTF-8. An invalid UTF-8 byte sequence results in a compile error.</p>10449 <p>Zig source code is encoded in UTF-8. An invalid UTF-8 byte sequence results in a compile error.</p>
10450 <p>Throughout all zig source code (including in comments), some codepoints are never allowed:</p>10450 <p>Throughout all zig source code (including in comments), some code points are never allowed:</p>
10451 <ul>10451 <ul>
10452 <li>Ascii control characters, except for U+000a (LF): U+0000 - U+0009, U+000b - U+0001f, U+007f. (Note that Windows line endings (CRLF) are not allowed, and hard tabs are not allowed.)</li>10452 <li>Ascii control characters, except for U+000a (LF), U+000d (CR), and U+0009 (HT): U+0000 - U+0008, U+000b - U+000c, U+000e - U+0001f, U+007f.</li>
10453 <li>Non-Ascii Unicode line endings: U+0085 (NEL), U+2028 (LS), U+2029 (PS).</li>10453 <li>Non-Ascii Unicode line endings: U+0085 (NEL), U+2028 (LS), U+2029 (PS).</li>
10454 </ul>10454 </ul>
10455 <p>The codepoint U+000a (LF) (which is encoded as the single-byte value 0x0a) is the line terminator character. This character always terminates a line of zig source code (except possibly the last line of the file).</p>10455 <p>
10456 <p>For some discussion on the rationale behind these design decisions, see <a href="https://github.com/ziglang/zig/issues/663">issue #663</a></p>10456 LF (byte value 0x0a, code point U+000a, {#syntax#}'\n'{#endsyntax#}) is the line terminator in Zig source code.
10457 This byte value terminates every line of zig source code except the last line of the file.
10458 It is recommended that non-empty source files end with an empty line, which means the last byte would be 0x0a (LF).
10459 </p>
10460 <p>
10461 Each LF may be immediately preceded by a single CR (byte value 0x0d, code point U+000d, {#syntax#}'\r'{#endsyntax#})
10462 to form a Windows style line ending, but this is discouraged.
10463 A CR in any other context is not allowed.
10464 </p>
10465 <p>
10466 HT hard tabs (byte value 0x09, code point U+0009, {#syntax#}'\t'{#endsyntax#}) are interchangeable with
10467 SP spaces (byte value 0x20, code point U+0020, {#syntax#}' '{#endsyntax#}) as a token separator,
10468 but use of hard tabs is discouraged. See {#link|Grammar#}.
10469 </p>
10470 <p>
10471 Note that running <code>zig fmt</code> on a source file will implement all recommendations mentioned here.
10472 Note also that the stage1 compiler does <a href="https://github.com/ziglang/zig/wiki/FAQ#why-does-zig-force-me-to-use-spaces-instead-of-tabs">not yet support CR or HT</a> control characters.
10473 </p>
10474 <p>
10475 Note that a tool reading Zig source code can make assumptions if the source code is assumed to be correct Zig code.
10476 For example, when identifying the ends of lines, a tool can use a naive search such as <code>/\n/</code>,
10477 or an <a href="https://msdn.microsoft.com/en-us/library/dd409797.aspx">advanced</a>
10478 search such as <code>/\r\n?|[\n\u0085\u2028\u2029]/</code>, and in either case line endings will be correctly identified.
10479 For another example, when identifying the whitespace before the first token on a line,
10480 a tool can either use a naive search such as <code>/[ \t]/</code>,
10481 or an <a href="https://tc39.es/ecma262/#sec-characterclassescape">advanced</a> search such as <code>/\s/</code>,
10482 and in either case whitespace will be correctly identified.
10483 </p>
10457 {#header_close#}10484 {#header_close#}
1045810485
10459 {#header_open|Keyword Reference#}10486 {#header_open|Keyword Reference#}
...@@ -11373,6 +11400,7 @@ ExprList &lt;- (Expr COMMA)* Expr?...@@ -11373,6 +11400,7 @@ ExprList &lt;- (Expr COMMA)* Expr?
1137311400
11374# *** Tokens ***11401# *** Tokens ***
11375eof &lt;- !.11402eof &lt;- !.
11403eol &lt;- ('\r'? '\n') | eof
11376hex &lt;- [0-9a-fA-F]11404hex &lt;- [0-9a-fA-F]
11377hex_ &lt;- ('_'/hex)11405hex_ &lt;- ('_'/hex)
11378dec &lt;- [0-9]11406dec &lt;- [0-9]
...@@ -11382,39 +11410,39 @@ dec_int &lt;- dec (dec_* dec)?...@@ -11382,39 +11410,39 @@ dec_int &lt;- dec (dec_* dec)?
11382hex_int &lt;- hex (hex_* dec)?11410hex_int &lt;- hex (hex_* dec)?
1138311411
11384char_escape11412char_escape
11385 &lt;- &quot;\\x&quot; hex hex11413 &lt;- '\\x' hex hex
11386 / &quot;\\u{&quot; hex+ &quot;}&quot;11414 / '\\u{' hex+ '}'
11387 / &quot;\\&quot; [nr\\t'&quot;]11415 / '\\' [nr\\t'&quot;]
11388char_char11416char_char
11389 &lt;- char_escape11417 &lt;- char_escape
11390 / [^\\'\n]11418 / [^\\'\r\n]
11391string_char11419string_char
11392 &lt;- char_escape11420 &lt;- char_escape
11393 / [^\\&quot;\n]11421 / [^\\&quot;\r\n]
1139411422
11395line_comment &lt;- '//'[^\n]*11423line_comment &lt;- '//'[^\r\n]* eol
11396line_string &lt;- (&quot;\\\\&quot; [^\n]* [ \n]*)+11424line_string &lt;- ('\\\\' [^\r\n]* eol skip)+
11397skip &lt;- ([ \n] / line_comment)*11425skip &lt;- ([ \t] / eol / line_comment)*
1139811426
11399CHAR_LITERAL &lt;- &quot;'&quot; char_char &quot;'&quot; skip11427CHAR_LITERAL &lt;- &quot;'&quot; char_char &quot;'&quot; skip
11400FLOAT11428FLOAT
11401 &lt;- &quot;0x&quot; hex_* hex &quot;.&quot; hex_int ([pP] [-+]? hex_int)? skip11429 &lt;- '0x' hex_* hex '.' hex_int ([pP] [-+]? hex_int)? skip
11402 / dec_int &quot;.&quot; dec_int ([eE] [-+]? dec_int)? skip11430 / dec_int '.' dec_int ([eE] [-+]? dec_int)? skip
11403 / &quot;0x&quot; hex_* hex &quot;.&quot;? [pP] [-+]? hex_int skip11431 / '0x' hex_* hex '.'? [pP] [-+]? hex_int skip
11404 / dec_int &quot;.&quot;? [eE] [-+]? dec_int skip11432 / dec_int '.'? [eE] [-+]? dec_int skip
11405INTEGER11433INTEGER
11406 &lt;- &quot;0b&quot; [_01]* [01] skip11434 &lt;- '0b' [_01]* [01] skip
11407 / &quot;0o&quot; [_0-7]* [0-7] skip11435 / '0o' [_0-7]* [0-7] skip
11408 / &quot;0x&quot; hex_* hex skip11436 / '0x' hex_* hex skip
11409 / dec_int skip11437 / dec_int skip
11410STRINGLITERALSINGLE &lt;- &quot;\&quot;&quot; string_char* &quot;\&quot;&quot; skip11438STRINGLITERALSINGLE &lt;- '&quot;' string_char* '&quot;' skip
11411STRINGLITERAL11439STRINGLITERAL
11412 &lt;- STRINGLITERALSINGLE11440 &lt;- STRINGLITERALSINGLE
11413 / line_string skip11441 / line_string skip
11414IDENTIFIER11442IDENTIFIER
11415 &lt;- !keyword [A-Za-z_] [A-Za-z0-9_]* skip11443 &lt;- !keyword [A-Za-z_] [A-Za-z0-9_]* skip
11416 / &quot;@\&quot;&quot; string_char* &quot;\&quot;&quot; skip11444 / '@&quot;' string_char* '&quot;' skip
11417BUILTINIDENTIFIER &lt;- &quot;@&quot;[A-Za-z_][A-Za-z0-9_]* skip11445BUILTINIDENTIFIER &lt;- '@'[A-Za-z_][A-Za-z0-9_]* skip
1141811446
1141911447
11420AMPERSAND &lt;- '&amp;' ![=] skip11448AMPERSAND &lt;- '&amp;' ![=] skip
lib/std/bit_set.zig created+1255
...@@ -0,0 +1,1255 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7//! This file defines several variants of bit sets. A bit set
8//! is a densely stored set of integers with a known maximum,
9//! in which each integer gets a single bit. Bit sets have very
10//! fast presence checks, update operations, and union and intersection
11//! operations. However, if the number of possible items is very
12//! large and the number of actual items in a given set is usually
13//! small, they may be less memory efficient than an array set.
14//!
15//! There are five variants defined here:
16//!
17//! IntegerBitSet:
18//! A bit set with static size, which is backed by a single integer.
19//! This set is good for sets with a small size, but may generate
20//! inefficient code for larger sets, especially in debug mode.
21//!
22//! ArrayBitSet:
23//! A bit set with static size, which is backed by an array of usize.
24//! This set is good for sets with a larger size, but may use
25//! more bytes than necessary if your set is small.
26//!
27//! StaticBitSet:
28//! Picks either IntegerBitSet or ArrayBitSet depending on the requested
29//! size. The interfaces of these two types match exactly, except for fields.
30//!
31//! DynamicBitSet:
32//! A bit set with runtime known size, backed by an allocated slice
33//! of usize.
34//!
35//! DynamicBitSetUnmanaged:
36//! A variant of DynamicBitSet which does not store a pointer to its
37//! allocator, in order to save space.
38
39const std = @import("std");
40const assert = std.debug.assert;
41const Allocator = std.mem.Allocator;
42
43/// Returns the optimal static bit set type for the specified number
44/// of elements. The returned type will perform no allocations,
45/// can be copied by value, and does not require deinitialization.
46/// Both possible implementations fulfill the same interface.
47pub fn StaticBitSet(comptime size: usize) type {
48 if (size <= @bitSizeOf(usize)) {
49 return IntegerBitSet(size);
50 } else {
51 return ArrayBitSet(usize, size);
52 }
53}
54
55/// A bit set with static size, which is backed by a single integer.
56/// This set is good for sets with a small size, but may generate
57/// inefficient code for larger sets, especially in debug mode.
58pub fn IntegerBitSet(comptime size: u16) type {
59 return struct {
60 const Self = @This();
61
62 // TODO: Make this a comptime field once those are fixed
63 /// The number of items in this bit set
64 pub const bit_length: usize = size;
65
66 /// The integer type used to represent a mask in this bit set
67 pub const MaskInt = std.meta.Int(.unsigned, size);
68
69 /// The integer type used to shift a mask in this bit set
70 pub const ShiftInt = std.math.Log2Int(MaskInt);
71
72 /// The bit mask, as a single integer
73 mask: MaskInt,
74
75 /// Creates a bit set with no elements present.
76 pub fn initEmpty() Self {
77 return .{ .mask = 0 };
78 }
79
80 /// Creates a bit set with all elements present.
81 pub fn initFull() Self {
82 return .{ .mask = ~@as(MaskInt, 0) };
83 }
84
85 /// Returns the number of bits in this bit set
86 pub fn capacity(self: Self) callconv(.Inline) usize {
87 return bit_length;
88 }
89
90 /// Returns true if the bit at the specified index
91 /// is present in the set, false otherwise.
92 pub fn isSet(self: Self, index: usize) bool {
93 assert(index < bit_length);
94 return (self.mask & maskBit(index)) != 0;
95 }
96
97 /// Returns the total number of set bits in this bit set.
98 pub fn count(self: Self) usize {
99 return @popCount(MaskInt, self.mask);
100 }
101
102 /// Changes the value of the specified bit of the bit
103 /// set to match the passed boolean.
104 pub fn setValue(self: *Self, index: usize, value: bool) void {
105 assert(index < bit_length);
106 if (MaskInt == u0) return;
107 const bit = maskBit(index);
108 const new_bit = bit & std.math.boolMask(MaskInt, value);
109 self.mask = (self.mask & ~bit) | new_bit;
110 }
111
112 /// Adds a specific bit to the bit set
113 pub fn set(self: *Self, index: usize) void {
114 assert(index < bit_length);
115 self.mask |= maskBit(index);
116 }
117
118 /// Removes a specific bit from the bit set
119 pub fn unset(self: *Self, index: usize) void {
120 assert(index < bit_length);
121 // Workaround for #7953
122 if (MaskInt == u0) return;
123 self.mask &= ~maskBit(index);
124 }
125
126 /// Flips a specific bit in the bit set
127 pub fn toggle(self: *Self, index: usize) void {
128 assert(index < bit_length);
129 self.mask ^= maskBit(index);
130 }
131
132 /// Flips all bits in this bit set which are present
133 /// in the toggles bit set.
134 pub fn toggleSet(self: *Self, toggles: Self) void {
135 self.mask ^= toggles.mask;
136 }
137
138 /// Flips every bit in the bit set.
139 pub fn toggleAll(self: *Self) void {
140 self.mask = ~self.mask;
141 }
142
143 /// Performs a union of two bit sets, and stores the
144 /// result in the first one. Bits in the result are
145 /// set if the corresponding bits were set in either input.
146 pub fn setUnion(self: *Self, other: Self) void {
147 self.mask |= other.mask;
148 }
149
150 /// Performs an intersection of two bit sets, and stores
151 /// the result in the first one. Bits in the result are
152 /// set if the corresponding bits were set in both inputs.
153 pub fn setIntersection(self: *Self, other: Self) void {
154 self.mask &= other.mask;
155 }
156
157 /// Finds the index of the first set bit.
158 /// If no bits are set, returns null.
159 pub fn findFirstSet(self: Self) ?usize {
160 const mask = self.mask;
161 if (mask == 0) return null;
162 return @ctz(MaskInt, mask);
163 }
164
165 /// Finds the index of the first set bit, and unsets it.
166 /// If no bits are set, returns null.
167 pub fn toggleFirstSet(self: *Self) ?usize {
168 const mask = self.mask;
169 if (mask == 0) return null;
170 const index = @ctz(MaskInt, mask);
171 self.mask = mask & (mask - 1);
172 return index;
173 }
174
175 /// Iterates through the items in the set, according to the options.
176 /// The default options (.{}) will iterate indices of set bits in
177 /// ascending order. Modifications to the underlying bit set may
178 /// or may not be observed by the iterator.
179 pub fn iterator(self: *const Self, comptime options: IteratorOptions) Iterator(options.direction) {
180 return .{
181 .bits_remain = switch (options.kind) {
182 .set => self.mask,
183 .unset => ~self.mask,
184 },
185 };
186 }
187
188 fn Iterator(comptime direction: IteratorOptions.Direction) type {
189 return struct {
190 const IterSelf = @This();
191 // all bits which have not yet been iterated over
192 bits_remain: MaskInt,
193
194 /// Returns the index of the next unvisited set bit
195 /// in the bit set, in ascending order.
196 pub fn next(self: *IterSelf) ?usize {
197 if (self.bits_remain == 0) return null;
198
199 switch (direction) {
200 .forward => {
201 const next_index = @ctz(MaskInt, self.bits_remain);
202 self.bits_remain &= self.bits_remain - 1;
203 return next_index;
204 },
205 .reverse => {
206 const leading_zeroes = @clz(MaskInt, self.bits_remain);
207 const top_bit = (@bitSizeOf(MaskInt) - 1) - leading_zeroes;
208 self.bits_remain &= (@as(MaskInt, 1) << @intCast(ShiftInt, top_bit)) - 1;
209 return top_bit;
210 },
211 }
212 }
213 };
214 }
215
216 fn maskBit(index: usize) MaskInt {
217 if (MaskInt == u0) return 0;
218 return @as(MaskInt, 1) << @intCast(ShiftInt, index);
219 }
220 fn boolMaskBit(index: usize, value: bool) MaskInt {
221 if (MaskInt == u0) return 0;
222 return @as(MaskInt, @boolToInt(value)) << @intCast(ShiftInt, index);
223 }
224 };
225}
226
227/// A bit set with static size, which is backed by an array of usize.
228/// This set is good for sets with a larger size, but may use
229/// more bytes than necessary if your set is small.
230pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
231 const mask_info: std.builtin.TypeInfo = @typeInfo(MaskIntType);
232
233 // Make sure the mask int is indeed an int
234 if (mask_info != .Int) @compileError("ArrayBitSet can only operate on integer masks, but was passed " ++ @typeName(MaskIntType));
235
236 // It must also be unsigned.
237 if (mask_info.Int.signedness != .unsigned) @compileError("ArrayBitSet requires an unsigned integer mask type, but was passed " ++ @typeName(MaskIntType));
238
239 // And it must not be empty.
240 if (MaskIntType == u0)
241 @compileError("ArrayBitSet requires a sized integer for its mask int. u0 does not work.");
242
243 const byte_size = std.mem.byte_size_in_bits;
244
245 // We use shift and truncate to decompose indices into mask indices and bit indices.
246 // This operation requires that the mask has an exact power of two number of bits.
247 if (!std.math.isPowerOfTwo(@bitSizeOf(MaskIntType))) {
248 var desired_bits = std.math.ceilPowerOfTwoAssert(usize, @bitSizeOf(MaskIntType));
249 if (desired_bits < byte_size) desired_bits = byte_size;
250 const FixedMaskType = std.meta.Int(.unsigned, desired_bits);
251 @compileError("ArrayBitSet was passed integer type " ++ @typeName(MaskIntType) ++
252 ", which is not a power of two. Please round this up to a power of two integer size (i.e. " ++ @typeName(FixedMaskType) ++ ").");
253 }
254
255 // Make sure the integer has no padding bits.
256 // Those would be wasteful here and are probably a mistake by the user.
257 // This case may be hit with small powers of two, like u4.
258 if (@bitSizeOf(MaskIntType) != @sizeOf(MaskIntType) * byte_size) {
259 var desired_bits = @sizeOf(MaskIntType) * byte_size;
260 desired_bits = std.math.ceilPowerOfTwoAssert(usize, desired_bits);
261 const FixedMaskType = std.meta.Int(.unsigned, desired_bits);
262 @compileError("ArrayBitSet was passed integer type " ++ @typeName(MaskIntType) ++
263 ", which contains padding bits. Please round this up to an unpadded integer size (i.e. " ++ @typeName(FixedMaskType) ++ ").");
264 }
265
266 return struct {
267 const Self = @This();
268
269 // TODO: Make this a comptime field once those are fixed
270 /// The number of items in this bit set
271 pub const bit_length: usize = size;
272
273 /// The integer type used to represent a mask in this bit set
274 pub const MaskInt = MaskIntType;
275
276 /// The integer type used to shift a mask in this bit set
277 pub const ShiftInt = std.math.Log2Int(MaskInt);
278
279 // bits in one mask
280 const mask_len = @bitSizeOf(MaskInt);
281 // total number of masks
282 const num_masks = (size + mask_len - 1) / mask_len;
283 // padding bits in the last mask (may be 0)
284 const last_pad_bits = mask_len * num_masks - size;
285 // Mask of valid bits in the last mask.
286 // All functions will ensure that the invalid
287 // bits in the last mask are zero.
288 pub const last_item_mask = ~@as(MaskInt, 0) >> last_pad_bits;
289
290 /// The bit masks, ordered with lower indices first.
291 /// Padding bits at the end are undefined.
292 masks: [num_masks]MaskInt,
293
294 /// Creates a bit set with no elements present.
295 pub fn initEmpty() Self {
296 return .{ .masks = [_]MaskInt{0} ** num_masks };
297 }
298
299 /// Creates a bit set with all elements present.
300 pub fn initFull() Self {
301 if (num_masks == 0) {
302 return .{ .masks = .{} };
303 } else {
304 return .{ .masks = [_]MaskInt{~@as(MaskInt, 0)} ** (num_masks - 1) ++ [_]MaskInt{last_item_mask} };
305 }
306 }
307
308 /// Returns the number of bits in this bit set
309 pub fn capacity(self: Self) callconv(.Inline) usize {
310 return bit_length;
311 }
312
313 /// Returns true if the bit at the specified index
314 /// is present in the set, false otherwise.
315 pub fn isSet(self: Self, index: usize) bool {
316 assert(index < bit_length);
317 if (num_masks == 0) return false; // doesn't compile in this case
318 return (self.masks[maskIndex(index)] & maskBit(index)) != 0;
319 }
320
321 /// Returns the total number of set bits in this bit set.
322 pub fn count(self: Self) usize {
323 var total: usize = 0;
324 for (self.masks) |mask| {
325 total += @popCount(MaskInt, mask);
326 }
327 return total;
328 }
329
330 /// Changes the value of the specified bit of the bit
331 /// set to match the passed boolean.
332 pub fn setValue(self: *Self, index: usize, value: bool) void {
333 assert(index < bit_length);
334 if (num_masks == 0) return; // doesn't compile in this case
335 const bit = maskBit(index);
336 const mask_index = maskIndex(index);
337 const new_bit = bit & std.math.boolMask(MaskInt, value);
338 self.masks[mask_index] = (self.masks[mask_index] & ~bit) | new_bit;
339 }
340
341 /// Adds a specific bit to the bit set
342 pub fn set(self: *Self, index: usize) void {
343 assert(index < bit_length);
344 if (num_masks == 0) return; // doesn't compile in this case
345 self.masks[maskIndex(index)] |= maskBit(index);
346 }
347
348 /// Removes a specific bit from the bit set
349 pub fn unset(self: *Self, index: usize) void {
350 assert(index < bit_length);
351 if (num_masks == 0) return; // doesn't compile in this case
352 self.masks[maskIndex(index)] &= ~maskBit(index);
353 }
354
355 /// Flips a specific bit in the bit set
356 pub fn toggle(self: *Self, index: usize) void {
357 assert(index < bit_length);
358 if (num_masks == 0) return; // doesn't compile in this case
359 self.masks[maskIndex(index)] ^= maskBit(index);
360 }
361
362 /// Flips all bits in this bit set which are present
363 /// in the toggles bit set.
364 pub fn toggleSet(self: *Self, toggles: Self) void {
365 for (self.masks) |*mask, i| {
366 mask.* ^= toggles.masks[i];
367 }
368 }
369
370 /// Flips every bit in the bit set.
371 pub fn toggleAll(self: *Self) void {
372 for (self.masks) |*mask, i| {
373 mask.* = ~mask.*;
374 }
375
376 // Zero the padding bits
377 if (num_masks > 0) {
378 self.masks[num_masks - 1] &= last_item_mask;
379 }
380 }
381
382 /// Performs a union of two bit sets, and stores the
383 /// result in the first one. Bits in the result are
384 /// set if the corresponding bits were set in either input.
385 pub fn setUnion(self: *Self, other: Self) void {
386 for (self.masks) |*mask, i| {
387 mask.* |= other.masks[i];
388 }
389 }
390
391 /// Performs an intersection of two bit sets, and stores
392 /// the result in the first one. Bits in the result are
393 /// set if the corresponding bits were set in both inputs.
394 pub fn setIntersection(self: *Self, other: Self) void {
395 for (self.masks) |*mask, i| {
396 mask.* &= other.masks[i];
397 }
398 }
399
400 /// Finds the index of the first set bit.
401 /// If no bits are set, returns null.
402 pub fn findFirstSet(self: Self) ?usize {
403 var offset: usize = 0;
404 const mask = for (self.masks) |mask| {
405 if (mask != 0) break mask;
406 offset += @bitSizeOf(MaskInt);
407 } else return null;
408 return offset + @ctz(MaskInt, mask);
409 }
410
411 /// Finds the index of the first set bit, and unsets it.
412 /// If no bits are set, returns null.
413 pub fn toggleFirstSet(self: *Self) ?usize {
414 var offset: usize = 0;
415 const mask = for (self.masks) |*mask| {
416 if (mask.* != 0) break mask;
417 offset += @bitSizeOf(MaskInt);
418 } else return null;
419 const index = @ctz(MaskInt, mask.*);
420 mask.* &= (mask.* - 1);
421 return offset + index;
422 }
423
424 /// Iterates through the items in the set, according to the options.
425 /// The default options (.{}) will iterate indices of set bits in
426 /// ascending order. Modifications to the underlying bit set may
427 /// or may not be observed by the iterator.
428 pub fn iterator(self: *const Self, comptime options: IteratorOptions) BitSetIterator(MaskInt, options) {
429 return BitSetIterator(MaskInt, options).init(&self.masks, last_item_mask);
430 }
431
432 fn maskBit(index: usize) MaskInt {
433 return @as(MaskInt, 1) << @truncate(ShiftInt, index);
434 }
435 fn maskIndex(index: usize) usize {
436 return index >> @bitSizeOf(ShiftInt);
437 }
438 fn boolMaskBit(index: usize, value: bool) MaskInt {
439 return @as(MaskInt, @boolToInt(value)) << @intCast(ShiftInt, index);
440 }
441 };
442}
443
444/// A bit set with runtime known size, backed by an allocated slice
445/// of usize. The allocator must be tracked externally by the user.
446pub const DynamicBitSetUnmanaged = struct {
447 const Self = @This();
448
449 /// The integer type used to represent a mask in this bit set
450 pub const MaskInt = usize;
451
452 /// The integer type used to shift a mask in this bit set
453 pub const ShiftInt = std.math.Log2Int(MaskInt);
454
455 /// The number of valid items in this bit set
456 bit_length: usize = 0,
457
458 /// The bit masks, ordered with lower indices first.
459 /// Padding bits at the end must be zeroed.
460 masks: [*]MaskInt = empty_masks_ptr,
461 // This pointer is one usize after the actual allocation.
462 // That slot holds the size of the true allocation, which
463 // is needed by Zig's allocator interface in case a shrink
464 // fails.
465
466 // Don't modify this value. Ideally it would go in const data so
467 // modifications would cause a bus error, but the only way
468 // to discard a const qualifier is through ptrToInt, which
469 // cannot currently round trip at comptime.
470 var empty_masks_data = [_]MaskInt{ 0, undefined };
471 const empty_masks_ptr = empty_masks_data[1..2];
472
473 /// Creates a bit set with no elements present.
474 /// If bit_length is not zero, deinit must eventually be called.
475 pub fn initEmpty(bit_length: usize, allocator: *Allocator) !Self {
476 var self = Self{};
477 try self.resize(bit_length, false, allocator);
478 return self;
479 }
480
481 /// Creates a bit set with all elements present.
482 /// If bit_length is not zero, deinit must eventually be called.
483 pub fn initFull(bit_length: usize, allocator: *Allocator) !Self {
484 var self = Self{};
485 try self.resize(bit_length, true, allocator);
486 return self;
487 }
488
489 /// Resizes to a new bit_length. If the new length is larger
490 /// than the old length, fills any added bits with `fill`.
491 /// If new_len is not zero, deinit must eventually be called.
492 pub fn resize(self: *@This(), new_len: usize, fill: bool, allocator: *Allocator) !void {
493 const old_len = self.bit_length;
494
495 const old_masks = numMasks(old_len);
496 const new_masks = numMasks(new_len);
497
498 const old_allocation = (self.masks - 1)[0..(self.masks - 1)[0]];
499
500 if (new_masks == 0) {
501 assert(new_len == 0);
502 allocator.free(old_allocation);
503 self.masks = empty_masks_ptr;
504 self.bit_length = 0;
505 return;
506 }
507
508 if (old_allocation.len != new_masks + 1) realloc: {
509 // If realloc fails, it may mean one of two things.
510 // If we are growing, it means we are out of memory.
511 // If we are shrinking, it means the allocator doesn't
512 // want to move the allocation. This means we need to
513 // hold on to the extra 8 bytes required to be able to free
514 // this allocation properly.
515 const new_allocation = allocator.realloc(old_allocation, new_masks + 1) catch |err| {
516 if (new_masks + 1 > old_allocation.len) return err;
517 break :realloc;
518 };
519
520 new_allocation[0] = new_allocation.len;
521 self.masks = new_allocation.ptr + 1;
522 }
523
524 // If we increased in size, we need to set any new bits
525 // to the fill value.
526 if (new_len > old_len) {
527 // set the padding bits in the old last item to 1
528 if (fill and old_masks > 0) {
529 const old_padding_bits = old_masks * @bitSizeOf(MaskInt) - old_len;
530 const old_mask = (~@as(MaskInt, 0)) >> @intCast(ShiftInt, old_padding_bits);
531 self.masks[old_masks - 1] |= ~old_mask;
532 }
533
534 // fill in any new masks
535 if (new_masks > old_masks) {
536 const fill_value = std.math.boolMask(MaskInt, fill);
537 std.mem.set(MaskInt, self.masks[old_masks..new_masks], fill_value);
538 }
539 }
540
541 // Zero out the padding bits
542 if (new_len > 0) {
543 const padding_bits = new_masks * @bitSizeOf(MaskInt) - new_len;
544 const last_item_mask = (~@as(MaskInt, 0)) >> @intCast(ShiftInt, padding_bits);
545 self.masks[new_masks - 1] &= last_item_mask;
546 }
547
548 // And finally, save the new length.
549 self.bit_length = new_len;
550 }
551
552 /// deinitializes the array and releases its memory.
553 /// The passed allocator must be the same one used for
554 /// init* or resize in the past.
555 pub fn deinit(self: *Self, allocator: *Allocator) void {
556 self.resize(0, false, allocator) catch unreachable;
557 }
558
559 /// Creates a duplicate of this bit set, using the new allocator.
560 pub fn clone(self: *const Self, new_allocator: *Allocator) !Self {
561 const num_masks = numMasks(self.bit_length);
562 var copy = Self{};
563 try copy.resize(self.bit_length, false, new_allocator);
564 std.mem.copy(MaskInt, copy.masks[0..num_masks], self.masks[0..num_masks]);
565 return copy;
566 }
567
568 /// Returns the number of bits in this bit set
569 pub fn capacity(self: Self) callconv(.Inline) usize {
570 return self.bit_length;
571 }
572
573 /// Returns true if the bit at the specified index
574 /// is present in the set, false otherwise.
575 pub fn isSet(self: Self, index: usize) bool {
576 assert(index < self.bit_length);
577 return (self.masks[maskIndex(index)] & maskBit(index)) != 0;
578 }
579
580 /// Returns the total number of set bits in this bit set.
581 pub fn count(self: Self) usize {
582 const num_masks = (self.bit_length + (@bitSizeOf(MaskInt) - 1)) / @bitSizeOf(MaskInt);
583 var total: usize = 0;
584 for (self.masks[0..num_masks]) |mask| {
585 // Note: This is where we depend on padding bits being zero
586 total += @popCount(MaskInt, mask);
587 }
588 return total;
589 }
590
591 /// Changes the value of the specified bit of the bit
592 /// set to match the passed boolean.
593 pub fn setValue(self: *Self, index: usize, value: bool) void {
594 assert(index < self.bit_length);
595 const bit = maskBit(index);
596 const mask_index = maskIndex(index);
597 const new_bit = bit & std.math.boolMask(MaskInt, value);
598 self.masks[mask_index] = (self.masks[mask_index] & ~bit) | new_bit;
599 }
600
601 /// Adds a specific bit to the bit set
602 pub fn set(self: *Self, index: usize) void {
603 assert(index < self.bit_length);
604 self.masks[maskIndex(index)] |= maskBit(index);
605 }
606
607 /// Removes a specific bit from the bit set
608 pub fn unset(self: *Self, index: usize) void {
609 assert(index < self.bit_length);
610 self.masks[maskIndex(index)] &= ~maskBit(index);
611 }
612
613 /// Flips a specific bit in the bit set
614 pub fn toggle(self: *Self, index: usize) void {
615 assert(index < self.bit_length);
616 self.masks[maskIndex(index)] ^= maskBit(index);
617 }
618
619 /// Flips all bits in this bit set which are present
620 /// in the toggles bit set. Both sets must have the
621 /// same bit_length.
622 pub fn toggleSet(self: *Self, toggles: Self) void {
623 assert(toggles.bit_length == self.bit_length);
624 const num_masks = numMasks(self.bit_length);
625 for (self.masks[0..num_masks]) |*mask, i| {
626 mask.* ^= toggles.masks[i];
627 }
628 }
629
630 /// Flips every bit in the bit set.
631 pub fn toggleAll(self: *Self) void {
632 const bit_length = self.bit_length;
633 // avoid underflow if bit_length is zero
634 if (bit_length == 0) return;
635
636 const num_masks = numMasks(self.bit_length);
637 for (self.masks[0..num_masks]) |*mask, i| {
638 mask.* = ~mask.*;
639 }
640
641 const padding_bits = num_masks * @bitSizeOf(MaskInt) - bit_length;
642 const last_item_mask = (~@as(MaskInt, 0)) >> @intCast(ShiftInt, padding_bits);
643 self.masks[num_masks - 1] &= last_item_mask;
644 }
645
646 /// Performs a union of two bit sets, and stores the
647 /// result in the first one. Bits in the result are
648 /// set if the corresponding bits were set in either input.
649 /// The two sets must both be the same bit_length.
650 pub fn setUnion(self: *Self, other: Self) void {
651 assert(other.bit_length == self.bit_length);
652 const num_masks = numMasks(self.bit_length);
653 for (self.masks[0..num_masks]) |*mask, i| {
654 mask.* |= other.masks[i];
655 }
656 }
657
658 /// Performs an intersection of two bit sets, and stores
659 /// the result in the first one. Bits in the result are
660 /// set if the corresponding bits were set in both inputs.
661 /// The two sets must both be the same bit_length.
662 pub fn setIntersection(self: *Self, other: Self) void {
663 assert(other.bit_length == self.bit_length);
664 const num_masks = numMasks(self.bit_length);
665 for (self.masks[0..num_masks]) |*mask, i| {
666 mask.* &= other.masks[i];
667 }
668 }
669
670 /// Finds the index of the first set bit.
671 /// If no bits are set, returns null.
672 pub fn findFirstSet(self: Self) ?usize {
673 var offset: usize = 0;
674 var mask = self.masks;
675 while (offset < self.bit_length) {
676 if (mask[0] != 0) break;
677 mask += 1;
678 offset += @bitSizeOf(MaskInt);
679 } else return null;
680 return offset + @ctz(MaskInt, mask[0]);
681 }
682
683 /// Finds the index of the first set bit, and unsets it.
684 /// If no bits are set, returns null.
685 pub fn toggleFirstSet(self: *Self) ?usize {
686 var offset: usize = 0;
687 var mask = self.masks;
688 while (offset < self.bit_length) {
689 if (mask[0] != 0) break;
690 mask += 1;
691 offset += @bitSizeOf(MaskInt);
692 } else return null;
693 const index = @ctz(MaskInt, mask[0]);
694 mask[0] &= (mask[0] - 1);
695 return offset + index;
696 }
697
698 /// Iterates through the items in the set, according to the options.
699 /// The default options (.{}) will iterate indices of set bits in
700 /// ascending order. Modifications to the underlying bit set may
701 /// or may not be observed by the iterator. Resizing the underlying
702 /// bit set invalidates the iterator.
703 pub fn iterator(self: *const Self, comptime options: IteratorOptions) BitSetIterator(MaskInt, options) {
704 const num_masks = numMasks(self.bit_length);
705 const padding_bits = num_masks * @bitSizeOf(MaskInt) - self.bit_length;
706 const last_item_mask = (~@as(MaskInt, 0)) >> @intCast(ShiftInt, padding_bits);
707 return BitSetIterator(MaskInt, options).init(self.masks[0..num_masks], last_item_mask);
708 }
709
710 fn maskBit(index: usize) MaskInt {
711 return @as(MaskInt, 1) << @truncate(ShiftInt, index);
712 }
713 fn maskIndex(index: usize) usize {
714 return index >> @bitSizeOf(ShiftInt);
715 }
716 fn boolMaskBit(index: usize, value: bool) MaskInt {
717 return @as(MaskInt, @boolToInt(value)) << @intCast(ShiftInt, index);
718 }
719 fn numMasks(bit_length: usize) usize {
720 return (bit_length + (@bitSizeOf(MaskInt) - 1)) / @bitSizeOf(MaskInt);
721 }
722};
723
724/// A bit set with runtime known size, backed by an allocated slice
725/// of usize. Thin wrapper around DynamicBitSetUnmanaged which keeps
726/// track of the allocator instance.
727pub const DynamicBitSet = struct {
728 const Self = @This();
729
730 /// The integer type used to represent a mask in this bit set
731 pub const MaskInt = usize;
732
733 /// The integer type used to shift a mask in this bit set
734 pub const ShiftInt = std.math.Log2Int(MaskInt);
735
736 /// The allocator used by this bit set
737 allocator: *Allocator,
738
739 /// The number of valid items in this bit set
740 unmanaged: DynamicBitSetUnmanaged = .{},
741
742 /// Creates a bit set with no elements present.
743 pub fn initEmpty(bit_length: usize, allocator: *Allocator) !Self {
744 return Self{
745 .unmanaged = try DynamicBitSetUnmanaged.initEmpty(bit_length, allocator),
746 .allocator = allocator,
747 };
748 }
749
750 /// Creates a bit set with all elements present.
751 pub fn initFull(bit_length: usize, allocator: *Allocator) !Self {
752 return Self{
753 .unmanaged = try DynamicBitSetUnmanaged.initFull(bit_length, allocator),
754 .allocator = allocator,
755 };
756 }
757
758 /// Resizes to a new length. If the new length is larger
759 /// than the old length, fills any added bits with `fill`.
760 pub fn resize(self: *@This(), new_len: usize, fill: bool) !void {
761 try self.unmanaged.resize(new_len, fill, self.allocator);
762 }
763
764 /// deinitializes the array and releases its memory.
765 /// The passed allocator must be the same one used for
766 /// init* or resize in the past.
767 pub fn deinit(self: *Self) void {
768 self.unmanaged.deinit(self.allocator);
769 }
770
771 /// Creates a duplicate of this bit set, using the new allocator.
772 pub fn clone(self: *const Self, new_allocator: *Allocator) !Self {
773 return Self{
774 .unmanaged = try self.unmanaged.clone(new_allocator),
775 .allocator = new_allocator,
776 };
777 }
778
779 /// Returns the number of bits in this bit set
780 pub fn capacity(self: Self) callconv(.Inline) usize {
781 return self.unmanaged.capacity();
782 }
783
784 /// Returns true if the bit at the specified index
785 /// is present in the set, false otherwise.
786 pub fn isSet(self: Self, index: usize) bool {
787 return self.unmanaged.isSet(index);
788 }
789
790 /// Returns the total number of set bits in this bit set.
791 pub fn count(self: Self) usize {
792 return self.unmanaged.count();
793 }
794
795 /// Changes the value of the specified bit of the bit
796 /// set to match the passed boolean.
797 pub fn setValue(self: *Self, index: usize, value: bool) void {
798 self.unmanaged.setValue(index, value);
799 }
800
801 /// Adds a specific bit to the bit set
802 pub fn set(self: *Self, index: usize) void {
803 self.unmanaged.set(index);
804 }
805
806 /// Removes a specific bit from the bit set
807 pub fn unset(self: *Self, index: usize) void {
808 self.unmanaged.unset(index);
809 }
810
811 /// Flips a specific bit in the bit set
812 pub fn toggle(self: *Self, index: usize) void {
813 self.unmanaged.toggle(index);
814 }
815
816 /// Flips all bits in this bit set which are present
817 /// in the toggles bit set. Both sets must have the
818 /// same bit_length.
819 pub fn toggleSet(self: *Self, toggles: Self) void {
820 self.unmanaged.toggleSet(toggles.unmanaged);
821 }
822
823 /// Flips every bit in the bit set.
824 pub fn toggleAll(self: *Self) void {
825 self.unmanaged.toggleAll();
826 }
827
828 /// Performs a union of two bit sets, and stores the
829 /// result in the first one. Bits in the result are
830 /// set if the corresponding bits were set in either input.
831 /// The two sets must both be the same bit_length.
832 pub fn setUnion(self: *Self, other: Self) void {
833 self.unmanaged.setUnion(other.unmanaged);
834 }
835
836 /// Performs an intersection of two bit sets, and stores
837 /// the result in the first one. Bits in the result are
838 /// set if the corresponding bits were set in both inputs.
839 /// The two sets must both be the same bit_length.
840 pub fn setIntersection(self: *Self, other: Self) void {
841 self.unmanaged.setIntersection(other.unmanaged);
842 }
843
844 /// Finds the index of the first set bit.
845 /// If no bits are set, returns null.
846 pub fn findFirstSet(self: Self) ?usize {
847 return self.unmanaged.findFirstSet();
848 }
849
850 /// Finds the index of the first set bit, and unsets it.
851 /// If no bits are set, returns null.
852 pub fn toggleFirstSet(self: *Self) ?usize {
853 return self.unmanaged.toggleFirstSet();
854 }
855
856 /// Iterates through the items in the set, according to the options.
857 /// The default options (.{}) will iterate indices of set bits in
858 /// ascending order. Modifications to the underlying bit set may
859 /// or may not be observed by the iterator. Resizing the underlying
860 /// bit set invalidates the iterator.
861 pub fn iterator(self: *Self, comptime options: IteratorOptions) BitSetIterator(MaskInt, options) {
862 return self.unmanaged.iterator(options);
863 }
864};
865
866/// Options for configuring an iterator over a bit set
867pub const IteratorOptions = struct {
868 /// determines which bits should be visited
869 kind: Type = .set,
870 /// determines the order in which bit indices should be visited
871 direction: Direction = .forward,
872
873 pub const Type = enum {
874 /// visit indexes of set bits
875 set,
876 /// visit indexes of unset bits
877 unset,
878 };
879
880 pub const Direction = enum {
881 /// visit indices in ascending order
882 forward,
883 /// visit indices in descending order.
884 /// Note that this may be slightly more expensive than forward iteration.
885 reverse,
886 };
887};
888
889// The iterator is reusable between several bit set types
890fn BitSetIterator(comptime MaskInt: type, comptime options: IteratorOptions) type {
891 const ShiftInt = std.math.Log2Int(MaskInt);
892 const kind = options.kind;
893 const direction = options.direction;
894 return struct {
895 const Self = @This();
896
897 // all bits which have not yet been iterated over
898 bits_remain: MaskInt,
899 // all words which have not yet been iterated over
900 words_remain: []const MaskInt,
901 // the offset of the current word
902 bit_offset: usize,
903 // the mask of the last word
904 last_word_mask: MaskInt,
905
906 fn init(masks: []const MaskInt, last_word_mask: MaskInt) Self {
907 if (masks.len == 0) {
908 return Self{
909 .bits_remain = 0,
910 .words_remain = &[_]MaskInt{},
911 .last_word_mask = last_word_mask,
912 .bit_offset = 0,
913 };
914 } else {
915 var result = Self{
916 .bits_remain = 0,
917 .words_remain = masks,
918 .last_word_mask = last_word_mask,
919 .bit_offset = if (direction == .forward) 0 else (masks.len - 1) * @bitSizeOf(MaskInt),
920 };
921 result.nextWord(true);
922 return result;
923 }
924 }
925
926 /// Returns the index of the next unvisited set bit
927 /// in the bit set, in ascending order.
928 pub fn next(self: *Self) ?usize {
929 while (self.bits_remain == 0) {
930 if (self.words_remain.len == 0) return null;
931 self.nextWord(false);
932 switch (direction) {
933 .forward => self.bit_offset += @bitSizeOf(MaskInt),
934 .reverse => self.bit_offset -= @bitSizeOf(MaskInt),
935 }
936 }
937
938 switch (direction) {
939 .forward => {
940 const next_index = @ctz(MaskInt, self.bits_remain) + self.bit_offset;
941 self.bits_remain &= self.bits_remain - 1;
942 return next_index;
943 },
944 .reverse => {
945 const leading_zeroes = @clz(MaskInt, self.bits_remain);
946 const top_bit = (@bitSizeOf(MaskInt) - 1) - leading_zeroes;
947 const no_top_bit_mask = (@as(MaskInt, 1) << @intCast(ShiftInt, top_bit)) - 1;
948 self.bits_remain &= no_top_bit_mask;
949 return top_bit + self.bit_offset;
950 },
951 }
952 }
953
954 // Load the next word. Don't call this if there
955 // isn't a next word. If the next word is the
956 // last word, mask off the padding bits so we
957 // don't visit them.
958 fn nextWord(self: *Self, comptime is_first_word: bool) callconv(.Inline) void {
959 var word = switch (direction) {
960 .forward => self.words_remain[0],
961 .reverse => self.words_remain[self.words_remain.len - 1],
962 };
963 switch (kind) {
964 .set => {},
965 .unset => {
966 word = ~word;
967 if ((direction == .reverse and is_first_word) or
968 (direction == .forward and self.words_remain.len == 1))
969 {
970 word &= self.last_word_mask;
971 }
972 },
973 }
974 switch (direction) {
975 .forward => self.words_remain = self.words_remain[1..],
976 .reverse => self.words_remain.len -= 1,
977 }
978 self.bits_remain = word;
979 }
980 };
981}
982
983// ---------------- Tests -----------------
984
985const testing = std.testing;
986
987fn testBitSet(a: anytype, b: anytype, len: usize) void {
988 testing.expectEqual(len, a.capacity());
989 testing.expectEqual(len, b.capacity());
990
991 {
992 var i: usize = 0;
993 while (i < len) : (i += 1) {
994 a.setValue(i, i & 1 == 0);
995 b.setValue(i, i & 2 == 0);
996 }
997 }
998
999 testing.expectEqual((len + 1) / 2, a.count());
1000 testing.expectEqual((len + 3) / 4 + (len + 2) / 4, b.count());
1001
1002 {
1003 var iter = a.iterator(.{});
1004 var i: usize = 0;
1005 while (i < len) : (i += 2) {
1006 testing.expectEqual(@as(?usize, i), iter.next());
1007 }
1008 testing.expectEqual(@as(?usize, null), iter.next());
1009 testing.expectEqual(@as(?usize, null), iter.next());
1010 testing.expectEqual(@as(?usize, null), iter.next());
1011 }
1012 a.toggleAll();
1013 {
1014 var iter = a.iterator(.{});
1015 var i: usize = 1;
1016 while (i < len) : (i += 2) {
1017 testing.expectEqual(@as(?usize, i), iter.next());
1018 }
1019 testing.expectEqual(@as(?usize, null), iter.next());
1020 testing.expectEqual(@as(?usize, null), iter.next());
1021 testing.expectEqual(@as(?usize, null), iter.next());
1022 }
1023
1024 {
1025 var iter = b.iterator(.{ .kind = .unset });
1026 var i: usize = 2;
1027 while (i < len) : (i += 4) {
1028 testing.expectEqual(@as(?usize, i), iter.next());
1029 if (i + 1 < len) {
1030 testing.expectEqual(@as(?usize, i + 1), iter.next());
1031 }
1032 }
1033 testing.expectEqual(@as(?usize, null), iter.next());
1034 testing.expectEqual(@as(?usize, null), iter.next());
1035 testing.expectEqual(@as(?usize, null), iter.next());
1036 }
1037
1038 {
1039 var i: usize = 0;
1040 while (i < len) : (i += 1) {
1041 testing.expectEqual(i & 1 != 0, a.isSet(i));
1042 testing.expectEqual(i & 2 == 0, b.isSet(i));
1043 }
1044 }
1045
1046 a.setUnion(b.*);
1047 {
1048 var i: usize = 0;
1049 while (i < len) : (i += 1) {
1050 testing.expectEqual(i & 1 != 0 or i & 2 == 0, a.isSet(i));
1051 testing.expectEqual(i & 2 == 0, b.isSet(i));
1052 }
1053
1054 i = len;
1055 var set = a.iterator(.{ .direction = .reverse });
1056 var unset = a.iterator(.{ .kind = .unset, .direction = .reverse });
1057 while (i > 0) {
1058 i -= 1;
1059 if (i & 1 != 0 or i & 2 == 0) {
1060 testing.expectEqual(@as(?usize, i), set.next());
1061 } else {
1062 testing.expectEqual(@as(?usize, i), unset.next());
1063 }
1064 }
1065 testing.expectEqual(@as(?usize, null), set.next());
1066 testing.expectEqual(@as(?usize, null), set.next());
1067 testing.expectEqual(@as(?usize, null), set.next());
1068 testing.expectEqual(@as(?usize, null), unset.next());
1069 testing.expectEqual(@as(?usize, null), unset.next());
1070 testing.expectEqual(@as(?usize, null), unset.next());
1071 }
1072
1073 a.toggleSet(b.*);
1074 {
1075 testing.expectEqual(len / 4, a.count());
1076
1077 var i: usize = 0;
1078 while (i < len) : (i += 1) {
1079 testing.expectEqual(i & 1 != 0 and i & 2 != 0, a.isSet(i));
1080 testing.expectEqual(i & 2 == 0, b.isSet(i));
1081 if (i & 1 == 0) {
1082 a.set(i);
1083 } else {
1084 a.unset(i);
1085 }
1086 }
1087 }
1088
1089 a.setIntersection(b.*);
1090 {
1091 testing.expectEqual((len + 3) / 4, a.count());
1092
1093 var i: usize = 0;
1094 while (i < len) : (i += 1) {
1095 testing.expectEqual(i & 1 == 0 and i & 2 == 0, a.isSet(i));
1096 testing.expectEqual(i & 2 == 0, b.isSet(i));
1097 }
1098 }
1099
1100 a.toggleSet(a.*);
1101 {
1102 var iter = a.iterator(.{});
1103 testing.expectEqual(@as(?usize, null), iter.next());
1104 testing.expectEqual(@as(?usize, null), iter.next());
1105 testing.expectEqual(@as(?usize, null), iter.next());
1106 testing.expectEqual(@as(usize, 0), a.count());
1107 }
1108 {
1109 var iter = a.iterator(.{ .direction = .reverse });
1110 testing.expectEqual(@as(?usize, null), iter.next());
1111 testing.expectEqual(@as(?usize, null), iter.next());
1112 testing.expectEqual(@as(?usize, null), iter.next());
1113 testing.expectEqual(@as(usize, 0), a.count());
1114 }
1115
1116 const test_bits = [_]usize{
1117 0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 22, 31, 32, 63, 64,
1118 66, 95, 127, 160, 192, 1000,
1119 };
1120 for (test_bits) |i| {
1121 if (i < a.capacity()) {
1122 a.set(i);
1123 }
1124 }
1125
1126 for (test_bits) |i| {
1127 if (i < a.capacity()) {
1128 testing.expectEqual(@as(?usize, i), a.findFirstSet());
1129 testing.expectEqual(@as(?usize, i), a.toggleFirstSet());
1130 }
1131 }
1132 testing.expectEqual(@as(?usize, null), a.findFirstSet());
1133 testing.expectEqual(@as(?usize, null), a.toggleFirstSet());
1134 testing.expectEqual(@as(?usize, null), a.findFirstSet());
1135 testing.expectEqual(@as(?usize, null), a.toggleFirstSet());
1136 testing.expectEqual(@as(usize, 0), a.count());
1137}
1138
1139fn testStaticBitSet(comptime Set: type) void {
1140 var a = Set.initEmpty();
1141 var b = Set.initFull();
1142 testing.expectEqual(@as(usize, 0), a.count());
1143 testing.expectEqual(@as(usize, Set.bit_length), b.count());
1144
1145 testBitSet(&a, &b, Set.bit_length);
1146}
1147
1148test "IntegerBitSet" {
1149 testStaticBitSet(IntegerBitSet(0));
1150 testStaticBitSet(IntegerBitSet(1));
1151 testStaticBitSet(IntegerBitSet(2));
1152 testStaticBitSet(IntegerBitSet(5));
1153 testStaticBitSet(IntegerBitSet(8));
1154 testStaticBitSet(IntegerBitSet(32));
1155 testStaticBitSet(IntegerBitSet(64));
1156 testStaticBitSet(IntegerBitSet(127));
1157}
1158
1159test "ArrayBitSet" {
1160 inline for (.{ 0, 1, 2, 31, 32, 33, 63, 64, 65, 254, 500, 3000 }) |size| {
1161 testStaticBitSet(ArrayBitSet(u8, size));
1162 testStaticBitSet(ArrayBitSet(u16, size));
1163 testStaticBitSet(ArrayBitSet(u32, size));
1164 testStaticBitSet(ArrayBitSet(u64, size));
1165 testStaticBitSet(ArrayBitSet(u128, size));
1166 }
1167}
1168
1169test "DynamicBitSetUnmanaged" {
1170 const allocator = std.testing.allocator;
1171 var a = try DynamicBitSetUnmanaged.initEmpty(300, allocator);
1172 testing.expectEqual(@as(usize, 0), a.count());
1173 a.deinit(allocator);
1174
1175 a = try DynamicBitSetUnmanaged.initEmpty(0, allocator);
1176 defer a.deinit(allocator);
1177 for ([_]usize{ 1, 2, 31, 32, 33, 0, 65, 64, 63, 500, 254, 3000 }) |size| {
1178 const old_len = a.capacity();
1179
1180 var tmp = try a.clone(allocator);
1181 defer tmp.deinit(allocator);
1182 testing.expectEqual(old_len, tmp.capacity());
1183 var i: usize = 0;
1184 while (i < old_len) : (i += 1) {
1185 testing.expectEqual(a.isSet(i), tmp.isSet(i));
1186 }
1187
1188 a.toggleSet(a); // zero a
1189 tmp.toggleSet(tmp);
1190
1191 try a.resize(size, true, allocator);
1192 try tmp.resize(size, false, allocator);
1193
1194 if (size > old_len) {
1195 testing.expectEqual(size - old_len, a.count());
1196 } else {
1197 testing.expectEqual(@as(usize, 0), a.count());
1198 }
1199 testing.expectEqual(@as(usize, 0), tmp.count());
1200
1201 var b = try DynamicBitSetUnmanaged.initFull(size, allocator);
1202 defer b.deinit(allocator);
1203 testing.expectEqual(@as(usize, size), b.count());
1204
1205 testBitSet(&a, &b, size);
1206 }
1207}
1208
1209test "DynamicBitSet" {
1210 const allocator = std.testing.allocator;
1211 var a = try DynamicBitSet.initEmpty(300, allocator);
1212 testing.expectEqual(@as(usize, 0), a.count());
1213 a.deinit();
1214
1215 a = try DynamicBitSet.initEmpty(0, allocator);
1216 defer a.deinit();
1217 for ([_]usize{ 1, 2, 31, 32, 33, 0, 65, 64, 63, 500, 254, 3000 }) |size| {
1218 const old_len = a.capacity();
1219
1220 var tmp = try a.clone(allocator);
1221 defer tmp.deinit();
1222 testing.expectEqual(old_len, tmp.capacity());
1223 var i: usize = 0;
1224 while (i < old_len) : (i += 1) {
1225 testing.expectEqual(a.isSet(i), tmp.isSet(i));
1226 }
1227
1228 a.toggleSet(a); // zero a
1229 tmp.toggleSet(tmp); // zero tmp
1230
1231 try a.resize(size, true);
1232 try tmp.resize(size, false);
1233
1234 if (size > old_len) {
1235 testing.expectEqual(size - old_len, a.count());
1236 } else {
1237 testing.expectEqual(@as(usize, 0), a.count());
1238 }
1239 testing.expectEqual(@as(usize, 0), tmp.count());
1240
1241 var b = try DynamicBitSet.initFull(size, allocator);
1242 defer b.deinit();
1243 testing.expectEqual(@as(usize, size), b.count());
1244
1245 testBitSet(&a, &b, size);
1246 }
1247}
1248
1249test "StaticBitSet" {
1250 testing.expectEqual(IntegerBitSet(0), StaticBitSet(0));
1251 testing.expectEqual(IntegerBitSet(5), StaticBitSet(5));
1252 testing.expectEqual(IntegerBitSet(@bitSizeOf(usize)), StaticBitSet(@bitSizeOf(usize)));
1253 testing.expectEqual(ArrayBitSet(usize, @bitSizeOf(usize) + 1), StaticBitSet(@bitSizeOf(usize) + 1));
1254 testing.expectEqual(ArrayBitSet(usize, 500), StaticBitSet(500));
1255}
lib/std/build/emit_raw.zig+3-3
...@@ -51,9 +51,9 @@ const BinaryElfOutput = struct {...@@ -51,9 +51,9 @@ const BinaryElfOutput = struct {
51 .segments = ArrayList(*BinaryElfSegment).init(allocator),51 .segments = ArrayList(*BinaryElfSegment).init(allocator),
52 .sections = ArrayList(*BinaryElfSection).init(allocator),52 .sections = ArrayList(*BinaryElfSection).init(allocator),
53 };53 };
54 const elf_hdr = try std.elf.readHeader(elf_file);54 const elf_hdr = try std.elf.Header.read(&elf_file);
5555
56 var section_headers = elf_hdr.section_header_iterator(elf_file);56 var section_headers = elf_hdr.section_header_iterator(&elf_file);
57 while (try section_headers.next()) |section| {57 while (try section_headers.next()) |section| {
58 if (sectionValidForOutput(section)) {58 if (sectionValidForOutput(section)) {
59 const newSection = try allocator.create(BinaryElfSection);59 const newSection = try allocator.create(BinaryElfSection);
...@@ -67,7 +67,7 @@ const BinaryElfOutput = struct {...@@ -67,7 +67,7 @@ const BinaryElfOutput = struct {
67 }67 }
68 }68 }
6969
70 var program_headers = elf_hdr.program_header_iterator(elf_file);70 var program_headers = elf_hdr.program_header_iterator(&elf_file);
71 while (try program_headers.next()) |phdr| {71 while (try program_headers.next()) |phdr| {
72 if (phdr.p_type == elf.PT_LOAD) {72 if (phdr.p_type == elf.PT_LOAD) {
73 const newSegment = try allocator.create(BinaryElfSegment);73 const newSegment = try allocator.create(BinaryElfSegment);
lib/std/c/tokenizer.zig+30-2
...@@ -401,7 +401,9 @@ pub const Tokenizer = struct {...@@ -401,7 +401,9 @@ pub const Tokenizer = struct {
401 Zero,401 Zero,
402 IntegerLiteralOct,402 IntegerLiteralOct,
403 IntegerLiteralBinary,403 IntegerLiteralBinary,
404 IntegerLiteralBinaryFirst,
404 IntegerLiteralHex,405 IntegerLiteralHex,
406 IntegerLiteralHexFirst,
405 IntegerLiteral,407 IntegerLiteral,
406 IntegerSuffix,408 IntegerSuffix,
407 IntegerSuffixU,409 IntegerSuffixU,
...@@ -1046,10 +1048,10 @@ pub const Tokenizer = struct {...@@ -1046,10 +1048,10 @@ pub const Tokenizer = struct {
1046 state = .IntegerLiteralOct;1048 state = .IntegerLiteralOct;
1047 },1049 },
1048 'b', 'B' => {1050 'b', 'B' => {
1049 state = .IntegerLiteralBinary;1051 state = .IntegerLiteralBinaryFirst;
1050 },1052 },
1051 'x', 'X' => {1053 'x', 'X' => {
1052 state = .IntegerLiteralHex;1054 state = .IntegerLiteralHexFirst;
1053 },1055 },
1054 '.' => {1056 '.' => {
1055 state = .FloatFraction;1057 state = .FloatFraction;
...@@ -1066,6 +1068,13 @@ pub const Tokenizer = struct {...@@ -1066,6 +1068,13 @@ pub const Tokenizer = struct {
1066 self.index -= 1;1068 self.index -= 1;
1067 },1069 },
1068 },1070 },
1071 .IntegerLiteralBinaryFirst => switch (c) {
1072 '0'...'7' => state = .IntegerLiteralBinary,
1073 else => {
1074 result.id = .Invalid;
1075 break;
1076 },
1077 },
1069 .IntegerLiteralBinary => switch (c) {1078 .IntegerLiteralBinary => switch (c) {
1070 '0', '1' => {},1079 '0', '1' => {},
1071 else => {1080 else => {
...@@ -1073,6 +1082,19 @@ pub const Tokenizer = struct {...@@ -1073,6 +1082,19 @@ pub const Tokenizer = struct {
1073 self.index -= 1;1082 self.index -= 1;
1074 },1083 },
1075 },1084 },
1085 .IntegerLiteralHexFirst => switch (c) {
1086 '0'...'9', 'a'...'f', 'A'...'F' => state = .IntegerLiteralHex,
1087 '.' => {
1088 state = .FloatFractionHex;
1089 },
1090 'p', 'P' => {
1091 state = .FloatExponent;
1092 },
1093 else => {
1094 result.id = .Invalid;
1095 break;
1096 },
1097 },
1076 .IntegerLiteralHex => switch (c) {1098 .IntegerLiteralHex => switch (c) {
1077 '0'...'9', 'a'...'f', 'A'...'F' => {},1099 '0'...'9', 'a'...'f', 'A'...'F' => {},
1078 '.' => {1100 '.' => {
...@@ -1238,6 +1260,8 @@ pub const Tokenizer = struct {...@@ -1238,6 +1260,8 @@ pub const Tokenizer = struct {
1238 .MultiLineCommentAsterisk,1260 .MultiLineCommentAsterisk,
1239 .FloatExponent,1261 .FloatExponent,
1240 .MacroString,1262 .MacroString,
1263 .IntegerLiteralBinaryFirst,
1264 .IntegerLiteralHexFirst,
1241 => result.id = .Invalid,1265 => result.id = .Invalid,
12421266
1243 .FloatExponentDigits => result.id = if (counter == 0) .Invalid else .{ .FloatLiteral = .none },1267 .FloatExponentDigits => result.id = if (counter == 0) .Invalid else .{ .FloatLiteral = .none },
...@@ -1523,6 +1547,7 @@ test "num suffixes" {...@@ -1523,6 +1547,7 @@ test "num suffixes" {
1523 \\ 1.0f 1.0L 1.0 .0 1.1547 \\ 1.0f 1.0L 1.0 .0 1.
1524 \\ 0l 0lu 0ll 0llu 01548 \\ 0l 0lu 0ll 0llu 0
1525 \\ 1u 1ul 1ull 11549 \\ 1u 1ul 1ull 1
1550 \\ 0x 0b
1526 \\1551 \\
1527 , &[_]Token.Id{1552 , &[_]Token.Id{
1528 .{ .FloatLiteral = .f },1553 .{ .FloatLiteral = .f },
...@@ -1542,6 +1567,9 @@ test "num suffixes" {...@@ -1542,6 +1567,9 @@ test "num suffixes" {
1542 .{ .IntegerLiteral = .llu },1567 .{ .IntegerLiteral = .llu },
1543 .{ .IntegerLiteral = .none },1568 .{ .IntegerLiteral = .none },
1544 .Nl,1569 .Nl,
1570 .Invalid,
1571 .Invalid,
1572 .Nl,
1545 });1573 });
1546}1574}
15471575
lib/std/crypto/25519/curve25519.zig+2-2
...@@ -115,9 +115,9 @@ test "curve25519" {...@@ -115,9 +115,9 @@ test "curve25519" {
115 const p = try Curve25519.basePoint.clampedMul(s);115 const p = try Curve25519.basePoint.clampedMul(s);
116 try p.rejectIdentity();116 try p.rejectIdentity();
117 var buf: [128]u8 = undefined;117 var buf: [128]u8 = undefined;
118 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{p.toBytes()}), "E6F2A4D1C28EE5C7AD0329268255A468AD407D2672824C0C0EB30EA6EF450145");118 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&p.toBytes())}), "E6F2A4D1C28EE5C7AD0329268255A468AD407D2672824C0C0EB30EA6EF450145");
119 const q = try p.clampedMul(s);119 const q = try p.clampedMul(s);
120 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{q.toBytes()}), "3614E119FFE55EC55B87D6B19971A9F4CBC78EFE80BEC55B96392BABCC712537");120 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&q.toBytes())}), "3614E119FFE55EC55B87D6B19971A9F4CBC78EFE80BEC55B96392BABCC712537");
121121
122 try Curve25519.rejectNonCanonical(s);122 try Curve25519.rejectNonCanonical(s);
123 s[31] |= 0x80;123 s[31] |= 0x80;
lib/std/crypto/25519/ed25519.zig+3-3
...@@ -210,8 +210,8 @@ test "ed25519 key pair creation" {...@@ -210,8 +210,8 @@ test "ed25519 key pair creation" {
210 _ = try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");210 _ = try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
211 const key_pair = try Ed25519.KeyPair.create(seed);211 const key_pair = try Ed25519.KeyPair.create(seed);
212 var buf: [256]u8 = undefined;212 var buf: [256]u8 = undefined;
213 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{key_pair.secret_key}), "8052030376D47112BE7F73ED7A019293DD12AD910B654455798B4667D73DE1662D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");213 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&key_pair.secret_key)}), "8052030376D47112BE7F73ED7A019293DD12AD910B654455798B4667D73DE1662D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
214 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{key_pair.public_key}), "2D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");214 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&key_pair.public_key)}), "2D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
215}215}
216216
217test "ed25519 signature" {217test "ed25519 signature" {
...@@ -221,7 +221,7 @@ test "ed25519 signature" {...@@ -221,7 +221,7 @@ test "ed25519 signature" {
221221
222 const sig = try Ed25519.sign("test", key_pair, null);222 const sig = try Ed25519.sign("test", key_pair, null);
223 var buf: [128]u8 = undefined;223 var buf: [128]u8 = undefined;
224 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{sig}), "10A442B4A80CC4225B154F43BEF28D2472CA80221951262EB8E0DF9091575E2687CC486E77263C3418C757522D54F84B0359236ABBBD4ACD20DC297FDCA66808");224 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&sig)}), "10A442B4A80CC4225B154F43BEF28D2472CA80221951262EB8E0DF9091575E2687CC486E77263C3418C757522D54F84B0359236ABBBD4ACD20DC297FDCA66808");
225 try Ed25519.verify(sig, "test", key_pair.public_key);225 try Ed25519.verify(sig, "test", key_pair.public_key);
226 std.testing.expectError(error.InvalidSignature, Ed25519.verify(sig, "TEST", key_pair.public_key));226 std.testing.expectError(error.InvalidSignature, Ed25519.verify(sig, "TEST", key_pair.public_key));
227}227}
lib/std/crypto/25519/edwards25519.zig+1-1
...@@ -450,7 +450,7 @@ test "edwards25519 packing/unpacking" {...@@ -450,7 +450,7 @@ test "edwards25519 packing/unpacking" {
450 var b = Edwards25519.basePoint;450 var b = Edwards25519.basePoint;
451 const pk = try b.mul(s);451 const pk = try b.mul(s);
452 var buf: [128]u8 = undefined;452 var buf: [128]u8 = undefined;
453 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{pk.toBytes()}), "074BC7E0FCBD587FDBC0969444245FADC562809C8F6E97E949AF62484B5B81A6");453 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&pk.toBytes())}), "074BC7E0FCBD587FDBC0969444245FADC562809C8F6E97E949AF62484B5B81A6");
454454
455 const small_order_ss: [7][32]u8 = .{455 const small_order_ss: [7][32]u8 = .{
456 .{456 .{
lib/std/crypto/25519/ristretto255.zig+4-4
...@@ -170,21 +170,21 @@ pub const Ristretto255 = struct {...@@ -170,21 +170,21 @@ pub const Ristretto255 = struct {
170test "ristretto255" {170test "ristretto255" {
171 const p = Ristretto255.basePoint;171 const p = Ristretto255.basePoint;
172 var buf: [256]u8 = undefined;172 var buf: [256]u8 = undefined;
173 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{p.toBytes()}), "E2F2AE0A6ABC4E71A884A961C500515F58E30B6AA582DD8DB6A65945E08D2D76");173 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&p.toBytes())}), "E2F2AE0A6ABC4E71A884A961C500515F58E30B6AA582DD8DB6A65945E08D2D76");
174174
175 var r: [Ristretto255.encoded_length]u8 = undefined;175 var r: [Ristretto255.encoded_length]u8 = undefined;
176 _ = try fmt.hexToBytes(r[0..], "6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919");176 _ = try fmt.hexToBytes(r[0..], "6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919");
177 var q = try Ristretto255.fromBytes(r);177 var q = try Ristretto255.fromBytes(r);
178 q = q.dbl().add(p);178 q = q.dbl().add(p);
179 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{q.toBytes()}), "E882B131016B52C1D3337080187CF768423EFCCBB517BB495AB812C4160FF44E");179 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&q.toBytes())}), "E882B131016B52C1D3337080187CF768423EFCCBB517BB495AB812C4160FF44E");
180180
181 const s = [_]u8{15} ++ [_]u8{0} ** 31;181 const s = [_]u8{15} ++ [_]u8{0} ** 31;
182 const w = try p.mul(s);182 const w = try p.mul(s);
183 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{w.toBytes()}), "E0C418F7C8D9C4CDD7395B93EA124F3AD99021BB681DFC3302A9D99A2E53E64E");183 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&w.toBytes())}), "E0C418F7C8D9C4CDD7395B93EA124F3AD99021BB681DFC3302A9D99A2E53E64E");
184184
185 std.testing.expect(p.dbl().dbl().dbl().dbl().equivalent(w.add(p)));185 std.testing.expect(p.dbl().dbl().dbl().dbl().equivalent(w.add(p)));
186186
187 const h = [_]u8{69} ** 32 ++ [_]u8{42} ** 32;187 const h = [_]u8{69} ** 32 ++ [_]u8{42} ** 32;
188 const ph = Ristretto255.fromUniform(h);188 const ph = Ristretto255.fromUniform(h);
189 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{ph.toBytes()}), "DCCA54E037A4311EFBEEF413ACD21D35276518970B7A61DC88F8587B493D5E19");189 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&ph.toBytes())}), "DCCA54E037A4311EFBEEF413ACD21D35276518970B7A61DC88F8587B493D5E19");
190}190}
lib/std/crypto/25519/scalar.zig+3-3
...@@ -771,10 +771,10 @@ test "scalar25519" {...@@ -771,10 +771,10 @@ test "scalar25519" {
771 var y = x.toBytes();771 var y = x.toBytes();
772 try rejectNonCanonical(y);772 try rejectNonCanonical(y);
773 var buf: [128]u8 = undefined;773 var buf: [128]u8 = undefined;
774 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{y}), "1E979B917937F3DE71D18077F961F6CEFF01030405060708010203040506070F");774 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&y)}), "1E979B917937F3DE71D18077F961F6CEFF01030405060708010203040506070F");
775775
776 const reduced = reduce(field_size);776 const reduced = reduce(field_size);
777 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{reduced}), "0000000000000000000000000000000000000000000000000000000000000000");777 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&reduced)}), "0000000000000000000000000000000000000000000000000000000000000000");
778}778}
779779
780test "non-canonical scalar25519" {780test "non-canonical scalar25519" {
...@@ -788,5 +788,5 @@ test "mulAdd overflow check" {...@@ -788,5 +788,5 @@ test "mulAdd overflow check" {
788 const c: [32]u8 = [_]u8{0xff} ** 32;788 const c: [32]u8 = [_]u8{0xff} ** 32;
789 const x = mulAdd(a, b, c);789 const x = mulAdd(a, b, c);
790 var buf: [128]u8 = undefined;790 var buf: [128]u8 = undefined;
791 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{x}), "D14DF91389432C25AD60FF9791B9FD1D67BEF517D273ECCE3D9A307C1B419903");791 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&x)}), "D14DF91389432C25AD60FF9791B9FD1D67BEF517D273ECCE3D9A307C1B419903");
792}792}
lib/std/crypto/chacha20.zig+2-2
...@@ -876,7 +876,7 @@ test "crypto.xchacha20" {...@@ -876,7 +876,7 @@ test "crypto.xchacha20" {
876 var ciphertext: [input.len]u8 = undefined;876 var ciphertext: [input.len]u8 = undefined;
877 XChaCha20IETF.xor(ciphertext[0..], input[0..], 0, key, nonce);877 XChaCha20IETF.xor(ciphertext[0..], input[0..], 0, key, nonce);
878 var buf: [2 * ciphertext.len]u8 = undefined;878 var buf: [2 * ciphertext.len]u8 = undefined;
879 testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{ciphertext}), "E0A1BCF939654AFDBDC1746EC49832647C19D891F0D1A81FC0C1703B4514BDEA584B512F6908C2C5E9DD18D5CBC1805DE5803FE3B9CA5F193FB8359E91FAB0C3BB40309A292EB1CF49685C65C4A3ADF4F11DB0CD2B6B67FBC174BC2E860E8F769FD3565BBFAD1C845E05A0FED9BE167C240D");879 testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&ciphertext)}), "E0A1BCF939654AFDBDC1746EC49832647C19D891F0D1A81FC0C1703B4514BDEA584B512F6908C2C5E9DD18D5CBC1805DE5803FE3B9CA5F193FB8359E91FAB0C3BB40309A292EB1CF49685C65C4A3ADF4F11DB0CD2B6B67FBC174BC2E860E8F769FD3565BBFAD1C845E05A0FED9BE167C240D");
880 }880 }
881 {881 {
882 const data = "Additional data";882 const data = "Additional data";
...@@ -885,7 +885,7 @@ test "crypto.xchacha20" {...@@ -885,7 +885,7 @@ test "crypto.xchacha20" {
885 var out: [input.len]u8 = undefined;885 var out: [input.len]u8 = undefined;
886 try xchacha20poly1305Open(out[0..], ciphertext[0..], data, key, nonce);886 try xchacha20poly1305Open(out[0..], ciphertext[0..], data, key, nonce);
887 var buf: [2 * ciphertext.len]u8 = undefined;887 var buf: [2 * ciphertext.len]u8 = undefined;
888 testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{ciphertext}), "994D2DD32333F48E53650C02C7A2ABB8E018B0836D7175AEC779F52E961780768F815C58F1AA52D211498DB89B9216763F569C9433A6BBFCEFB4D4A49387A4C5207FBB3B5A92B5941294DF30588C6740D39DC16FA1F0E634F7246CF7CDCB978E44347D89381B7A74EB7084F754B90BDE9AAF5A94B8F2A85EFD0B50692AE2D425E234");888 testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&ciphertext)}), "994D2DD32333F48E53650C02C7A2ABB8E018B0836D7175AEC779F52E961780768F815C58F1AA52D211498DB89B9216763F569C9433A6BBFCEFB4D4A49387A4C5207FBB3B5A92B5941294DF30588C6740D39DC16FA1F0E634F7246CF7CDCB978E44347D89381B7A74EB7084F754B90BDE9AAF5A94B8F2A85EFD0B50692AE2D425E234");
889 testing.expectEqualSlices(u8, out[0..], input);889 testing.expectEqualSlices(u8, out[0..], input);
890 ciphertext[0] += 1;890 ciphertext[0] += 1;
891 testing.expectError(error.AuthenticationFailed, xchacha20poly1305Open(out[0..], ciphertext[0..], data, key, nonce));891 testing.expectError(error.AuthenticationFailed, xchacha20poly1305Open(out[0..], ciphertext[0..], data, key, nonce));
lib/std/debug.zig+17-3
...@@ -360,14 +360,24 @@ pub const StackIterator = struct {...@@ -360,14 +360,24 @@ pub const StackIterator = struct {
360 };360 };
361 }361 }
362362
363 // Negative offset of the saved BP wrt the frame pointer.363 // Offset of the saved BP wrt the frame pointer.
364 const fp_offset = if (builtin.arch.isRISCV())364 const fp_offset = if (builtin.arch.isRISCV())
365 // On RISC-V the frame pointer points to the top of the saved register365 // On RISC-V the frame pointer points to the top of the saved register
366 // area, on pretty much every other architecture it points to the stack366 // area, on pretty much every other architecture it points to the stack
367 // slot where the previous frame pointer is saved.367 // slot where the previous frame pointer is saved.
368 2 * @sizeOf(usize)368 2 * @sizeOf(usize)
369 else if (builtin.arch.isSPARC())
370 // On SPARC the previous frame pointer is stored at 14 slots past %fp+BIAS.
371 14 * @sizeOf(usize)
369 else372 else
370 0;373 0;
374
375 const fp_bias = if (builtin.arch.isSPARC())
376 // On SPARC frame pointers are biased by a constant.
377 2047
378 else
379 0;
380
371 // Positive offset of the saved PC wrt the frame pointer.381 // Positive offset of the saved PC wrt the frame pointer.
372 const pc_offset = if (builtin.arch == .powerpc64le)382 const pc_offset = if (builtin.arch == .powerpc64le)
373 2 * @sizeOf(usize)383 2 * @sizeOf(usize)
...@@ -388,13 +398,17 @@ pub const StackIterator = struct {...@@ -388,13 +398,17 @@ pub const StackIterator = struct {
388 }398 }
389399
390 fn next_internal(self: *StackIterator) ?usize {400 fn next_internal(self: *StackIterator) ?usize {
391 const fp = math.sub(usize, self.fp, fp_offset) catch return null;401 const fp = if (builtin.arch.isSPARC())
402 // On SPARC the offset is positive. (!)
403 math.add(usize, self.fp, fp_offset) catch return null
404 else
405 math.sub(usize, self.fp, fp_offset) catch return null;
392406
393 // Sanity check.407 // Sanity check.
394 if (fp == 0 or !mem.isAligned(fp, @alignOf(usize)))408 if (fp == 0 or !mem.isAligned(fp, @alignOf(usize)))
395 return null;409 return null;
396410
397 const new_fp = @intToPtr(*const usize, fp).*;411 const new_fp = math.add(usize, @intToPtr(*const usize, fp).*, fp_bias) catch return null;
398412
399 // Sanity check: the stack grows down thus all the parent frames must be413 // Sanity check: the stack grows down thus all the parent frames must be
400 // be at addresses that are greater (or equal) than the previous one.414 // be at addresses that are greater (or equal) than the previous one.
lib/std/elf.zig+173-182
...@@ -335,7 +335,7 @@ pub const ET = extern enum(u16) {...@@ -335,7 +335,7 @@ pub const ET = extern enum(u16) {
335};335};
336336
337/// All integers are native endian.337/// All integers are native endian.
338const Header = struct {338pub const Header = struct {
339 endian: builtin.Endian,339 endian: builtin.Endian,
340 is_64: bool,340 is_64: bool,
341 entry: u64,341 entry: u64,
...@@ -347,187 +347,200 @@ const Header = struct {...@@ -347,187 +347,200 @@ const Header = struct {
347 shnum: u16,347 shnum: u16,
348 shstrndx: u16,348 shstrndx: u16,
349349
350 pub fn program_header_iterator(self: Header, file: File) ProgramHeaderIterator {350 pub fn program_header_iterator(self: Header, parse_source: anytype) ProgramHeaderIterator(@TypeOf(parse_source)) {
351 return .{351 return ProgramHeaderIterator(@TypeOf(parse_source)){
352 .elf_header = self,352 .elf_header = self,
353 .file = file,353 .parse_source = parse_source,
354 };354 };
355 }355 }
356356
357 pub fn section_header_iterator(self: Header, file: File) SectionHeaderIterator {357 pub fn section_header_iterator(self: Header, parse_source: anytype) SectionHeaderIterator(@TypeOf(parse_source)) {
358 return .{358 return SectionHeaderIterator(@TypeOf(parse_source)){
359 .elf_header = self,359 .elf_header = self,
360 .file = file,360 .parse_source = parse_source,
361 };361 };
362 }362 }
363};
364363
365pub fn readHeader(file: File) !Header {364 pub fn read(parse_source: anytype) !Header {
366 var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined;365 var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined;
367 try preadNoEof(file, &hdr_buf, 0);366 try parse_source.seekableStream().seekTo(0);
368 const hdr32 = @ptrCast(*Elf32_Ehdr, &hdr_buf);367 try parse_source.reader().readNoEof(&hdr_buf);
369 const hdr64 = @ptrCast(*Elf64_Ehdr, &hdr_buf);368 return Header.parse(&hdr_buf);
370 if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;369 }
371 if (hdr32.e_ident[EI_VERSION] != 1) return error.InvalidElfVersion;
372
373 const endian: std.builtin.Endian = switch (hdr32.e_ident[EI_DATA]) {
374 ELFDATA2LSB => .Little,
375 ELFDATA2MSB => .Big,
376 else => return error.InvalidElfEndian,
377 };
378 const need_bswap = endian != std.builtin.endian;
379370
380 const is_64 = switch (hdr32.e_ident[EI_CLASS]) {371 pub fn parse(hdr_buf: *align(@alignOf(Elf64_Ehdr)) const [@sizeOf(Elf64_Ehdr)]u8) !Header {
381 ELFCLASS32 => false,372 const hdr32 = @ptrCast(*const Elf32_Ehdr, hdr_buf);
382 ELFCLASS64 => true,373 const hdr64 = @ptrCast(*const Elf64_Ehdr, hdr_buf);
383 else => return error.InvalidElfClass,374 if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
384 };375 if (hdr32.e_ident[EI_VERSION] != 1) return error.InvalidElfVersion;
385376
386 return @as(Header, .{377 const endian: std.builtin.Endian = switch (hdr32.e_ident[EI_DATA]) {
387 .endian = endian,378 ELFDATA2LSB => .Little,
388 .is_64 = is_64,379 ELFDATA2MSB => .Big,
389 .entry = int(is_64, need_bswap, hdr32.e_entry, hdr64.e_entry),380 else => return error.InvalidElfEndian,
390 .phoff = int(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff),381 };
391 .shoff = int(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff),382 const need_bswap = endian != std.builtin.endian;
392 .phentsize = int(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize),
393 .phnum = int(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum),
394 .shentsize = int(is_64, need_bswap, hdr32.e_shentsize, hdr64.e_shentsize),
395 .shnum = int(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum),
396 .shstrndx = int(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx),
397 });
398}
399383
400pub const ProgramHeaderIterator = struct {384 const is_64 = switch (hdr32.e_ident[EI_CLASS]) {
401 elf_header: Header,385 ELFCLASS32 => false,
402 file: File,386 ELFCLASS64 => true,
403 index: usize = 0,387 else => return error.InvalidElfClass,
388 };
404389
405 pub fn next(self: *ProgramHeaderIterator) !?Elf64_Phdr {390 return @as(Header, .{
406 if (self.index >= self.elf_header.phnum) return null;391 .endian = endian,
407 defer self.index += 1;392 .is_64 = is_64,
393 .entry = int(is_64, need_bswap, hdr32.e_entry, hdr64.e_entry),
394 .phoff = int(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff),
395 .shoff = int(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff),
396 .phentsize = int(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize),
397 .phnum = int(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum),
398 .shentsize = int(is_64, need_bswap, hdr32.e_shentsize, hdr64.e_shentsize),
399 .shnum = int(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum),
400 .shstrndx = int(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx),
401 });
402 }
403};
408404
409 if (self.elf_header.is_64) {405pub fn ProgramHeaderIterator(ParseSource: anytype) type {
410 var phdr: Elf64_Phdr = undefined;406 return struct {
407 elf_header: Header,
408 parse_source: ParseSource,
409 index: usize = 0,
410
411 pub fn next(self: *@This()) !?Elf64_Phdr {
412 if (self.index >= self.elf_header.phnum) return null;
413 defer self.index += 1;
414
415 if (self.elf_header.is_64) {
416 var phdr: Elf64_Phdr = undefined;
417 const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index;
418 try self.parse_source.seekableStream().seekTo(offset);
419 try self.parse_source.reader().readNoEof(mem.asBytes(&phdr));
420
421 // ELF endianness matches native endianness.
422 if (self.elf_header.endian == std.builtin.endian) return phdr;
423
424 // Convert fields to native endianness.
425 return Elf64_Phdr{
426 .p_type = @byteSwap(@TypeOf(phdr.p_type), phdr.p_type),
427 .p_offset = @byteSwap(@TypeOf(phdr.p_offset), phdr.p_offset),
428 .p_vaddr = @byteSwap(@TypeOf(phdr.p_vaddr), phdr.p_vaddr),
429 .p_paddr = @byteSwap(@TypeOf(phdr.p_paddr), phdr.p_paddr),
430 .p_filesz = @byteSwap(@TypeOf(phdr.p_filesz), phdr.p_filesz),
431 .p_memsz = @byteSwap(@TypeOf(phdr.p_memsz), phdr.p_memsz),
432 .p_flags = @byteSwap(@TypeOf(phdr.p_flags), phdr.p_flags),
433 .p_align = @byteSwap(@TypeOf(phdr.p_align), phdr.p_align),
434 };
435 }
436
437 var phdr: Elf32_Phdr = undefined;
411 const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index;438 const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index;
412 try preadNoEof(self.file, mem.asBytes(&phdr), offset);439 try self.parse_source.seekableStream().seekTo(offset);
413440 try self.parse_source.reader().readNoEof(mem.asBytes(&phdr));
414 // ELF endianness matches native endianness.441
415 if (self.elf_header.endian == std.builtin.endian) return phdr;442 // ELF endianness does NOT match native endianness.
416443 if (self.elf_header.endian != std.builtin.endian) {
417 // Convert fields to native endianness.444 // Convert fields to native endianness.
445 phdr = .{
446 .p_type = @byteSwap(@TypeOf(phdr.p_type), phdr.p_type),
447 .p_offset = @byteSwap(@TypeOf(phdr.p_offset), phdr.p_offset),
448 .p_vaddr = @byteSwap(@TypeOf(phdr.p_vaddr), phdr.p_vaddr),
449 .p_paddr = @byteSwap(@TypeOf(phdr.p_paddr), phdr.p_paddr),
450 .p_filesz = @byteSwap(@TypeOf(phdr.p_filesz), phdr.p_filesz),
451 .p_memsz = @byteSwap(@TypeOf(phdr.p_memsz), phdr.p_memsz),
452 .p_flags = @byteSwap(@TypeOf(phdr.p_flags), phdr.p_flags),
453 .p_align = @byteSwap(@TypeOf(phdr.p_align), phdr.p_align),
454 };
455 }
456
457 // Convert 32-bit header to 64-bit.
418 return Elf64_Phdr{458 return Elf64_Phdr{
419 .p_type = @byteSwap(@TypeOf(phdr.p_type), phdr.p_type),459 .p_type = phdr.p_type,
420 .p_offset = @byteSwap(@TypeOf(phdr.p_offset), phdr.p_offset),460 .p_offset = phdr.p_offset,
421 .p_vaddr = @byteSwap(@TypeOf(phdr.p_vaddr), phdr.p_vaddr),461 .p_vaddr = phdr.p_vaddr,
422 .p_paddr = @byteSwap(@TypeOf(phdr.p_paddr), phdr.p_paddr),462 .p_paddr = phdr.p_paddr,
423 .p_filesz = @byteSwap(@TypeOf(phdr.p_filesz), phdr.p_filesz),463 .p_filesz = phdr.p_filesz,
424 .p_memsz = @byteSwap(@TypeOf(phdr.p_memsz), phdr.p_memsz),464 .p_memsz = phdr.p_memsz,
425 .p_flags = @byteSwap(@TypeOf(phdr.p_flags), phdr.p_flags),465 .p_flags = phdr.p_flags,
426 .p_align = @byteSwap(@TypeOf(phdr.p_align), phdr.p_align),466 .p_align = phdr.p_align,
427 };467 };
428 }468 }
469 };
470}
429471
430 var phdr: Elf32_Phdr = undefined;472pub fn SectionHeaderIterator(ParseSource: anytype) type {
431 const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index;473 return struct {
432 try preadNoEof(self.file, mem.asBytes(&phdr), offset);474 elf_header: Header,
433475 parse_source: ParseSource,
434 // ELF endianness does NOT match native endianness.476 index: usize = 0,
435 if (self.elf_header.endian != std.builtin.endian) {477
436 // Convert fields to native endianness.478 pub fn next(self: *@This()) !?Elf64_Shdr {
437 phdr = .{479 if (self.index >= self.elf_header.shnum) return null;
438 .p_type = @byteSwap(@TypeOf(phdr.p_type), phdr.p_type),480 defer self.index += 1;
439 .p_offset = @byteSwap(@TypeOf(phdr.p_offset), phdr.p_offset),481
440 .p_vaddr = @byteSwap(@TypeOf(phdr.p_vaddr), phdr.p_vaddr),482 if (self.elf_header.is_64) {
441 .p_paddr = @byteSwap(@TypeOf(phdr.p_paddr), phdr.p_paddr),483 var shdr: Elf64_Shdr = undefined;
442 .p_filesz = @byteSwap(@TypeOf(phdr.p_filesz), phdr.p_filesz),484 const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index;
443 .p_memsz = @byteSwap(@TypeOf(phdr.p_memsz), phdr.p_memsz),485 try self.parse_source.seekableStream().seekTo(offset);
444 .p_flags = @byteSwap(@TypeOf(phdr.p_flags), phdr.p_flags),486 try self.parse_source.reader().readNoEof(mem.asBytes(&shdr));
445 .p_align = @byteSwap(@TypeOf(phdr.p_align), phdr.p_align),487
446 };488 // ELF endianness matches native endianness.
447 }489 if (self.elf_header.endian == std.builtin.endian) return shdr;
448490
449 // Convert 32-bit header to 64-bit.491 // Convert fields to native endianness.
450 return Elf64_Phdr{492 return Elf64_Shdr{
451 .p_type = phdr.p_type,493 .sh_name = @byteSwap(@TypeOf(shdr.sh_name), shdr.sh_name),
452 .p_offset = phdr.p_offset,494 .sh_type = @byteSwap(@TypeOf(shdr.sh_type), shdr.sh_type),
453 .p_vaddr = phdr.p_vaddr,495 .sh_flags = @byteSwap(@TypeOf(shdr.sh_flags), shdr.sh_flags),
454 .p_paddr = phdr.p_paddr,496 .sh_addr = @byteSwap(@TypeOf(shdr.sh_addr), shdr.sh_addr),
455 .p_filesz = phdr.p_filesz,497 .sh_offset = @byteSwap(@TypeOf(shdr.sh_offset), shdr.sh_offset),
456 .p_memsz = phdr.p_memsz,498 .sh_size = @byteSwap(@TypeOf(shdr.sh_size), shdr.sh_size),
457 .p_flags = phdr.p_flags,499 .sh_link = @byteSwap(@TypeOf(shdr.sh_link), shdr.sh_link),
458 .p_align = phdr.p_align,500 .sh_info = @byteSwap(@TypeOf(shdr.sh_info), shdr.sh_info),
459 };501 .sh_addralign = @byteSwap(@TypeOf(shdr.sh_addralign), shdr.sh_addralign),
460 }502 .sh_entsize = @byteSwap(@TypeOf(shdr.sh_entsize), shdr.sh_entsize),
461};503 };
462504 }
463pub const SectionHeaderIterator = struct {505
464 elf_header: Header,506 var shdr: Elf32_Shdr = undefined;
465 file: File,
466 index: usize = 0,
467
468 pub fn next(self: *SectionHeaderIterator) !?Elf64_Shdr {
469 if (self.index >= self.elf_header.shnum) return null;
470 defer self.index += 1;
471
472 if (self.elf_header.is_64) {
473 var shdr: Elf64_Shdr = undefined;
474 const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index;507 const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index;
475 try preadNoEof(self.file, mem.asBytes(&shdr), offset);508 try self.parse_source.seekableStream().seekTo(offset);
476509 try self.parse_source.reader().readNoEof(mem.asBytes(&shdr));
477 // ELF endianness matches native endianness.510
478 if (self.elf_header.endian == std.builtin.endian) return shdr;511 // ELF endianness does NOT match native endianness.
479512 if (self.elf_header.endian != std.builtin.endian) {
480 // Convert fields to native endianness.513 // Convert fields to native endianness.
514 shdr = .{
515 .sh_name = @byteSwap(@TypeOf(shdr.sh_name), shdr.sh_name),
516 .sh_type = @byteSwap(@TypeOf(shdr.sh_type), shdr.sh_type),
517 .sh_flags = @byteSwap(@TypeOf(shdr.sh_flags), shdr.sh_flags),
518 .sh_addr = @byteSwap(@TypeOf(shdr.sh_addr), shdr.sh_addr),
519 .sh_offset = @byteSwap(@TypeOf(shdr.sh_offset), shdr.sh_offset),
520 .sh_size = @byteSwap(@TypeOf(shdr.sh_size), shdr.sh_size),
521 .sh_link = @byteSwap(@TypeOf(shdr.sh_link), shdr.sh_link),
522 .sh_info = @byteSwap(@TypeOf(shdr.sh_info), shdr.sh_info),
523 .sh_addralign = @byteSwap(@TypeOf(shdr.sh_addralign), shdr.sh_addralign),
524 .sh_entsize = @byteSwap(@TypeOf(shdr.sh_entsize), shdr.sh_entsize),
525 };
526 }
527
528 // Convert 32-bit header to 64-bit.
481 return Elf64_Shdr{529 return Elf64_Shdr{
482 .sh_name = @byteSwap(@TypeOf(shdr.sh_name), shdr.sh_name),530 .sh_name = shdr.sh_name,
483 .sh_type = @byteSwap(@TypeOf(shdr.sh_type), shdr.sh_type),531 .sh_type = shdr.sh_type,
484 .sh_flags = @byteSwap(@TypeOf(shdr.sh_flags), shdr.sh_flags),532 .sh_flags = shdr.sh_flags,
485 .sh_addr = @byteSwap(@TypeOf(shdr.sh_addr), shdr.sh_addr),533 .sh_addr = shdr.sh_addr,
486 .sh_offset = @byteSwap(@TypeOf(shdr.sh_offset), shdr.sh_offset),534 .sh_offset = shdr.sh_offset,
487 .sh_size = @byteSwap(@TypeOf(shdr.sh_size), shdr.sh_size),535 .sh_size = shdr.sh_size,
488 .sh_link = @byteSwap(@TypeOf(shdr.sh_link), shdr.sh_link),536 .sh_link = shdr.sh_link,
489 .sh_info = @byteSwap(@TypeOf(shdr.sh_info), shdr.sh_info),537 .sh_info = shdr.sh_info,
490 .sh_addralign = @byteSwap(@TypeOf(shdr.sh_addralign), shdr.sh_addralign),538 .sh_addralign = shdr.sh_addralign,
491 .sh_entsize = @byteSwap(@TypeOf(shdr.sh_entsize), shdr.sh_entsize),539 .sh_entsize = shdr.sh_entsize,
492 };540 };
493 }541 }
494542 };
495 var shdr: Elf32_Shdr = undefined;543}
496 const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index;
497 try preadNoEof(self.file, mem.asBytes(&shdr), offset);
498
499 // ELF endianness does NOT match native endianness.
500 if (self.elf_header.endian != std.builtin.endian) {
501 // Convert fields to native endianness.
502 shdr = .{
503 .sh_name = @byteSwap(@TypeOf(shdr.sh_name), shdr.sh_name),
504 .sh_type = @byteSwap(@TypeOf(shdr.sh_type), shdr.sh_type),
505 .sh_flags = @byteSwap(@TypeOf(shdr.sh_flags), shdr.sh_flags),
506 .sh_addr = @byteSwap(@TypeOf(shdr.sh_addr), shdr.sh_addr),
507 .sh_offset = @byteSwap(@TypeOf(shdr.sh_offset), shdr.sh_offset),
508 .sh_size = @byteSwap(@TypeOf(shdr.sh_size), shdr.sh_size),
509 .sh_link = @byteSwap(@TypeOf(shdr.sh_link), shdr.sh_link),
510 .sh_info = @byteSwap(@TypeOf(shdr.sh_info), shdr.sh_info),
511 .sh_addralign = @byteSwap(@TypeOf(shdr.sh_addralign), shdr.sh_addralign),
512 .sh_entsize = @byteSwap(@TypeOf(shdr.sh_entsize), shdr.sh_entsize),
513 };
514 }
515
516 // Convert 32-bit header to 64-bit.
517 return Elf64_Shdr{
518 .sh_name = shdr.sh_name,
519 .sh_type = shdr.sh_type,
520 .sh_flags = shdr.sh_flags,
521 .sh_addr = shdr.sh_addr,
522 .sh_offset = shdr.sh_offset,
523 .sh_size = shdr.sh_size,
524 .sh_link = shdr.sh_link,
525 .sh_info = shdr.sh_info,
526 .sh_addralign = shdr.sh_addralign,
527 .sh_entsize = shdr.sh_entsize,
528 };
529 }
530};
531544
532pub fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) {545pub fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) {
533 if (is_64) {546 if (is_64) {
...@@ -549,28 +562,6 @@ pub fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 {...@@ -549,28 +562,6 @@ pub fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 {
549 }562 }
550}563}
551564
552fn preadNoEof(file: std.fs.File, buf: []u8, offset: u64) !void {
553 var i: usize = 0;
554 while (i < buf.len) {
555 const len = file.pread(buf[i .. buf.len - i], offset + i) catch |err| switch (err) {
556 error.SystemResources => return error.SystemResources,
557 error.IsDir => return error.UnableToReadElfFile,
558 error.OperationAborted => return error.UnableToReadElfFile,
559 error.BrokenPipe => return error.UnableToReadElfFile,
560 error.Unseekable => return error.UnableToReadElfFile,
561 error.ConnectionResetByPeer => return error.UnableToReadElfFile,
562 error.ConnectionTimedOut => return error.UnableToReadElfFile,
563 error.InputOutput => return error.FileSystem,
564 error.Unexpected => return error.Unexpected,
565 error.WouldBlock => return error.Unexpected,
566 error.NotOpenForReading => return error.Unexpected,
567 error.AccessDenied => return error.Unexpected,
568 };
569 if (len == 0) return error.UnexpectedEndOfFile;
570 i += len;
571 }
572}
573
574pub const EI_NIDENT = 16;565pub const EI_NIDENT = 16;
575566
576pub const EI_CLASS = 4;567pub const EI_CLASS = 4;
lib/std/fmt.zig+104-26
...@@ -709,6 +709,87 @@ fn formatFloatValue(...@@ -709,6 +709,87 @@ fn formatFloatValue(
709 return formatBuf(buf_stream.getWritten(), options, writer);709 return formatBuf(buf_stream.getWritten(), options, writer);
710}710}
711711
712fn formatSliceHexImpl(comptime uppercase: bool) type {
713 const charset = "0123456789" ++ if (uppercase) "ABCDEF" else "abcdef";
714
715 return struct {
716 pub fn f(
717 bytes: []const u8,
718 comptime fmt: []const u8,
719 options: std.fmt.FormatOptions,
720 writer: anytype,
721 ) !void {
722 var buf: [2]u8 = undefined;
723
724 for (bytes) |c| {
725 buf[0] = charset[c >> 4];
726 buf[1] = charset[c & 15];
727 try writer.writeAll(&buf);
728 }
729 }
730 };
731}
732
733const formatSliceHexLower = formatSliceHexImpl(false).f;
734const formatSliceHexUpper = formatSliceHexImpl(true).f;
735
736/// Return a Formatter for a []const u8 where every byte is formatted as a pair
737/// of lowercase hexadecimal digits.
738pub fn fmtSliceHexLower(bytes: []const u8) std.fmt.Formatter(formatSliceHexLower) {
739 return .{ .data = bytes };
740}
741
742/// Return a Formatter for a []const u8 where every byte is formatted as a pair
743/// of uppercase hexadecimal digits.
744pub fn fmtSliceHexUpper(bytes: []const u8) std.fmt.Formatter(formatSliceHexUpper) {
745 return .{ .data = bytes };
746}
747
748fn formatSliceEscapeImpl(comptime uppercase: bool) type {
749 const charset = "0123456789" ++ if (uppercase) "ABCDEF" else "abcdef";
750
751 return struct {
752 pub fn f(
753 bytes: []const u8,
754 comptime fmt: []const u8,
755 options: std.fmt.FormatOptions,
756 writer: anytype,
757 ) !void {
758 var buf: [4]u8 = undefined;
759
760 buf[0] = '\\';
761 buf[1] = 'x';
762
763 for (bytes) |c| {
764 if (std.ascii.isPrint(c)) {
765 try writer.writeByte(c);
766 } else {
767 buf[2] = charset[c >> 4];
768 buf[3] = charset[c & 15];
769 try writer.writeAll(&buf);
770 }
771 }
772 }
773 };
774}
775
776const formatSliceEscapeLower = formatSliceEscapeImpl(false).f;
777const formatSliceEscapeUpper = formatSliceEscapeImpl(true).f;
778
779/// Return a Formatter for a []const u8 where every non-printable ASCII
780/// character is escaped as \xNN, where NN is the character in lowercase
781/// hexadecimal notation.
782pub fn fmtSliceEscapeLower(bytes: []const u8) std.fmt.Formatter(formatSliceEscapeLower) {
783 return .{ .data = bytes };
784}
785
786/// Return a Formatter for a []const u8 where every non-printable ASCII
787/// character is escaped as \xNN, where NN is the character in uppercase
788/// hexadecimal notation.
789pub fn fmtSliceEscapeUpper(bytes: []const u8) std.fmt.Formatter(formatSliceEscapeUpper) {
790 return .{ .data = bytes };
791}
792
712pub fn formatText(793pub fn formatText(
713 bytes: []const u8,794 bytes: []const u8,
714 comptime fmt: []const u8,795 comptime fmt: []const u8,
...@@ -717,21 +798,18 @@ pub fn formatText(...@@ -717,21 +798,18 @@ pub fn formatText(
717) !void {798) !void {
718 if (comptime std.mem.eql(u8, fmt, "s")) {799 if (comptime std.mem.eql(u8, fmt, "s")) {
719 return formatBuf(bytes, options, writer);800 return formatBuf(bytes, options, writer);
720 } else if (comptime (std.mem.eql(u8, fmt, "x") or std.mem.eql(u8, fmt, "X"))) {801 } else if (comptime (std.mem.eql(u8, fmt, "x"))) {
721 for (bytes) |c| {802 @compileError("specifier 'x' has been deprecated, wrap your argument in std.fmt.fmtSliceHexLower instead");
722 try formatInt(c, 16, fmt[0] == 'X', FormatOptions{ .width = 2, .fill = '0' }, writer);803 } else if (comptime (std.mem.eql(u8, fmt, "X"))) {
723 }804 @compileError("specifier 'X' has been deprecated, wrap your argument in std.fmt.fmtSliceHexUpper instead");
724 return;805 } else if (comptime (std.mem.eql(u8, fmt, "e"))) {
725 } else if (comptime (std.mem.eql(u8, fmt, "e") or std.mem.eql(u8, fmt, "E"))) {806 @compileError("specifier 'e' has been deprecated, wrap your argument in std.fmt.fmtSliceEscapeLower instead");
726 for (bytes) |c| {807 } else if (comptime (std.mem.eql(u8, fmt, "E"))) {
727 if (std.ascii.isPrint(c)) {808 @compileError("specifier 'X' has been deprecated, wrap your argument in std.fmt.fmtSliceEscapeUpper instead");
728 try writer.writeByte(c);809 } else if (comptime std.mem.eql(u8, fmt, "z")) {
729 } else {810 @compileError("specifier 'z' has been deprecated, wrap your argument in std.zig.fmtId instead");
730 try writer.writeAll("\\x");811 } else if (comptime std.mem.eql(u8, fmt, "Z")) {
731 try formatInt(c, 16, fmt[0] == 'E', FormatOptions{ .width = 2, .fill = '0' }, writer);812 @compileError("specifier 'Z' has been deprecated, wrap your argument in std.zig.fmtEscapes instead");
732 }
733 }
734 return;
735 } else {813 } else {
736 @compileError("Unsupported format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'");814 @compileError("Unsupported format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'");
737 }815 }
...@@ -1693,9 +1771,9 @@ test "slice" {...@@ -1693,9 +1771,9 @@ test "slice" {
1693}1771}
16941772
1695test "escape non-printable" {1773test "escape non-printable" {
1696 try expectFmt("abc", "{e}", .{"abc"});1774 try expectFmt("abc", "{s}", .{fmtSliceEscapeLower("abc")});
1697 try expectFmt("ab\\xffc", "{e}", .{"ab\xffc"});1775 try expectFmt("ab\\xffc", "{s}", .{fmtSliceEscapeLower("ab\xffc")});
1698 try expectFmt("ab\\xFFc", "{E}", .{"ab\xffc"});1776 try expectFmt("ab\\xFFc", "{s}", .{fmtSliceEscapeUpper("ab\xffc")});
1699}1777}
17001778
1701test "pointer" {1779test "pointer" {
...@@ -1968,13 +2046,13 @@ test "struct.zero-size" {...@@ -1968,13 +2046,13 @@ test "struct.zero-size" {
19682046
1969test "bytes.hex" {2047test "bytes.hex" {
1970 const some_bytes = "\xCA\xFE\xBA\xBE";2048 const some_bytes = "\xCA\xFE\xBA\xBE";
1971 try expectFmt("lowercase: cafebabe\n", "lowercase: {x}\n", .{some_bytes});2049 try expectFmt("lowercase: cafebabe\n", "lowercase: {x}\n", .{fmtSliceHexLower(some_bytes)});
1972 try expectFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", .{some_bytes});2050 try expectFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", .{fmtSliceHexUpper(some_bytes)});
1973 //Test Slices2051 //Test Slices
1974 try expectFmt("uppercase: CAFE\n", "uppercase: {X}\n", .{some_bytes[0..2]});2052 try expectFmt("uppercase: CAFE\n", "uppercase: {X}\n", .{fmtSliceHexUpper(some_bytes[0..2])});
1975 try expectFmt("lowercase: babe\n", "lowercase: {x}\n", .{some_bytes[2..]});2053 try expectFmt("lowercase: babe\n", "lowercase: {x}\n", .{fmtSliceHexLower(some_bytes[2..])});
1976 const bytes_with_zeros = "\x00\x0E\xBA\xBE";2054 const bytes_with_zeros = "\x00\x0E\xBA\xBE";
1977 try expectFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", .{bytes_with_zeros});2055 try expectFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", .{fmtSliceHexLower(bytes_with_zeros)});
1978}2056}
19792057
1980pub const trim = @compileError("deprecated; use std.mem.trim with std.ascii.spaces instead");2058pub const trim = @compileError("deprecated; use std.mem.trim with std.ascii.spaces instead");
...@@ -2002,9 +2080,9 @@ pub fn hexToBytes(out: []u8, input: []const u8) ![]u8 {...@@ -2002,9 +2080,9 @@ pub fn hexToBytes(out: []u8, input: []const u8) ![]u8 {
20022080
2003test "hexToBytes" {2081test "hexToBytes" {
2004 var buf: [32]u8 = undefined;2082 var buf: [32]u8 = undefined;
2005 try expectFmt("90" ** 32, "{X}", .{try hexToBytes(&buf, "90" ** 32)});2083 try expectFmt("90" ** 32, "{s}", .{fmtSliceHexUpper(try hexToBytes(&buf, "90" ** 32))});
2006 try expectFmt("ABCD", "{X}", .{try hexToBytes(&buf, "ABCD")});2084 try expectFmt("ABCD", "{s}", .{fmtSliceHexUpper(try hexToBytes(&buf, "ABCD"))});
2007 try expectFmt("", "{X}", .{try hexToBytes(&buf, "")});2085 try expectFmt("", "{s}", .{fmtSliceHexUpper(try hexToBytes(&buf, ""))});
2008 std.testing.expectError(error.InvalidCharacter, hexToBytes(&buf, "012Z"));2086 std.testing.expectError(error.InvalidCharacter, hexToBytes(&buf, "012Z"));
2009 std.testing.expectError(error.InvalidLength, hexToBytes(&buf, "AAA"));2087 std.testing.expectError(error.InvalidLength, hexToBytes(&buf, "AAA"));
2010 std.testing.expectError(error.NoSpaceLeft, hexToBytes(buf[0..1], "ABAB"));2088 std.testing.expectError(error.NoSpaceLeft, hexToBytes(buf[0..1], "ABAB"));
lib/std/fs/get_app_data_dir.zig+1-1
...@@ -60,7 +60,7 @@ pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataD...@@ -60,7 +60,7 @@ pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataD
60 var dir_path_ptr: [*:0]u8 = undefined;60 var dir_path_ptr: [*:0]u8 = undefined;
61 // TODO look into directory_which61 // TODO look into directory_which
62 const be_user_settings = 0xbbe;62 const be_user_settings = 0xbbe;
63 const rc = os.system.find_directory(be_user_settings, -1, true, dir_path_ptr, 1) ;63 const rc = os.system.find_directory(be_user_settings, -1, true, dir_path_ptr, 1);
64 const settings_dir = try allocator.dupeZ(u8, mem.spanZ(dir_path_ptr));64 const settings_dir = try allocator.dupeZ(u8, mem.spanZ(dir_path_ptr));
65 defer allocator.free(settings_dir);65 defer allocator.free(settings_dir);
66 switch (rc) {66 switch (rc) {
lib/std/io/writer.zig+7
...@@ -4,6 +4,7 @@...@@ -4,6 +4,7 @@
4// The MIT license requires this copyright notice to be included in all copies4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.5// and substantial portions of the software.
6const std = @import("../std.zig");6const std = @import("../std.zig");
7const assert = std.debug.assert;
7const builtin = std.builtin;8const builtin = std.builtin;
8const mem = std.mem;9const mem = std.mem;
910
...@@ -86,5 +87,11 @@ pub fn Writer(...@@ -86,5 +87,11 @@ pub fn Writer(
86 mem.writeInt(T, &bytes, value, endian);87 mem.writeInt(T, &bytes, value, endian);
87 return self.writeAll(&bytes);88 return self.writeAll(&bytes);
88 }89 }
90
91 pub fn writeStruct(self: Self, value: anytype) Error!void {
92 // Only extern and packed structs have defined in-memory layout.
93 comptime assert(@typeInfo(@TypeOf(value)).Struct.layout != builtin.TypeInfo.ContainerLayout.Auto);
94 return self.writeAll(mem.asBytes(&value));
95 }
89 };96 };
90}97}
lib/std/math.zig+56
...@@ -1330,3 +1330,59 @@ test "math.comptime" {...@@ -1330,3 +1330,59 @@ test "math.comptime" {
1330 comptime const v = sin(@as(f32, 1)) + ln(@as(f32, 5));1330 comptime const v = sin(@as(f32, 1)) + ln(@as(f32, 5));
1331 testing.expect(v == sin(@as(f32, 1)) + ln(@as(f32, 5)));1331 testing.expect(v == sin(@as(f32, 1)) + ln(@as(f32, 5)));
1332}1332}
1333
1334/// Returns a mask of all ones if value is true,
1335/// and a mask of all zeroes if value is false.
1336/// Compiles to one instruction for register sized integers.
1337pub fn boolMask(comptime MaskInt: type, value: bool) callconv(.Inline) MaskInt {
1338 if (@typeInfo(MaskInt) != .Int)
1339 @compileError("boolMask requires an integer mask type.");
1340
1341 if (MaskInt == u0 or MaskInt == i0)
1342 @compileError("boolMask cannot convert to u0 or i0, they are too small.");
1343
1344 // The u1 and i1 cases tend to overflow,
1345 // so we special case them here.
1346 if (MaskInt == u1) return @boolToInt(value);
1347 if (MaskInt == i1) {
1348 // The @as here is a workaround for #7950
1349 return @bitCast(i1, @as(u1, @boolToInt(value)));
1350 }
1351
1352 // At comptime, -% is disallowed on unsigned values.
1353 // So we need to jump through some hoops in that case.
1354 // This is a workaround for #7951
1355 if (@typeInfo(@TypeOf(.{value})).Struct.fields[0].is_comptime) {
1356 // Since it's comptime, we don't need this to generate nice code.
1357 // We can just do a branch here.
1358 return if (value) ~@as(MaskInt, 0) else 0;
1359 }
1360
1361 return -%@intCast(MaskInt, @boolToInt(value));
1362}
1363
1364test "boolMask" {
1365 const runTest = struct {
1366 fn runTest() void {
1367 testing.expectEqual(@as(u1, 0), boolMask(u1, false));
1368 testing.expectEqual(@as(u1, 1), boolMask(u1, true));
1369
1370 testing.expectEqual(@as(i1, 0), boolMask(i1, false));
1371 testing.expectEqual(@as(i1, -1), boolMask(i1, true));
1372
1373 testing.expectEqual(@as(u13, 0), boolMask(u13, false));
1374 testing.expectEqual(@as(u13, 0x1FFF), boolMask(u13, true));
1375
1376 testing.expectEqual(@as(i13, 0), boolMask(i13, false));
1377 testing.expectEqual(@as(i13, -1), boolMask(i13, true));
1378
1379 testing.expectEqual(@as(u32, 0), boolMask(u32, false));
1380 testing.expectEqual(@as(u32, 0xFFFF_FFFF), boolMask(u32, true));
1381
1382 testing.expectEqual(@as(i32, 0), boolMask(i32, false));
1383 testing.expectEqual(@as(i32, -1), boolMask(i32, true));
1384 }
1385 }.runTest;
1386 runTest();
1387 comptime runTest();
1388}
lib/std/mem.zig+8
...@@ -25,6 +25,14 @@ pub const page_size = switch (builtin.arch) {...@@ -25,6 +25,14 @@ pub const page_size = switch (builtin.arch) {
25 else => 4 * 1024,25 else => 4 * 1024,
26};26};
2727
28/// The standard library currently thoroughly depends on byte size
29/// being 8 bits. (see the use of u8 throughout allocation code as
30/// the "byte" type.) Code which depends on this can reference this
31/// declaration. If we ever try to port the standard library to a
32/// non-8-bit-byte platform, this will allow us to search for things
33/// which need to be updated.
34pub const byte_size_in_bits = 8;
35
28pub const Allocator = @import("mem/Allocator.zig");36pub const Allocator = @import("mem/Allocator.zig");
2937
30/// Detects and asserts if the std.mem.Allocator interface is violated by the caller38/// Detects and asserts if the std.mem.Allocator interface is violated by the caller
lib/std/multi_array_list.zig+1-1
...@@ -136,7 +136,7 @@ pub fn MultiArrayList(comptime S: type) type {...@@ -136,7 +136,7 @@ pub fn MultiArrayList(comptime S: type) type {
136 const slices = self.slice();136 const slices = self.slice();
137 var result: S = undefined;137 var result: S = undefined;
138 inline for (fields) |field_info, i| {138 inline for (fields) |field_info, i| {
139 @field(elem, field_info.name) = slices.items(@intToEnum(Field, i))[index];139 @field(result, field_info.name) = slices.items(@intToEnum(Field, i))[index];
140 }140 }
141 return result;141 return result;
142 }142 }
lib/std/os/bits/haiku.zig+6-7
...@@ -180,8 +180,8 @@ pub const dirent = extern struct {...@@ -180,8 +180,8 @@ pub const dirent = extern struct {
180};180};
181181
182pub const image_info = extern struct {182pub const image_info = extern struct {
183 id: u32, //image_id183 id: u32,
184 type: u32, // image_type184 type: u32,
185 sequence: i32,185 sequence: i32,
186 init_order: i32,186 init_order: i32,
187 init_routine: *c_void,187 init_routine: *c_void,
...@@ -806,17 +806,16 @@ pub const Sigaction = extern struct {...@@ -806,17 +806,16 @@ pub const Sigaction = extern struct {
806806
807pub const _SIG_WORDS = 4;807pub const _SIG_WORDS = 4;
808pub const _SIG_MAXSIG = 128;808pub const _SIG_MAXSIG = 128;
809809pub fn _SIG_IDX(sig: usize) callconv(.Inline) usize {
810pub inline fn _SIG_IDX(sig: usize) usize {
811 return sig - 1;810 return sig - 1;
812}811}
813pub inline fn _SIG_WORD(sig: usize) usize {812pub fn _SIG_WORD(sig: usize) callconv(.Inline) usize {
814 return_SIG_IDX(sig) >> 5;813 return_SIG_IDX(sig) >> 5;
815}814}
816pub inline fn _SIG_BIT(sig: usize) usize {815pub fn _SIG_BIT(sig: usize) callconv(.Inline) usize {
817 return 1 << (_SIG_IDX(sig) & 31);816 return 1 << (_SIG_IDX(sig) & 31);
818}817}
819pub inline fn _SIG_VALID(sig: usize) usize {818pub fn _SIG_VALID(sig: usize) callconv(.Inline) usize {
820 return sig <= _SIG_MAXSIG and sig > 0;819 return sig <= _SIG_MAXSIG and sig > 0;
821}820}
822821
lib/std/os/bits/linux.zig+5
...@@ -2244,3 +2244,8 @@ pub const MADV_COLD = 20;...@@ -2244,3 +2244,8 @@ pub const MADV_COLD = 20;
2244pub const MADV_PAGEOUT = 21;2244pub const MADV_PAGEOUT = 21;
2245pub const MADV_HWPOISON = 100;2245pub const MADV_HWPOISON = 100;
2246pub const MADV_SOFT_OFFLINE = 101;2246pub const MADV_SOFT_OFFLINE = 101;
2247
2248pub const __kernel_timespec = extern struct {
2249 tv_sec: i64,
2250 tv_nsec: i64,
2251};
lib/std/os/linux/io_uring.zig+5-5
...@@ -526,7 +526,7 @@ pub const IO_Uring = struct {...@@ -526,7 +526,7 @@ pub const IO_Uring = struct {
526 pub fn timeout(526 pub fn timeout(
527 self: *IO_Uring,527 self: *IO_Uring,
528 user_data: u64,528 user_data: u64,
529 ts: *const os.timespec,529 ts: *const os.__kernel_timespec,
530 count: u32,530 count: u32,
531 flags: u32,531 flags: u32,
532 ) !*io_uring_sqe {532 ) !*io_uring_sqe {
...@@ -884,7 +884,7 @@ pub fn io_uring_prep_close(sqe: *io_uring_sqe, fd: os.fd_t) void {...@@ -884,7 +884,7 @@ pub fn io_uring_prep_close(sqe: *io_uring_sqe, fd: os.fd_t) void {
884884
885pub fn io_uring_prep_timeout(885pub fn io_uring_prep_timeout(
886 sqe: *io_uring_sqe,886 sqe: *io_uring_sqe,
887 ts: *const os.timespec,887 ts: *const os.__kernel_timespec,
888 count: u32,888 count: u32,
889 flags: u32,889 flags: u32,
890) void {890) void {
...@@ -1339,7 +1339,7 @@ test "timeout (after a relative time)" {...@@ -1339,7 +1339,7 @@ test "timeout (after a relative time)" {
13391339
1340 const ms = 10;1340 const ms = 10;
1341 const margin = 5;1341 const margin = 5;
1342 const ts = os.timespec{ .tv_sec = 0, .tv_nsec = ms * 1000000 };1342 const ts = os.__kernel_timespec{ .tv_sec = 0, .tv_nsec = ms * 1000000 };
13431343
1344 const started = std.time.milliTimestamp();1344 const started = std.time.milliTimestamp();
1345 const sqe = try ring.timeout(0x55555555, &ts, 0, 0);1345 const sqe = try ring.timeout(0x55555555, &ts, 0, 0);
...@@ -1366,7 +1366,7 @@ test "timeout (after a number of completions)" {...@@ -1366,7 +1366,7 @@ test "timeout (after a number of completions)" {
1366 };1366 };
1367 defer ring.deinit();1367 defer ring.deinit();
13681368
1369 const ts = os.timespec{ .tv_sec = 3, .tv_nsec = 0 };1369 const ts = os.__kernel_timespec{ .tv_sec = 3, .tv_nsec = 0 };
1370 const count_completions: u64 = 1;1370 const count_completions: u64 = 1;
1371 const sqe_timeout = try ring.timeout(0x66666666, &ts, count_completions, 0);1371 const sqe_timeout = try ring.timeout(0x66666666, &ts, count_completions, 0);
1372 testing.expectEqual(linux.IORING_OP.TIMEOUT, sqe_timeout.opcode);1372 testing.expectEqual(linux.IORING_OP.TIMEOUT, sqe_timeout.opcode);
...@@ -1399,7 +1399,7 @@ test "timeout_remove" {...@@ -1399,7 +1399,7 @@ test "timeout_remove" {
1399 };1399 };
1400 defer ring.deinit();1400 defer ring.deinit();
14011401
1402 const ts = os.timespec{ .tv_sec = 3, .tv_nsec = 0 };1402 const ts = os.__kernel_timespec{ .tv_sec = 3, .tv_nsec = 0 };
1403 const sqe_timeout = try ring.timeout(0x88888888, &ts, 0, 0);1403 const sqe_timeout = try ring.timeout(0x88888888, &ts, 0, 0);
1404 testing.expectEqual(linux.IORING_OP.TIMEOUT, sqe_timeout.opcode);1404 testing.expectEqual(linux.IORING_OP.TIMEOUT, sqe_timeout.opcode);
1405 testing.expectEqual(@as(u64, 0x88888888), sqe_timeout.user_data);1405 testing.expectEqual(@as(u64, 0x88888888), sqe_timeout.user_data);
lib/std/std.zig+4
...@@ -18,6 +18,8 @@ pub const BufSet = @import("buf_set.zig").BufSet;...@@ -18,6 +18,8 @@ pub const BufSet = @import("buf_set.zig").BufSet;
18pub const ChildProcess = @import("child_process.zig").ChildProcess;18pub const ChildProcess = @import("child_process.zig").ChildProcess;
19pub const ComptimeStringMap = @import("comptime_string_map.zig").ComptimeStringMap;19pub const ComptimeStringMap = @import("comptime_string_map.zig").ComptimeStringMap;
20pub const DynLib = @import("dynamic_library.zig").DynLib;20pub const DynLib = @import("dynamic_library.zig").DynLib;
21pub const DynamicBitSet = bit_set.DynamicBitSet;
22pub const DynamicBitSetUnmanaged = bit_set.DynamicBitSetUnmanaged;
21pub const HashMap = hash_map.HashMap;23pub const HashMap = hash_map.HashMap;
22pub const HashMapUnmanaged = hash_map.HashMapUnmanaged;24pub const HashMapUnmanaged = hash_map.HashMapUnmanaged;
23pub const MultiArrayList = @import("multi_array_list.zig").MultiArrayList;25pub const MultiArrayList = @import("multi_array_list.zig").MultiArrayList;
...@@ -29,6 +31,7 @@ pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;...@@ -29,6 +31,7 @@ pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;
29pub const Progress = @import("Progress.zig");31pub const Progress = @import("Progress.zig");
30pub const SemanticVersion = @import("SemanticVersion.zig");32pub const SemanticVersion = @import("SemanticVersion.zig");
31pub const SinglyLinkedList = @import("linked_list.zig").SinglyLinkedList;33pub const SinglyLinkedList = @import("linked_list.zig").SinglyLinkedList;
34pub const StaticBitSet = bit_set.StaticBitSet;
32pub const StringHashMap = hash_map.StringHashMap;35pub const StringHashMap = hash_map.StringHashMap;
33pub const StringHashMapUnmanaged = hash_map.StringHashMapUnmanaged;36pub const StringHashMapUnmanaged = hash_map.StringHashMapUnmanaged;
34pub const StringArrayHashMap = array_hash_map.StringArrayHashMap;37pub const StringArrayHashMap = array_hash_map.StringArrayHashMap;
...@@ -40,6 +43,7 @@ pub const Thread = @import("Thread.zig");...@@ -40,6 +43,7 @@ pub const Thread = @import("Thread.zig");
40pub const array_hash_map = @import("array_hash_map.zig");43pub const array_hash_map = @import("array_hash_map.zig");
41pub const atomic = @import("atomic.zig");44pub const atomic = @import("atomic.zig");
42pub const base64 = @import("base64.zig");45pub const base64 = @import("base64.zig");
46pub const bit_set = @import("bit_set.zig");
43pub const build = @import("build.zig");47pub const build = @import("build.zig");
44pub const builtin = @import("builtin.zig");48pub const builtin = @import("builtin.zig");
45pub const c = @import("c.zig");49pub const c = @import("c.zig");
lib/std/zig/parse.zig+12-20
...@@ -3714,7 +3714,6 @@ const Parser = struct {...@@ -3714,7 +3714,6 @@ const Parser = struct {
3714 if (p.eatToken(.r_paren)) |_| {3714 if (p.eatToken(.r_paren)) |_| {
3715 return SmallSpan{ .zero_or_one = 0 };3715 return SmallSpan{ .zero_or_one = 0 };
3716 }3716 }
3717 continue;
3718 },3717 },
3719 .r_paren => return SmallSpan{ .zero_or_one = 0 },3718 .r_paren => return SmallSpan{ .zero_or_one = 0 },
3720 else => {3719 else => {
...@@ -3728,14 +3727,7 @@ const Parser = struct {...@@ -3728,14 +3727,7 @@ const Parser = struct {
37283727
3729 const param_two = while (true) {3728 const param_two = while (true) {
3730 switch (p.token_tags[p.nextToken()]) {3729 switch (p.token_tags[p.nextToken()]) {
3731 .comma => {3730 .comma => {},
3732 if (p.eatToken(.r_paren)) |_| {
3733 return SmallSpan{ .zero_or_one = param_one };
3734 }
3735 const param = try p.expectParamDecl();
3736 if (param != 0) break param;
3737 continue;
3738 },
3739 .r_paren => return SmallSpan{ .zero_or_one = param_one },3731 .r_paren => return SmallSpan{ .zero_or_one = param_one },
3740 .colon, .r_brace, .r_bracket => {3732 .colon, .r_brace, .r_bracket => {
3741 p.tok_i -= 1;3733 p.tok_i -= 1;
...@@ -3748,6 +3740,11 @@ const Parser = struct {...@@ -3748,6 +3740,11 @@ const Parser = struct {
3748 try p.warnExpected(.comma);3740 try p.warnExpected(.comma);
3749 },3741 },
3750 }3742 }
3743 if (p.eatToken(.r_paren)) |_| {
3744 return SmallSpan{ .zero_or_one = param_one };
3745 }
3746 const param = try p.expectParamDecl();
3747 if (param != 0) break param;
3751 } else unreachable;3748 } else unreachable;
37523749
3753 var list = std.ArrayList(Node.Index).init(p.gpa);3750 var list = std.ArrayList(Node.Index).init(p.gpa);
...@@ -3757,17 +3754,7 @@ const Parser = struct {...@@ -3757,17 +3754,7 @@ const Parser = struct {
37573754
3758 while (true) {3755 while (true) {
3759 switch (p.token_tags[p.nextToken()]) {3756 switch (p.token_tags[p.nextToken()]) {
3760 .comma => {3757 .comma => {},
3761 if (p.token_tags[p.tok_i] == .r_paren) {
3762 p.tok_i += 1;
3763 return SmallSpan{ .multi = list.toOwnedSlice() };
3764 }
3765 const param = try p.expectParamDecl();
3766 if (param != 0) {
3767 try list.append(param);
3768 }
3769 continue;
3770 },
3771 .r_paren => return SmallSpan{ .multi = list.toOwnedSlice() },3758 .r_paren => return SmallSpan{ .multi = list.toOwnedSlice() },
3772 .colon, .r_brace, .r_bracket => {3759 .colon, .r_brace, .r_bracket => {
3773 p.tok_i -= 1;3760 p.tok_i -= 1;
...@@ -3780,6 +3767,11 @@ const Parser = struct {...@@ -3780,6 +3767,11 @@ const Parser = struct {
3780 try p.warnExpected(.comma);3767 try p.warnExpected(.comma);
3781 },3768 },
3782 }3769 }
3770 if (p.eatToken(.r_paren)) |_| {
3771 return SmallSpan{ .multi = list.toOwnedSlice() };
3772 }
3773 const param = try p.expectParamDecl();
3774 if (param != 0) try list.append(param);
3783 }3775 }
3784 }3776 }
37853777
lib/std/zig/parser_test.zig+31
...@@ -1108,6 +1108,25 @@ test "zig fmt: comment to disable/enable zig fmt first" {...@@ -1108,6 +1108,25 @@ test "zig fmt: comment to disable/enable zig fmt first" {
1108 );1108 );
1109}1109}
11101110
1111test "zig fmt: 'zig fmt: (off|on)' can be surrounded by arbitrary whitespace" {
1112 try testTransform(
1113 \\// Test trailing comma syntax
1114 \\// zig fmt: off
1115 \\
1116 \\const struct_trailing_comma = struct { x: i32, y: i32, };
1117 \\
1118 \\// zig fmt: on
1119 ,
1120 \\// Test trailing comma syntax
1121 \\// zig fmt: off
1122 \\
1123 \\const struct_trailing_comma = struct { x: i32, y: i32, };
1124 \\
1125 \\// zig fmt: on
1126 \\
1127 );
1128}
1129
1111test "zig fmt: comment to disable/enable zig fmt" {1130test "zig fmt: comment to disable/enable zig fmt" {
1112 try testTransform(1131 try testTransform(
1113 \\const a = b;1132 \\const a = b;
...@@ -4549,6 +4568,18 @@ test "recovery: missing for payload" {...@@ -4549,6 +4568,18 @@ test "recovery: missing for payload" {
4549 });4568 });
4550}4569}
45514570
4571test "recovery: missing comma in params" {
4572 try testError(
4573 \\fn foo(comptime bool what what) void { }
4574 \\fn bar(a: i32, b: i32 c) void { }
4575 \\
4576 , &[_]Error{
4577 .expected_token,
4578 .expected_token,
4579 .expected_token,
4580 });
4581}
4582
4552const std = @import("std");4583const std = @import("std");
4553const mem = std.mem;4584const mem = std.mem;
4554const warn = std.debug.warn;4585const warn = std.debug.warn;
lib/std/zig/render.zig+17-11
...@@ -2352,18 +2352,24 @@ fn renderComments(ais: *Ais, tree: ast.Tree, start: usize, end: usize) Error!boo...@@ -2352,18 +2352,24 @@ fn renderComments(ais: *Ais, tree: ast.Tree, start: usize, end: usize) Error!boo
2352 }2352 }
2353 }2353 }
23542354
2355 try ais.writer().print("{s}\n", .{trimmed_comment});2355 index = 1 + (newline orelse end - 1);
2356 index = 1 + (newline orelse return true);2356
23572357 const comment_content = mem.trimLeft(u8, trimmed_comment["//".len..], &std.ascii.spaces);
2358 if (ais.disabled_offset) |disabled_offset| {2358 if (ais.disabled_offset != null and mem.eql(u8, comment_content, "zig fmt: on")) {
2359 if (mem.eql(u8, trimmed_comment, "// zig fmt: on")) {2359 // Write the source for which formatting was disabled directly
2360 // write the source for which formatting was disabled directly2360 // to the underlying writer, fixing up invaild whitespace.
2361 // to the underlying writer, fixing up invaild whitespace2361 const disabled_source = tree.source[ais.disabled_offset.?..comment_start];
2362 try writeFixingWhitespace(ais.underlying_writer, tree.source[disabled_offset..index]);2362 try writeFixingWhitespace(ais.underlying_writer, disabled_source);
2363 ais.disabled_offset = null;2363 ais.disabled_offset = null;
2364 }2364 // Write with the canonical single space.
2365 } else if (mem.eql(u8, trimmed_comment, "// zig fmt: off")) {2365 try ais.writer().writeAll("// zig fmt: on\n");
2366 } else if (ais.disabled_offset == null and mem.eql(u8, comment_content, "zig fmt: off")) {
2367 // Write with the canonical single space.
2368 try ais.writer().writeAll("// zig fmt: off\n");
2366 ais.disabled_offset = index;2369 ais.disabled_offset = index;
2370 } else {
2371 // Write the comment minus trailing whitespace.
2372 try ais.writer().print("{s}\n", .{trimmed_comment});
2367 }2373 }
2368 }2374 }
23692375
src/Cache.zig+20-4
...@@ -153,7 +153,11 @@ pub const HashHelper = struct {...@@ -153,7 +153,11 @@ pub const HashHelper = struct {
153 hh.hasher.final(&bin_digest);153 hh.hasher.final(&bin_digest);
154154
155 var out_digest: [hex_digest_len]u8 = undefined;155 var out_digest: [hex_digest_len]u8 = undefined;
156 _ = std.fmt.bufPrint(&out_digest, "{x}", .{bin_digest}) catch unreachable;156 _ = std.fmt.bufPrint(
157 &out_digest,
158 "{s}",
159 .{std.fmt.fmtSliceHexLower(&bin_digest)},
160 ) catch unreachable;
157 return out_digest;161 return out_digest;
158 }162 }
159};163};
...@@ -250,7 +254,11 @@ pub const Manifest = struct {...@@ -250,7 +254,11 @@ pub const Manifest = struct {
250 var bin_digest: BinDigest = undefined;254 var bin_digest: BinDigest = undefined;
251 self.hash.hasher.final(&bin_digest);255 self.hash.hasher.final(&bin_digest);
252256
253 _ = std.fmt.bufPrint(&self.hex_digest, "{x}", .{bin_digest}) catch unreachable;257 _ = std.fmt.bufPrint(
258 &self.hex_digest,
259 "{s}",
260 .{std.fmt.fmtSliceHexLower(&bin_digest)},
261 ) catch unreachable;
254262
255 self.hash.hasher = hasher_init;263 self.hash.hasher = hasher_init;
256 self.hash.hasher.update(&bin_digest);264 self.hash.hasher.update(&bin_digest);
...@@ -549,7 +557,11 @@ pub const Manifest = struct {...@@ -549,7 +557,11 @@ pub const Manifest = struct {
549 self.hash.hasher.final(&bin_digest);557 self.hash.hasher.final(&bin_digest);
550558
551 var out_digest: [hex_digest_len]u8 = undefined;559 var out_digest: [hex_digest_len]u8 = undefined;
552 _ = std.fmt.bufPrint(&out_digest, "{x}", .{bin_digest}) catch unreachable;560 _ = std.fmt.bufPrint(
561 &out_digest,
562 "{s}",
563 .{std.fmt.fmtSliceHexLower(&bin_digest)},
564 ) catch unreachable;
553565
554 return out_digest;566 return out_digest;
555 }567 }
...@@ -565,7 +577,11 @@ pub const Manifest = struct {...@@ -565,7 +577,11 @@ pub const Manifest = struct {
565 var encoded_digest: [hex_digest_len]u8 = undefined;577 var encoded_digest: [hex_digest_len]u8 = undefined;
566578
567 for (self.files.items) |file| {579 for (self.files.items) |file| {
568 _ = std.fmt.bufPrint(&encoded_digest, "{x}", .{file.bin_digest}) catch unreachable;580 _ = std.fmt.bufPrint(
581 &encoded_digest,
582 "{s}",
583 .{std.fmt.fmtSliceHexLower(&file.bin_digest)},
584 ) catch unreachable;
569 try writer.print("{d} {d} {d} {s} {s}\n", .{585 try writer.print("{d} {d} {d} {s} {s}\n", .{
570 file.stat.size,586 file.stat.size,
571 file.stat.inode,587 file.stat.inode,
src/Module.zig+6-6
...@@ -4083,15 +4083,15 @@ pub fn namedFieldPtr(...@@ -4083,15 +4083,15 @@ pub fn namedFieldPtr(
4083 const child_type = try val.toType(scope.arena());4083 const child_type = try val.toType(scope.arena());
4084 switch (child_type.zigTypeTag()) {4084 switch (child_type.zigTypeTag()) {
4085 .ErrorSet => {4085 .ErrorSet => {
4086 var name: []const u8 = undefined;
4086 // TODO resolve inferred error sets4087 // TODO resolve inferred error sets
4087 const entry = if (val.castTag(.error_set)) |payload|4088 if (val.castTag(.error_set)) |payload|
4088 (payload.data.fields.getEntry(field_name) orelse4089 name = (payload.data.fields.getEntry(field_name) orelse return mod.fail(scope, src, "no error named '{s}' in '{}'", .{ field_name, child_type })).key
4089 return mod.fail(scope, src, "no error named '{s}' in '{}'", .{ field_name, child_type })).*
4090 else4090 else
4091 try mod.getErrorValue(field_name);4091 name = (try mod.getErrorValue(field_name)).key;
40924092
4093 const result_type = if (child_type.tag() == .anyerror)4093 const result_type = if (child_type.tag() == .anyerror)
4094 try Type.Tag.error_set_single.create(scope.arena(), entry.key)4094 try Type.Tag.error_set_single.create(scope.arena(), name)
4095 else4095 else
4096 child_type;4096 child_type;
40974097
...@@ -4100,7 +4100,7 @@ pub fn namedFieldPtr(...@@ -4100,7 +4100,7 @@ pub fn namedFieldPtr(
4100 .val = try Value.Tag.ref_val.create(4100 .val = try Value.Tag.ref_val.create(
4101 scope.arena(),4101 scope.arena(),
4102 try Value.Tag.@"error".create(scope.arena(), .{4102 try Value.Tag.@"error".create(scope.arena(), .{
4103 .name = entry.key,4103 .name = name,
4104 }),4104 }),
4105 ),4105 ),
4106 });4106 });
src/astgen.zig+48-11
...@@ -453,13 +453,23 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In...@@ -453,13 +453,23 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
453 return rvalue(mod, scope, rl, result);453 return rvalue(mod, scope, rl, result);
454 },454 },
455 .unwrap_optional => {455 .unwrap_optional => {
456 const operand = try expr(mod, scope, rl, node_datas[node].lhs);
457 const op: zir.Inst.Tag = switch (rl) {
458 .ref => .optional_payload_safe_ptr,
459 else => .optional_payload_safe,
460 };
461 const src = token_starts[main_tokens[node]];456 const src = token_starts[main_tokens[node]];
462 return addZIRUnOp(mod, scope, src, op, operand);457 switch (rl) {
458 .ref => return addZIRUnOp(
459 mod,
460 scope,
461 src,
462 .optional_payload_safe_ptr,
463 try expr(mod, scope, .ref, node_datas[node].lhs),
464 ),
465 else => return rvalue(mod, scope, rl, try addZIRUnOp(
466 mod,
467 scope,
468 src,
469 .optional_payload_safe,
470 try expr(mod, scope, .none, node_datas[node].lhs),
471 )),
472 }
463 },473 },
464 .block_two, .block_two_semicolon => {474 .block_two, .block_two_semicolon => {
465 const statements = [2]ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs };475 const statements = [2]ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs };
...@@ -1645,7 +1655,7 @@ fn errorSetDecl(...@@ -1645,7 +1655,7 @@ fn errorSetDecl(
1645 switch (token_tags[tok_i]) {1655 switch (token_tags[tok_i]) {
1646 .doc_comment, .comma => {},1656 .doc_comment, .comma => {},
1647 .identifier => count += 1,1657 .identifier => count += 1,
1648 .r_paren => break :count count,1658 .r_brace => break :count count,
1649 else => unreachable,1659 else => unreachable,
1650 }1660 }
1651 } else unreachable; // TODO should not need else unreachable here1661 } else unreachable; // TODO should not need else unreachable here
...@@ -1662,7 +1672,7 @@ fn errorSetDecl(...@@ -1662,7 +1672,7 @@ fn errorSetDecl(
1662 fields[field_i] = try mod.identifierTokenString(scope, tok_i);1672 fields[field_i] = try mod.identifierTokenString(scope, tok_i);
1663 field_i += 1;1673 field_i += 1;
1664 },1674 },
1665 .r_paren => break,1675 .r_brace => break,
1666 else => unreachable,1676 else => unreachable,
1667 }1677 }
1668 }1678 }
...@@ -1699,9 +1709,13 @@ fn orelseCatchExpr(...@@ -1699,9 +1709,13 @@ fn orelseCatchExpr(
1699 setBlockResultLoc(&block_scope, rl);1709 setBlockResultLoc(&block_scope, rl);
1700 defer block_scope.instructions.deinit(mod.gpa);1710 defer block_scope.instructions.deinit(mod.gpa);
17011711
1702 // This could be a pointer or value depending on the `rl` parameter.1712 // This could be a pointer or value depending on the `operand_rl` parameter.
1713 // We cannot use `block_scope.break_result_loc` because that has the bare
1714 // type, whereas this expression has the optional type. Later we make
1715 // up for this fact by calling rvalue on the else branch.
1703 block_scope.break_count += 1;1716 block_scope.break_count += 1;
1704 const operand = try expr(mod, &block_scope.base, block_scope.break_result_loc, lhs);1717 const operand_rl = try makeOptionalTypeResultLoc(mod, &block_scope.base, src, block_scope.break_result_loc);
1718 const operand = try expr(mod, &block_scope.base, operand_rl, lhs);
1705 const cond = try addZIRUnOp(mod, &block_scope.base, src, cond_op, operand);1719 const cond = try addZIRUnOp(mod, &block_scope.base, src, cond_op, operand);
17061720
1707 const condbr = try addZIRInstSpecial(mod, &block_scope.base, src, zir.Inst.CondBr, .{1721 const condbr = try addZIRInstSpecial(mod, &block_scope.base, src, zir.Inst.CondBr, .{
...@@ -1753,6 +1767,10 @@ fn orelseCatchExpr(...@@ -1753,6 +1767,10 @@ fn orelseCatchExpr(
17531767
1754 // This could be a pointer or value depending on `unwrap_op`.1768 // This could be a pointer or value depending on `unwrap_op`.
1755 const unwrapped_payload = try addZIRUnOp(mod, &else_scope.base, src, unwrap_op, operand);1769 const unwrapped_payload = try addZIRUnOp(mod, &else_scope.base, src, unwrap_op, operand);
1770 const else_result = switch (rl) {
1771 .ref => unwrapped_payload,
1772 else => try rvalue(mod, &else_scope.base, block_scope.break_result_loc, unwrapped_payload),
1773 };
17561774
1757 return finishThenElseBlock(1775 return finishThenElseBlock(
1758 mod,1776 mod,
...@@ -1766,7 +1784,7 @@ fn orelseCatchExpr(...@@ -1766,7 +1784,7 @@ fn orelseCatchExpr(
1766 src,1784 src,
1767 src,1785 src,
1768 then_result,1786 then_result,
1769 unwrapped_payload,1787 else_result,
1770 block,1788 block,
1771 block,1789 block,
1772 );1790 );
...@@ -3955,6 +3973,25 @@ fn rlStrategy(rl: ResultLoc, block_scope: *Scope.GenZIR) ResultLoc.Strategy {...@@ -3955,6 +3973,25 @@ fn rlStrategy(rl: ResultLoc, block_scope: *Scope.GenZIR) ResultLoc.Strategy {
3955 }3973 }
3956}3974}
39573975
3976/// If the input ResultLoc is ref, returns ResultLoc.ref. Otherwise:
3977/// Returns ResultLoc.ty, where the type is determined by the input
3978/// ResultLoc type, wrapped in an optional type. If the input ResultLoc
3979/// has no type, .none is returned.
3980fn makeOptionalTypeResultLoc(mod: *Module, scope: *Scope, src: usize, rl: ResultLoc) !ResultLoc {
3981 switch (rl) {
3982 .ref => return ResultLoc.ref,
3983 .discard, .none, .block_ptr, .inferred_ptr, .bitcasted_ptr => return ResultLoc.none,
3984 .ty => |elem_ty| {
3985 const wrapped_ty = try addZIRUnOp(mod, scope, src, .optional_type, elem_ty);
3986 return ResultLoc{ .ty = wrapped_ty };
3987 },
3988 .ptr => |ptr_ty| {
3989 const wrapped_ty = try addZIRUnOp(mod, scope, src, .optional_type_from_ptr_elem, ptr_ty);
3990 return ResultLoc{ .ty = wrapped_ty };
3991 },
3992 }
3993}
3994
3958fn setBlockResultLoc(block_scope: *Scope.GenZIR, parent_rl: ResultLoc) void {3995fn setBlockResultLoc(block_scope: *Scope.GenZIR, parent_rl: ResultLoc) void {
3959 // Depending on whether the result location is a pointer or value, different3996 // Depending on whether the result location is a pointer or value, different
3960 // ZIR needs to be generated. In the former case we rely on storing to the3997 // ZIR needs to be generated. In the former case we rely on storing to the
src/clang_options_data.zig+5-5
...@@ -46,7 +46,7 @@ flagpd1("M"),...@@ -46,7 +46,7 @@ flagpd1("M"),
46.{46.{
47 .name = "MM",47 .name = "MM",
48 .syntax = .flag,48 .syntax = .flag,
49 .zig_equivalent = .dep_file,49 .zig_equivalent = .dep_file_mm,
50 .pd1 = true,50 .pd1 = true,
51 .pd2 = false,51 .pd2 = false,
52 .psl = false,52 .psl = false,
...@@ -1870,7 +1870,7 @@ flagpsl("MT"),...@@ -1870,7 +1870,7 @@ flagpsl("MT"),
1870.{1870.{
1871 .name = "print-missing-file-dependencies",1871 .name = "print-missing-file-dependencies",
1872 .syntax = .flag,1872 .syntax = .flag,
1873 .zig_equivalent = .other,1873 .zig_equivalent = .dep_file,
1874 .pd1 = false,1874 .pd1 = false,
1875 .pd2 = true,1875 .pd2 = true,
1876 .psl = false,1876 .psl = false,
...@@ -1990,7 +1990,7 @@ flagpsl("MT"),...@@ -1990,7 +1990,7 @@ flagpsl("MT"),
1990.{1990.{
1991 .name = "user-dependencies",1991 .name = "user-dependencies",
1992 .syntax = .flag,1992 .syntax = .flag,
1993 .zig_equivalent = .other,1993 .zig_equivalent = .dep_file_mm,
1994 .pd1 = false,1994 .pd1 = false,
1995 .pd2 = true,1995 .pd2 = true,
1996 .psl = false,1996 .psl = false,
...@@ -2014,7 +2014,7 @@ flagpsl("MT"),...@@ -2014,7 +2014,7 @@ flagpsl("MT"),
2014.{2014.{
2015 .name = "write-dependencies",2015 .name = "write-dependencies",
2016 .syntax = .flag,2016 .syntax = .flag,
2017 .zig_equivalent = .other,2017 .zig_equivalent = .dep_file,
2018 .pd1 = false,2018 .pd1 = false,
2019 .pd2 = true,2019 .pd2 = true,
2020 .psl = false,2020 .psl = false,
...@@ -2022,7 +2022,7 @@ flagpsl("MT"),...@@ -2022,7 +2022,7 @@ flagpsl("MT"),
2022.{2022.{
2023 .name = "write-user-dependencies",2023 .name = "write-user-dependencies",
2024 .syntax = .flag,2024 .syntax = .flag,
2025 .zig_equivalent = .other,2025 .zig_equivalent = .dep_file,
2026 .pd1 = false,2026 .pd1 = false,
2027 .pd2 = true,2027 .pd2 = true,
2028 .psl = false,2028 .psl = false,
src/codegen.zig+43
...@@ -899,6 +899,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -899,6 +899,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
899 .load => return self.genLoad(inst.castTag(.load).?),899 .load => return self.genLoad(inst.castTag(.load).?),
900 .loop => return self.genLoop(inst.castTag(.loop).?),900 .loop => return self.genLoop(inst.castTag(.loop).?),
901 .not => return self.genNot(inst.castTag(.not).?),901 .not => return self.genNot(inst.castTag(.not).?),
902 .mul => return self.genMul(inst.castTag(.mul).?),
902 .ptrtoint => return self.genPtrToInt(inst.castTag(.ptrtoint).?),903 .ptrtoint => return self.genPtrToInt(inst.castTag(.ptrtoint).?),
903 .ref => return self.genRef(inst.castTag(.ref).?),904 .ref => return self.genRef(inst.castTag(.ref).?),
904 .ret => return self.genRet(inst.castTag(.ret).?),905 .ret => return self.genRet(inst.castTag(.ret).?),
...@@ -1128,6 +1129,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1128,6 +1129,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1128 }1129 }
1129 }1130 }
11301131
1132 fn genMul(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
1133 // No side effects, so if it's unreferenced, do nothing.
1134 if (inst.base.isUnused())
1135 return MCValue.dead;
1136 switch (arch) {
1137 .arm, .armeb => return try self.genArmMul(&inst.base, inst.lhs, inst.rhs),
1138 else => return self.fail(inst.base.src, "TODO implement mul for {}", .{self.target.cpu.arch}),
1139 }
1140 }
1141
1131 fn genBitAnd(self: *Self, inst: *ir.Inst.BinOp) !MCValue {1142 fn genBitAnd(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
1132 // No side effects, so if it's unreferenced, do nothing.1143 // No side effects, so if it's unreferenced, do nothing.
1133 if (inst.base.isUnused())1144 if (inst.base.isUnused())
...@@ -1478,6 +1489,38 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1478,6 +1489,38 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1478 }1489 }
1479 }1490 }
14801491
1492 fn genArmMul(self: *Self, inst: *ir.Inst, op_lhs: *ir.Inst, op_rhs: *ir.Inst) !MCValue {
1493 const lhs = try self.resolveInst(op_lhs);
1494 const rhs = try self.resolveInst(op_rhs);
1495
1496 // Destination must be a register
1497 // LHS must be a register
1498 // RHS must be a register
1499 var dst_mcv: MCValue = undefined;
1500 var lhs_mcv: MCValue = undefined;
1501 var rhs_mcv: MCValue = undefined;
1502 if (self.reuseOperand(inst, 0, lhs)) {
1503 // LHS is the destination
1504 lhs_mcv = if (lhs != .register) try self.copyToNewRegister(inst, lhs) else lhs;
1505 rhs_mcv = if (rhs != .register) try self.copyToNewRegister(inst, rhs) else rhs;
1506 dst_mcv = lhs_mcv;
1507 } else if (self.reuseOperand(inst, 1, rhs)) {
1508 // RHS is the destination
1509 lhs_mcv = if (lhs != .register) try self.copyToNewRegister(inst, lhs) else lhs;
1510 rhs_mcv = if (rhs != .register) try self.copyToNewRegister(inst, rhs) else rhs;
1511 dst_mcv = rhs_mcv;
1512 } else {
1513 // TODO save 1 copy instruction by directly allocating the destination register
1514 // LHS is the destination
1515 lhs_mcv = try self.copyToNewRegister(inst, lhs);
1516 rhs_mcv = if (rhs != .register) try self.copyToNewRegister(inst, rhs) else rhs;
1517 dst_mcv = lhs_mcv;
1518 }
1519
1520 writeInt(u32, try self.code.addManyAsArray(4), Instruction.mul(.al, dst_mcv.register, lhs_mcv.register, rhs_mcv.register).toU32());
1521 return dst_mcv;
1522 }
1523
1481 /// ADD, SUB, XOR, OR, AND1524 /// ADD, SUB, XOR, OR, AND
1482 fn genX8664BinMath(self: *Self, inst: *ir.Inst, op_lhs: *ir.Inst, op_rhs: *ir.Inst, opx: u8, mr: u8) !MCValue {1525 fn genX8664BinMath(self: *Self, inst: *ir.Inst, op_lhs: *ir.Inst, op_rhs: *ir.Inst, opx: u8, mr: u8) !MCValue {
1483 try self.code.ensureCapacity(self.code.items.len + 8);1526 try self.code.ensureCapacity(self.code.items.len + 8);
src/codegen/llvm.zig+105-8
...@@ -400,6 +400,7 @@ pub const LLVMIRModule = struct {...@@ -400,6 +400,7 @@ pub const LLVMIRModule = struct {
400 .block => try self.genBlock(inst.castTag(.block).?),400 .block => try self.genBlock(inst.castTag(.block).?),
401 .br => try self.genBr(inst.castTag(.br).?),401 .br => try self.genBr(inst.castTag(.br).?),
402 .breakpoint => try self.genBreakpoint(inst.castTag(.breakpoint).?),402 .breakpoint => try self.genBreakpoint(inst.castTag(.breakpoint).?),
403 .br_void => try self.genBrVoid(inst.castTag(.br_void).?),
403 .call => try self.genCall(inst.castTag(.call).?),404 .call => try self.genCall(inst.castTag(.call).?),
404 .cmp_eq => try self.genCmp(inst.castTag(.cmp_eq).?, .eq),405 .cmp_eq => try self.genCmp(inst.castTag(.cmp_eq).?, .eq),
405 .cmp_gt => try self.genCmp(inst.castTag(.cmp_gt).?, .gt),406 .cmp_gt => try self.genCmp(inst.castTag(.cmp_gt).?, .gt),
...@@ -409,6 +410,10 @@ pub const LLVMIRModule = struct {...@@ -409,6 +410,10 @@ pub const LLVMIRModule = struct {
409 .cmp_neq => try self.genCmp(inst.castTag(.cmp_neq).?, .neq),410 .cmp_neq => try self.genCmp(inst.castTag(.cmp_neq).?, .neq),
410 .condbr => try self.genCondBr(inst.castTag(.condbr).?),411 .condbr => try self.genCondBr(inst.castTag(.condbr).?),
411 .intcast => try self.genIntCast(inst.castTag(.intcast).?),412 .intcast => try self.genIntCast(inst.castTag(.intcast).?),
413 .is_non_null => try self.genIsNonNull(inst.castTag(.is_non_null).?, false),
414 .is_non_null_ptr => try self.genIsNonNull(inst.castTag(.is_non_null_ptr).?, true),
415 .is_null => try self.genIsNull(inst.castTag(.is_null).?, false),
416 .is_null_ptr => try self.genIsNull(inst.castTag(.is_null_ptr).?, true),
412 .load => try self.genLoad(inst.castTag(.load).?),417 .load => try self.genLoad(inst.castTag(.load).?),
413 .loop => try self.genLoop(inst.castTag(.loop).?),418 .loop => try self.genLoop(inst.castTag(.loop).?),
414 .not => try self.genNot(inst.castTag(.not).?),419 .not => try self.genNot(inst.castTag(.not).?),
...@@ -417,6 +422,8 @@ pub const LLVMIRModule = struct {...@@ -417,6 +422,8 @@ pub const LLVMIRModule = struct {
417 .store => try self.genStore(inst.castTag(.store).?),422 .store => try self.genStore(inst.castTag(.store).?),
418 .sub => try self.genSub(inst.castTag(.sub).?),423 .sub => try self.genSub(inst.castTag(.sub).?),
419 .unreach => self.genUnreach(inst.castTag(.unreach).?),424 .unreach => self.genUnreach(inst.castTag(.unreach).?),
425 .optional_payload => try self.genOptionalPayload(inst.castTag(.optional_payload).?, false),
426 .optional_payload_ptr => try self.genOptionalPayload(inst.castTag(.optional_payload_ptr).?, true),
420 .dbg_stmt => blk: {427 .dbg_stmt => blk: {
421 // TODO: implement debug info428 // TODO: implement debug info
422 break :blk null;429 break :blk null;
...@@ -537,21 +544,29 @@ pub const LLVMIRModule = struct {...@@ -537,21 +544,29 @@ pub const LLVMIRModule = struct {
537 }544 }
538545
539 fn genBr(self: *LLVMIRModule, inst: *Inst.Br) !?*const llvm.Value {546 fn genBr(self: *LLVMIRModule, inst: *Inst.Br) !?*const llvm.Value {
540 // Get the block that we want to break to.
541 var block = self.blocks.get(inst.block).?;547 var block = self.blocks.get(inst.block).?;
542 _ = self.builder.buildBr(block.parent_bb);
543548
544 // If the break doesn't break a value, then we don't have to add549 // If the break doesn't break a value, then we don't have to add
545 // the values to the lists.550 // the values to the lists.
546 if (!inst.operand.ty.hasCodeGenBits()) return null;551 if (!inst.operand.ty.hasCodeGenBits()) {
552 // TODO: in astgen these instructions should turn into `br_void` instructions.
553 _ = self.builder.buildBr(block.parent_bb);
554 } else {
555 const val = try self.resolveInst(inst.operand);
547556
548 // For the phi node, we need the basic blocks and the values of the557 // For the phi node, we need the basic blocks and the values of the
549 // break instructions.558 // break instructions.
550 try block.break_bbs.append(self.gpa, self.builder.getInsertBlock());559 try block.break_bbs.append(self.gpa, self.builder.getInsertBlock());
560 try block.break_vals.append(self.gpa, val);
551561
552 const val = try self.resolveInst(inst.operand);562 _ = self.builder.buildBr(block.parent_bb);
553 try block.break_vals.append(self.gpa, val);563 }
564 return null;
565 }
554566
567 fn genBrVoid(self: *LLVMIRModule, inst: *Inst.BrVoid) !?*const llvm.Value {
568 var block = self.blocks.get(inst.block).?;
569 _ = self.builder.buildBr(block.parent_bb);
555 return null;570 return null;
556 }571 }
557572
...@@ -594,6 +609,44 @@ pub const LLVMIRModule = struct {...@@ -594,6 +609,44 @@ pub const LLVMIRModule = struct {
594 return null;609 return null;
595 }610 }
596611
612 fn genIsNonNull(self: *LLVMIRModule, inst: *Inst.UnOp, operand_is_ptr: bool) !?*const llvm.Value {
613 const operand = try self.resolveInst(inst.operand);
614
615 if (operand_is_ptr) {
616 const index_type = self.context.intType(32);
617
618 var indices: [2]*const llvm.Value = .{
619 index_type.constNull(),
620 index_type.constInt(1, false),
621 };
622
623 return self.builder.buildLoad(self.builder.buildInBoundsGEP(operand, &indices, 2, ""), "");
624 } else {
625 return self.builder.buildExtractValue(operand, 1, "");
626 }
627 }
628
629 fn genIsNull(self: *LLVMIRModule, inst: *Inst.UnOp, operand_is_ptr: bool) !?*const llvm.Value {
630 return self.builder.buildNot((try self.genIsNonNull(inst, operand_is_ptr)).?, "");
631 }
632
633 fn genOptionalPayload(self: *LLVMIRModule, inst: *Inst.UnOp, operand_is_ptr: bool) !?*const llvm.Value {
634 const operand = try self.resolveInst(inst.operand);
635
636 if (operand_is_ptr) {
637 const index_type = self.context.intType(32);
638
639 var indices: [2]*const llvm.Value = .{
640 index_type.constNull(),
641 index_type.constNull(),
642 };
643
644 return self.builder.buildInBoundsGEP(operand, &indices, 2, "");
645 } else {
646 return self.builder.buildExtractValue(operand, 0, "");
647 }
648 }
649
597 fn genAdd(self: *LLVMIRModule, inst: *Inst.BinOp) !?*const llvm.Value {650 fn genAdd(self: *LLVMIRModule, inst: *Inst.BinOp) !?*const llvm.Value {
598 const lhs = try self.resolveInst(inst.lhs);651 const lhs = try self.resolveInst(inst.lhs);
599 const rhs = try self.resolveInst(inst.rhs);652 const rhs = try self.resolveInst(inst.rhs);
...@@ -754,6 +807,13 @@ pub const LLVMIRModule = struct {...@@ -754,6 +807,13 @@ pub const LLVMIRModule = struct {
754 // TODO: consider using buildInBoundsGEP2 for opaque pointers807 // TODO: consider using buildInBoundsGEP2 for opaque pointers
755 return self.builder.buildInBoundsGEP(val, &indices, 2, "");808 return self.builder.buildInBoundsGEP(val, &indices, 2, "");
756 },809 },
810 .ref_val => {
811 const elem_value = tv.val.castTag(.ref_val).?.data;
812 const elem_type = tv.ty.castPointer().?.data;
813 const alloca = self.buildAlloca(try self.getLLVMType(elem_type, src));
814 _ = self.builder.buildStore(try self.genTypedValue(src, .{ .ty = elem_type, .val = elem_value }), alloca);
815 return alloca;
816 },
757 else => return self.fail(src, "TODO implement const of pointer type '{}'", .{tv.ty}),817 else => return self.fail(src, "TODO implement const of pointer type '{}'", .{tv.ty}),
758 },818 },
759 .Array => {819 .Array => {
...@@ -768,6 +828,29 @@ pub const LLVMIRModule = struct {...@@ -768,6 +828,29 @@ pub const LLVMIRModule = struct {
768 return self.fail(src, "TODO handle more array values", .{});828 return self.fail(src, "TODO handle more array values", .{});
769 }829 }
770 },830 },
831 .Optional => {
832 if (!tv.ty.isPtrLikeOptional()) {
833 var buf: Type.Payload.ElemType = undefined;
834 const child_type = tv.ty.optionalChild(&buf);
835 const llvm_child_type = try self.getLLVMType(child_type, src);
836
837 if (tv.val.tag() == .null_value) {
838 var optional_values: [2]*const llvm.Value = .{
839 llvm_child_type.constNull(),
840 self.context.intType(1).constNull(),
841 };
842 return self.context.constStruct(&optional_values, 2, false);
843 } else {
844 var optional_values: [2]*const llvm.Value = .{
845 try self.genTypedValue(src, .{ .ty = child_type, .val = tv.val }),
846 self.context.intType(1).constAllOnes(),
847 };
848 return self.context.constStruct(&optional_values, 2, false);
849 }
850 } else {
851 return self.fail(src, "TODO implement const of optional pointer", .{});
852 }
853 },
771 else => return self.fail(src, "TODO implement const of type '{}'", .{tv.ty}),854 else => return self.fail(src, "TODO implement const of type '{}'", .{tv.ty}),
772 }855 }
773 }856 }
...@@ -793,6 +876,20 @@ pub const LLVMIRModule = struct {...@@ -793,6 +876,20 @@ pub const LLVMIRModule = struct {
793 const elem_type = try self.getLLVMType(t.elemType(), src);876 const elem_type = try self.getLLVMType(t.elemType(), src);
794 return elem_type.arrayType(@intCast(c_uint, t.abiSize(self.module.getTarget())));877 return elem_type.arrayType(@intCast(c_uint, t.abiSize(self.module.getTarget())));
795 },878 },
879 .Optional => {
880 if (!t.isPtrLikeOptional()) {
881 var buf: Type.Payload.ElemType = undefined;
882 const child_type = t.optionalChild(&buf);
883
884 var optional_types: [2]*const llvm.Type = .{
885 try self.getLLVMType(child_type, src),
886 self.context.intType(1),
887 };
888 return self.context.structType(&optional_types, 2, false);
889 } else {
890 return self.fail(src, "TODO implement optional pointers as actual pointers", .{});
891 }
892 },
796 else => return self.fail(src, "TODO implement getLLVMType for type '{}'", .{t}),893 else => return self.fail(src, "TODO implement getLLVMType for type '{}'", .{t}),
797 }894 }
798 }895 }
src/codegen/llvm/bindings.zig+9
...@@ -21,9 +21,15 @@ pub const Context = opaque {...@@ -21,9 +21,15 @@ pub const Context = opaque {
21 pub const voidType = LLVMVoidTypeInContext;21 pub const voidType = LLVMVoidTypeInContext;
22 extern fn LLVMVoidTypeInContext(C: *const Context) *const Type;22 extern fn LLVMVoidTypeInContext(C: *const Context) *const Type;
2323
24 pub const structType = LLVMStructTypeInContext;
25 extern fn LLVMStructTypeInContext(C: *const Context, ElementTypes: [*]*const Type, ElementCount: c_uint, Packed: LLVMBool) *const Type;
26
24 pub const constString = LLVMConstStringInContext;27 pub const constString = LLVMConstStringInContext;
25 extern fn LLVMConstStringInContext(C: *const Context, Str: [*]const u8, Length: c_uint, DontNullTerminate: LLVMBool) *const Value;28 extern fn LLVMConstStringInContext(C: *const Context, Str: [*]const u8, Length: c_uint, DontNullTerminate: LLVMBool) *const Value;
2629
30 pub const constStruct = LLVMConstStructInContext;
31 extern fn LLVMConstStructInContext(C: *const Context, ConstantVals: [*]*const Value, Count: c_uint, Packed: LLVMBool) *const Value;
32
27 pub const createBasicBlock = LLVMCreateBasicBlockInContext;33 pub const createBasicBlock = LLVMCreateBasicBlockInContext;
28 extern fn LLVMCreateBasicBlockInContext(C: *const Context, Name: [*:0]const u8) *const BasicBlock;34 extern fn LLVMCreateBasicBlockInContext(C: *const Context, Name: [*:0]const u8) *const BasicBlock;
2935
...@@ -204,6 +210,9 @@ pub const Builder = opaque {...@@ -204,6 +210,9 @@ pub const Builder = opaque {
204210
205 pub const buildPhi = LLVMBuildPhi;211 pub const buildPhi = LLVMBuildPhi;
206 extern fn LLVMBuildPhi(*const Builder, Ty: *const Type, Name: [*:0]const u8) *const Value;212 extern fn LLVMBuildPhi(*const Builder, Ty: *const Type, Name: [*:0]const u8) *const Value;
213
214 pub const buildExtractValue = LLVMBuildExtractValue;
215 extern fn LLVMBuildExtractValue(*const Builder, AggVal: *const Value, Index: c_uint, Name: [*:0]const u8) *const Value;
207};216};
208217
209pub const IntPredicate = extern enum {218pub const IntPredicate = extern enum {
src/ir.zig+2
...@@ -106,6 +106,7 @@ pub const Inst = struct {...@@ -106,6 +106,7 @@ pub const Inst = struct {
106 store,106 store,
107 sub,107 sub,
108 unreach,108 unreach,
109 mul,
109 not,110 not,
110 floatcast,111 floatcast,
111 intcast,112 intcast,
...@@ -165,6 +166,7 @@ pub const Inst = struct {...@@ -165,6 +166,7 @@ pub const Inst = struct {
165166
166 .add,167 .add,
167 .sub,168 .sub,
169 .mul,
168 .cmp_lt,170 .cmp_lt,
169 .cmp_lte,171 .cmp_lte,
170 .cmp_eq,172 .cmp_eq,
src/link.zig+2-2
...@@ -550,11 +550,11 @@ pub const File = struct {...@@ -550,11 +550,11 @@ pub const File = struct {
550 id_symlink_basename,550 id_symlink_basename,
551 &prev_digest_buf,551 &prev_digest_buf,
552 ) catch |err| b: {552 ) catch |err| b: {
553 log.debug("archive new_digest={x} readFile error: {s}", .{ digest, @errorName(err) });553 log.debug("archive new_digest={s} readFile error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) });
554 break :b prev_digest_buf[0..0];554 break :b prev_digest_buf[0..0];
555 };555 };
556 if (mem.eql(u8, prev_digest, &digest)) {556 if (mem.eql(u8, prev_digest, &digest)) {
557 log.debug("archive digest={x} match - skipping invocation", .{digest});557 log.debug("archive digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)});
558 base.lock = man.toOwnedLock();558 base.lock = man.toOwnedLock();
559 return;559 return;
560 }560 }
src/link/Coff.zig+3-3
...@@ -892,17 +892,17 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {...@@ -892,17 +892,17 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
892 id_symlink_basename,892 id_symlink_basename,
893 &prev_digest_buf,893 &prev_digest_buf,
894 ) catch |err| blk: {894 ) catch |err| blk: {
895 log.debug("COFF LLD new_digest={x} error: {s}", .{ digest, @errorName(err) });895 log.debug("COFF LLD new_digest={s} error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) });
896 // Handle this as a cache miss.896 // Handle this as a cache miss.
897 break :blk prev_digest_buf[0..0];897 break :blk prev_digest_buf[0..0];
898 };898 };
899 if (mem.eql(u8, prev_digest, &digest)) {899 if (mem.eql(u8, prev_digest, &digest)) {
900 log.debug("COFF LLD digest={x} match - skipping invocation", .{digest});900 log.debug("COFF LLD digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)});
901 // Hot diggity dog! The output binary is already there.901 // Hot diggity dog! The output binary is already there.
902 self.base.lock = man.toOwnedLock();902 self.base.lock = man.toOwnedLock();
903 return;903 return;
904 }904 }
905 log.debug("COFF LLD prev_digest={x} new_digest={x}", .{ prev_digest, digest });905 log.debug("COFF LLD prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) });
906906
907 // We are about to change the output file to be different, so we invalidate the build hash now.907 // We are about to change the output file to be different, so we invalidate the build hash now.
908 directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {908 directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {
src/link/Elf.zig+3-3
...@@ -1365,17 +1365,17 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {...@@ -1365,17 +1365,17 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
1365 id_symlink_basename,1365 id_symlink_basename,
1366 &prev_digest_buf,1366 &prev_digest_buf,
1367 ) catch |err| blk: {1367 ) catch |err| blk: {
1368 log.debug("ELF LLD new_digest={x} error: {s}", .{ digest, @errorName(err) });1368 log.debug("ELF LLD new_digest={s} error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) });
1369 // Handle this as a cache miss.1369 // Handle this as a cache miss.
1370 break :blk prev_digest_buf[0..0];1370 break :blk prev_digest_buf[0..0];
1371 };1371 };
1372 if (mem.eql(u8, prev_digest, &digest)) {1372 if (mem.eql(u8, prev_digest, &digest)) {
1373 log.debug("ELF LLD digest={x} match - skipping invocation", .{digest});1373 log.debug("ELF LLD digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)});
1374 // Hot diggity dog! The output binary is already there.1374 // Hot diggity dog! The output binary is already there.
1375 self.base.lock = man.toOwnedLock();1375 self.base.lock = man.toOwnedLock();
1376 return;1376 return;
1377 }1377 }
1378 log.debug("ELF LLD prev_digest={x} new_digest={x}", .{ prev_digest, digest });1378 log.debug("ELF LLD prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) });
13791379
1380 // We are about to change the output file to be different, so we invalidate the build hash now.1380 // We are about to change the output file to be different, so we invalidate the build hash now.
1381 directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {1381 directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {
src/link/MachO.zig+3-3
...@@ -556,17 +556,17 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -556,17 +556,17 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
556 id_symlink_basename,556 id_symlink_basename,
557 &prev_digest_buf,557 &prev_digest_buf,
558 ) catch |err| blk: {558 ) catch |err| blk: {
559 log.debug("MachO LLD new_digest={x} error: {s}", .{ digest, @errorName(err) });559 log.debug("MachO LLD new_digest={s} error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) });
560 // Handle this as a cache miss.560 // Handle this as a cache miss.
561 break :blk prev_digest_buf[0..0];561 break :blk prev_digest_buf[0..0];
562 };562 };
563 if (mem.eql(u8, prev_digest, &digest)) {563 if (mem.eql(u8, prev_digest, &digest)) {
564 log.debug("MachO LLD digest={x} match - skipping invocation", .{digest});564 log.debug("MachO LLD digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)});
565 // Hot diggity dog! The output binary is already there.565 // Hot diggity dog! The output binary is already there.
566 self.base.lock = man.toOwnedLock();566 self.base.lock = man.toOwnedLock();
567 return;567 return;
568 }568 }
569 log.debug("MachO LLD prev_digest={x} new_digest={x}", .{ prev_digest, digest });569 log.debug("MachO LLD prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) });
570570
571 // We are about to change the output file to be different, so we invalidate the build hash now.571 // We are about to change the output file to be different, so we invalidate the build hash now.
572 directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {572 directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {
src/link/Wasm.zig+3-3
...@@ -391,17 +391,17 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {...@@ -391,17 +391,17 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
391 id_symlink_basename,391 id_symlink_basename,
392 &prev_digest_buf,392 &prev_digest_buf,
393 ) catch |err| blk: {393 ) catch |err| blk: {
394 log.debug("WASM LLD new_digest={x} error: {s}", .{ digest, @errorName(err) });394 log.debug("WASM LLD new_digest={s} error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) });
395 // Handle this as a cache miss.395 // Handle this as a cache miss.
396 break :blk prev_digest_buf[0..0];396 break :blk prev_digest_buf[0..0];
397 };397 };
398 if (mem.eql(u8, prev_digest, &digest)) {398 if (mem.eql(u8, prev_digest, &digest)) {
399 log.debug("WASM LLD digest={x} match - skipping invocation", .{digest});399 log.debug("WASM LLD digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)});
400 // Hot diggity dog! The output binary is already there.400 // Hot diggity dog! The output binary is already there.
401 self.base.lock = man.toOwnedLock();401 self.base.lock = man.toOwnedLock();
402 return;402 return;
403 }403 }
404 log.debug("WASM LLD prev_digest={x} new_digest={x}", .{ prev_digest, digest });404 log.debug("WASM LLD prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) });
405405
406 // We are about to change the output file to be different, so we invalidate the build hash now.406 // We are about to change the output file to be different, so we invalidate the build hash now.
407 directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {407 directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {
src/main.zig+18-2
...@@ -448,6 +448,15 @@ const Emit = union(enum) {...@@ -448,6 +448,15 @@ const Emit = union(enum) {
448 }448 }
449};449};
450450
451fn optionalBoolEnvVar(arena: *Allocator, name: []const u8) !bool {
452 if (std.process.getEnvVarOwned(arena, name)) |value| {
453 return true;
454 } else |err| switch (err) {
455 error.EnvironmentVariableNotFound => return false,
456 else => |e| return e,
457 }
458}
459
451fn optionalStringEnvVar(arena: *Allocator, name: []const u8) !?[]const u8 {460fn optionalStringEnvVar(arena: *Allocator, name: []const u8) !?[]const u8 {
452 if (std.process.getEnvVarOwned(arena, name)) |value| {461 if (std.process.getEnvVarOwned(arena, name)) |value| {
453 return value;462 return value;
...@@ -482,8 +491,8 @@ fn buildOutputType(...@@ -482,8 +491,8 @@ fn buildOutputType(
482 var single_threaded = false;491 var single_threaded = false;
483 var function_sections = false;492 var function_sections = false;
484 var watch = false;493 var watch = false;
485 var verbose_link = false;494 var verbose_link = try optionalBoolEnvVar(arena, "ZIG_VERBOSE_LINK");
486 var verbose_cc = false;495 var verbose_cc = try optionalBoolEnvVar(arena, "ZIG_VERBOSE_CC");
487 var verbose_tokenize = false;496 var verbose_tokenize = false;
488 var verbose_ast = false;497 var verbose_ast = false;
489 var verbose_ir = false;498 var verbose_ir = false;
...@@ -1183,6 +1192,12 @@ fn buildOutputType(...@@ -1183,6 +1192,12 @@ fn buildOutputType(
1183 disable_c_depfile = true;1192 disable_c_depfile = true;
1184 try clang_argv.appendSlice(it.other_args);1193 try clang_argv.appendSlice(it.other_args);
1185 },1194 },
1195 .dep_file_mm => { // -MM
1196 // "Like -MMD, but also implies -E and writes to stdout by default"
1197 c_out_mode = .preprocessor;
1198 disable_c_depfile = true;
1199 try clang_argv.appendSlice(it.other_args);
1200 },
1186 .framework_dir => try framework_dirs.append(it.only_arg),1201 .framework_dir => try framework_dirs.append(it.only_arg),
1187 .framework => try frameworks.append(it.only_arg),1202 .framework => try frameworks.append(it.only_arg),
1188 .nostdlibinc => want_native_include_dirs = false,1203 .nostdlibinc => want_native_include_dirs = false,
...@@ -3046,6 +3061,7 @@ pub const ClangArgIterator = struct {...@@ -3046,6 +3061,7 @@ pub const ClangArgIterator = struct {
3046 lib_dir,3061 lib_dir,
3047 mcpu,3062 mcpu,
3048 dep_file,3063 dep_file,
3064 dep_file_mm,
3049 framework_dir,3065 framework_dir,
3050 framework,3066 framework,
3051 nostdlibinc,3067 nostdlibinc,
src/stage1/codegen.cpp+9-1
...@@ -4126,7 +4126,15 @@ static LLVMValueRef gen_frame_size(CodeGen *g, LLVMValueRef fn_val) {...@@ -4126,7 +4126,15 @@ static LLVMValueRef gen_frame_size(CodeGen *g, LLVMValueRef fn_val) {
4126 LLVMValueRef casted_fn_val = LLVMBuildBitCast(g->builder, fn_val, ptr_usize_llvm_type, "");4126 LLVMValueRef casted_fn_val = LLVMBuildBitCast(g->builder, fn_val, ptr_usize_llvm_type, "");
4127 LLVMValueRef negative_one = LLVMConstInt(LLVMInt32Type(), -1, true);4127 LLVMValueRef negative_one = LLVMConstInt(LLVMInt32Type(), -1, true);
4128 LLVMValueRef prefix_ptr = LLVMBuildInBoundsGEP(g->builder, casted_fn_val, &negative_one, 1, "");4128 LLVMValueRef prefix_ptr = LLVMBuildInBoundsGEP(g->builder, casted_fn_val, &negative_one, 1, "");
4129 return LLVMBuildLoad(g->builder, prefix_ptr, "");4129 LLVMValueRef load_inst = LLVMBuildLoad(g->builder, prefix_ptr, "");
4130
4131 // Some architectures (e.g SPARCv9) has different alignment requirements between a
4132 // function/usize pointer and also require all loads to be aligned.
4133 // On those architectures, not explicitly setting the alignment will lead into @frameSize
4134 // generating usize-aligned load instruction that could crash if the function pointer
4135 // happens to be not usize-aligned.
4136 LLVMSetAlignment(load_inst, 1);
4137 return load_inst;
4130}4138}
41314139
4132static void gen_init_stack_trace(CodeGen *g, LLVMValueRef trace_field_ptr, LLVMValueRef addrs_field_ptr) {4140static void gen_init_stack_trace(CodeGen *g, LLVMValueRef trace_field_ptr, LLVMValueRef addrs_field_ptr) {
src/test.zig+2-2
...@@ -1030,8 +1030,8 @@ pub const TestContext = struct {...@@ -1030,8 +1030,8 @@ pub const TestContext = struct {
1030 var file = try tmp_dir.openFile(bin_name, .{ .read = true });1030 var file = try tmp_dir.openFile(bin_name, .{ .read = true });
1031 defer file.close();1031 defer file.close();
10321032
1033 const header = try std.elf.readHeader(file);1033 const header = try std.elf.Header.read(&file);
1034 var iterator = header.program_header_iterator(file);1034 var iterator = header.program_header_iterator(&file);
10351035
1036 var none_loaded = true;1036 var none_loaded = true;
10371037
src/translate_c.zig+1-1
...@@ -4608,7 +4608,7 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N...@@ -4608,7 +4608,7 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
4608 if (slice[0] != '\'' or slice[1] == '\\' or slice.len == 3) {4608 if (slice[0] != '\'' or slice[1] == '\\' or slice.len == 3) {
4609 return Tag.char_literal.create(c.arena, try zigifyEscapeSequences(c, m));4609 return Tag.char_literal.create(c.arena, try zigifyEscapeSequences(c, m));
4610 } else {4610 } else {
4611 const str = try std.fmt.allocPrint(c.arena, "0x{x}", .{slice[1 .. slice.len - 1]});4611 const str = try std.fmt.allocPrint(c.arena, "0x{s}", .{std.fmt.fmtSliceHexLower(slice[1 .. slice.len - 1])});
4612 return Tag.integer_literal.create(c.arena, str);4612 return Tag.integer_literal.create(c.arena, str);
4613 }4613 }
4614 },4614 },
src/value.zig+1-1
...@@ -2144,7 +2144,7 @@ pub const Value = extern union {...@@ -2144,7 +2144,7 @@ pub const Value = extern union {
2144 base: Payload = .{ .tag = base_tag },2144 base: Payload = .{ .tag = base_tag },
2145 data: struct {2145 data: struct {
2146 /// TODO revisit this when we have the concept of the error tag type2146 /// TODO revisit this when we have the concept of the error tag type
2147 fields: std.StringHashMapUnmanaged(u16),2147 fields: std.StringHashMapUnmanaged(void),
2148 decl: *Module.Decl,2148 decl: *Module.Decl,
2149 },2149 },
2150 };2150 };
src/zir.zig+7
...@@ -299,6 +299,9 @@ pub const Inst = struct {...@@ -299,6 +299,9 @@ pub const Inst = struct {
299 xor,299 xor,
300 /// Create an optional type '?T'300 /// Create an optional type '?T'
301 optional_type,301 optional_type,
302 /// Create an optional type '?T'. The operand is a pointer value. The optional type will
303 /// be the type of the pointer element, wrapped in an optional.
304 optional_type_from_ptr_elem,
302 /// Create a union type.305 /// Create a union type.
303 union_type,306 union_type,
304 /// ?T => T with safety.307 /// ?T => T with safety.
...@@ -397,6 +400,7 @@ pub const Inst = struct {...@@ -397,6 +400,7 @@ pub const Inst = struct {
397 .mut_slice_type,400 .mut_slice_type,
398 .const_slice_type,401 .const_slice_type,
399 .optional_type,402 .optional_type,
403 .optional_type_from_ptr_elem,
400 .optional_payload_safe,404 .optional_payload_safe,
401 .optional_payload_unsafe,405 .optional_payload_unsafe,
402 .optional_payload_safe_ptr,406 .optional_payload_safe_ptr,
...@@ -597,6 +601,7 @@ pub const Inst = struct {...@@ -597,6 +601,7 @@ pub const Inst = struct {
597 .typeof,601 .typeof,
598 .xor,602 .xor,
599 .optional_type,603 .optional_type,
604 .optional_type_from_ptr_elem,
600 .optional_payload_safe,605 .optional_payload_safe,
601 .optional_payload_unsafe,606 .optional_payload_unsafe,
602 .optional_payload_safe_ptr,607 .optional_payload_safe_ptr,
...@@ -1649,6 +1654,7 @@ const DumpTzir = struct {...@@ -1649,6 +1654,7 @@ const DumpTzir = struct {
16491654
1650 .add,1655 .add,
1651 .sub,1656 .sub,
1657 .mul,
1652 .cmp_lt,1658 .cmp_lt,
1653 .cmp_lte,1659 .cmp_lte,
1654 .cmp_eq,1660 .cmp_eq,
...@@ -1771,6 +1777,7 @@ const DumpTzir = struct {...@@ -1771,6 +1777,7 @@ const DumpTzir = struct {
17711777
1772 .add,1778 .add,
1773 .sub,1779 .sub,
1780 .mul,
1774 .cmp_lt,1781 .cmp_lt,
1775 .cmp_lte,1782 .cmp_lte,
1776 .cmp_eq,1783 .cmp_eq,
src/zir_sema.zig+86-2
...@@ -131,6 +131,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!...@@ -131,6 +131,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
131 .typeof => return zirTypeof(mod, scope, old_inst.castTag(.typeof).?),131 .typeof => return zirTypeof(mod, scope, old_inst.castTag(.typeof).?),
132 .typeof_peer => return zirTypeofPeer(mod, scope, old_inst.castTag(.typeof_peer).?),132 .typeof_peer => return zirTypeofPeer(mod, scope, old_inst.castTag(.typeof_peer).?),
133 .optional_type => return zirOptionalType(mod, scope, old_inst.castTag(.optional_type).?),133 .optional_type => return zirOptionalType(mod, scope, old_inst.castTag(.optional_type).?),
134 .optional_type_from_ptr_elem => return zirOptionalTypeFromPtrElem(mod, scope, old_inst.castTag(.optional_type_from_ptr_elem).?),
134 .optional_payload_safe => return zirOptionalPayload(mod, scope, old_inst.castTag(.optional_payload_safe).?, true),135 .optional_payload_safe => return zirOptionalPayload(mod, scope, old_inst.castTag(.optional_payload_safe).?, true),
135 .optional_payload_unsafe => return zirOptionalPayload(mod, scope, old_inst.castTag(.optional_payload_unsafe).?, false),136 .optional_payload_unsafe => return zirOptionalPayload(mod, scope, old_inst.castTag(.optional_payload_unsafe).?, false),
136 .optional_payload_safe_ptr => return zirOptionalPayloadPtr(mod, scope, old_inst.castTag(.optional_payload_safe_ptr).?, true),137 .optional_payload_safe_ptr => return zirOptionalPayloadPtr(mod, scope, old_inst.castTag(.optional_payload_safe_ptr).?, true),
...@@ -1093,6 +1094,16 @@ fn zirOptionalType(mod: *Module, scope: *Scope, optional: *zir.Inst.UnOp) InnerE...@@ -1093,6 +1094,16 @@ fn zirOptionalType(mod: *Module, scope: *Scope, optional: *zir.Inst.UnOp) InnerE
1093 return mod.constType(scope, optional.base.src, try mod.optionalType(scope, child_type));1094 return mod.constType(scope, optional.base.src, try mod.optionalType(scope, child_type));
1094}1095}
10951096
1097fn zirOptionalTypeFromPtrElem(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
1098 const tracy = trace(@src());
1099 defer tracy.end();
1100
1101 const ptr = try resolveInst(mod, scope, inst.positionals.operand);
1102 const elem_ty = ptr.ty.elemType();
1103
1104 return mod.constType(scope, inst.base.src, try mod.optionalType(scope, elem_ty));
1105}
1106
1096fn zirArrayType(mod: *Module, scope: *Scope, array: *zir.Inst.BinOp) InnerError!*Inst {1107fn zirArrayType(mod: *Module, scope: *Scope, array: *zir.Inst.BinOp) InnerError!*Inst {
1097 const tracy = trace(@src());1108 const tracy = trace(@src());
1098 defer tracy.end();1109 defer tracy.end();
...@@ -1154,7 +1165,7 @@ fn zirErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) InnerError...@@ -1154,7 +1165,7 @@ fn zirErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) InnerError
11541165
1155 for (inst.positionals.fields) |field_name| {1166 for (inst.positionals.fields) |field_name| {
1156 const entry = try mod.getErrorValue(field_name);1167 const entry = try mod.getErrorValue(field_name);
1157 if (payload.data.fields.fetchPutAssumeCapacity(entry.key, entry.value)) |prev| {1168 if (payload.data.fields.fetchPutAssumeCapacity(entry.key, {})) |_| {
1158 return mod.fail(scope, inst.base.src, "duplicate error: '{s}'", .{field_name});1169 return mod.fail(scope, inst.base.src, "duplicate error: '{s}'", .{field_name});
1159 }1170 }
1160 }1171 }
...@@ -1185,7 +1196,79 @@ fn zirErrorValue(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorValue) InnerE...@@ -1185,7 +1196,79 @@ fn zirErrorValue(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorValue) InnerE
1185fn zirMergeErrorSets(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {1196fn zirMergeErrorSets(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
1186 const tracy = trace(@src());1197 const tracy = trace(@src());
1187 defer tracy.end();1198 defer tracy.end();
1188 return mod.fail(scope, inst.base.src, "TODO implement merge_error_sets", .{});1199
1200 const rhs_ty = try resolveType(mod, scope, inst.positionals.rhs);
1201 const lhs_ty = try resolveType(mod, scope, inst.positionals.lhs);
1202 if (rhs_ty.zigTypeTag() != .ErrorSet)
1203 return mod.fail(scope, inst.positionals.rhs.src, "expected error set type, found {}", .{rhs_ty});
1204 if (lhs_ty.zigTypeTag() != .ErrorSet)
1205 return mod.fail(scope, inst.positionals.lhs.src, "expected error set type, found {}", .{lhs_ty});
1206
1207 // anything merged with anyerror is anyerror
1208 if (lhs_ty.tag() == .anyerror or rhs_ty.tag() == .anyerror)
1209 return mod.constInst(scope, inst.base.src, .{
1210 .ty = Type.initTag(.type),
1211 .val = Value.initTag(.anyerror_type),
1212 });
1213 // The declarations arena will store the hashmap.
1214 var new_decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
1215 errdefer new_decl_arena.deinit();
1216
1217 const payload = try new_decl_arena.allocator.create(Value.Payload.ErrorSet);
1218 payload.* = .{
1219 .base = .{ .tag = .error_set },
1220 .data = .{
1221 .fields = .{},
1222 .decl = undefined, // populated below
1223 },
1224 };
1225 try payload.data.fields.ensureCapacity(&new_decl_arena.allocator, @intCast(u32, switch (rhs_ty.tag()) {
1226 .error_set_single => 1,
1227 .error_set => rhs_ty.castTag(.error_set).?.data.typed_value.most_recent.typed_value.val.castTag(.error_set).?.data.fields.size,
1228 else => unreachable,
1229 } + switch (lhs_ty.tag()) {
1230 .error_set_single => 1,
1231 .error_set => lhs_ty.castTag(.error_set).?.data.typed_value.most_recent.typed_value.val.castTag(.error_set).?.data.fields.size,
1232 else => unreachable,
1233 }));
1234
1235 switch (lhs_ty.tag()) {
1236 .error_set_single => {
1237 const name = lhs_ty.castTag(.error_set_single).?.data;
1238 payload.data.fields.putAssumeCapacity(name, {});
1239 },
1240 .error_set => {
1241 var multiple = lhs_ty.castTag(.error_set).?.data.typed_value.most_recent.typed_value.val.castTag(.error_set).?.data.fields;
1242 var it = multiple.iterator();
1243 while (it.next()) |entry| {
1244 payload.data.fields.putAssumeCapacity(entry.key, entry.value);
1245 }
1246 },
1247 else => unreachable,
1248 }
1249
1250 switch (rhs_ty.tag()) {
1251 .error_set_single => {
1252 const name = rhs_ty.castTag(.error_set_single).?.data;
1253 payload.data.fields.putAssumeCapacity(name, {});
1254 },
1255 .error_set => {
1256 var multiple = rhs_ty.castTag(.error_set).?.data.typed_value.most_recent.typed_value.val.castTag(.error_set).?.data.fields;
1257 var it = multiple.iterator();
1258 while (it.next()) |entry| {
1259 payload.data.fields.putAssumeCapacity(entry.key, entry.value);
1260 }
1261 },
1262 else => unreachable,
1263 }
1264 // TODO create name in format "error:line:column"
1265 const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
1266 .ty = Type.initTag(.type),
1267 .val = Value.initPayload(&payload.base),
1268 });
1269 payload.data.decl = new_decl;
1270
1271 return mod.analyzeDeclVal(scope, inst.base.src, new_decl);
1189}1272}
11901273
1191fn zirEnumLiteral(mod: *Module, scope: *Scope, inst: *zir.Inst.EnumLiteral) InnerError!*Inst {1274fn zirEnumLiteral(mod: *Module, scope: *Scope, inst: *zir.Inst.EnumLiteral) InnerError!*Inst {
...@@ -2075,6 +2158,7 @@ fn zirArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!...@@ -2075,6 +2158,7 @@ fn zirArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!
2075 const ir_tag = switch (inst.base.tag) {2158 const ir_tag = switch (inst.base.tag) {
2076 .add => Inst.Tag.add,2159 .add => Inst.Tag.add,
2077 .sub => Inst.Tag.sub,2160 .sub => Inst.Tag.sub,
2161 .mul => Inst.Tag.mul,
2078 else => return mod.fail(scope, inst.base.src, "TODO implement arithmetic for operand '{s}''", .{@tagName(inst.base.tag)}),2162 else => return mod.fail(scope, inst.base.src, "TODO implement arithmetic for operand '{s}''", .{@tagName(inst.base.tag)}),
2079 };2163 };
20802164
test/run_translated_c.zig+2
...@@ -27,6 +27,8 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {...@@ -27,6 +27,8 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
27 \\#define FOO =27 \\#define FOO =
28 \\#define PtrToPtr64(p) ((void *POINTER_64) p)28 \\#define PtrToPtr64(p) ((void *POINTER_64) p)
29 \\#define STRUC_ALIGNED_STACK_COPY(t,s) ((CONST t *)(s))29 \\#define STRUC_ALIGNED_STACK_COPY(t,s) ((CONST t *)(s))
30 \\#define bar = 0x
31 \\#define baz = 0b
30 \\int main(void) {}32 \\int main(void) {}
31 , "");33 , "");
3234
test/stage1/behavior.zig+1-1
...@@ -141,5 +141,5 @@ comptime {...@@ -141,5 +141,5 @@ comptime {
141 _ = @import("behavior/while.zig");141 _ = @import("behavior/while.zig");
142 _ = @import("behavior/widening.zig");142 _ = @import("behavior/widening.zig");
143 _ = @import("behavior/src.zig");143 _ = @import("behavior/src.zig");
144 // _ = @import("behavior/translate_c_macros.zig");144 _ = @import("behavior/translate_c_macros.zig");
145}145}
test/stage2/arm.zig+34
...@@ -344,4 +344,38 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -344,4 +344,38 @@ pub fn addCases(ctx: *TestContext) !void {
344 "",344 "",
345 );345 );
346 }346 }
347
348 {
349 var case = ctx.exe("integer multiplication", linux_arm);
350 // Simple u32 integer multiplication
351 case.addCompareOutput(
352 \\export fn _start() noreturn {
353 \\ assert(mul(1, 1) == 1);
354 \\ assert(mul(42, 1) == 42);
355 \\ assert(mul(1, 42) == 42);
356 \\ assert(mul(123, 42) == 5166);
357 \\ exit();
358 \\}
359 \\
360 \\fn mul(x: u32, y: u32) u32 {
361 \\ return x * y;
362 \\}
363 \\
364 \\fn assert(ok: bool) void {
365 \\ if (!ok) unreachable;
366 \\}
367 \\
368 \\fn exit() noreturn {
369 \\ asm volatile ("svc #0"
370 \\ :
371 \\ : [number] "{r7}" (1),
372 \\ [arg1] "{r0}" (0)
373 \\ : "memory"
374 \\ );
375 \\ unreachable;
376 \\}
377 ,
378 "",
379 );
380 }
347}381}
test/stage2/llvm.zig+68
...@@ -132,4 +132,72 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -132,4 +132,72 @@ pub fn addCases(ctx: *TestContext) !void {
132 \\}132 \\}
133 , "");133 , "");
134 }134 }
135
136 {
137 var case = ctx.exeUsingLlvmBackend("optionals", linux_x64);
138
139 case.addCompareOutput(
140 \\fn assert(ok: bool) void {
141 \\ if (!ok) unreachable;
142 \\}
143 \\
144 \\export fn main() c_int {
145 \\ var opt_val: ?i32 = 10;
146 \\ var null_val: ?i32 = null;
147 \\
148 \\ var val1: i32 = opt_val.?;
149 \\ const val1_1: i32 = opt_val.?;
150 \\ var ptr_val1 = &(opt_val.?);
151 \\ const ptr_val1_1 = &(opt_val.?);
152 \\
153 \\ var val2: i32 = null_val orelse 20;
154 \\ const val2_2: i32 = null_val orelse 20;
155 \\
156 \\ var value: i32 = 20;
157 \\ var ptr_val2 = &(null_val orelse value);
158 \\
159 \\ const val3 = opt_val orelse 30;
160 \\ var val3_var = opt_val orelse 30;
161 \\
162 \\ assert(val1 == 10);
163 \\ assert(val1_1 == 10);
164 \\ assert(ptr_val1.* == 10);
165 \\ assert(ptr_val1_1.* == 10);
166 \\
167 \\ assert(val2 == 20);
168 \\ assert(val2_2 == 20);
169 \\ assert(ptr_val2.* == 20);
170 \\
171 \\ assert(val3 == 10);
172 \\ assert(val3_var == 10);
173 \\
174 \\ (null_val orelse val2) = 1234;
175 \\ assert(val2 == 1234);
176 \\
177 \\ (opt_val orelse val2) = 5678;
178 \\ assert(opt_val.? == 5678);
179 \\
180 \\ return 0;
181 \\}
182 , "");
183 }
184
185 {
186 var case = ctx.exeUsingLlvmBackend("for loop", linux_x64);
187
188 case.addCompareOutput(
189 \\fn assert(ok: bool) void {
190 \\ if (!ok) unreachable;
191 \\}
192 \\
193 \\export fn main() c_int {
194 \\ var x: u32 = 0;
195 \\ for ("hello") |_| {
196 \\ x += 1;
197 \\ }
198 \\ assert("hello".len == x);
199 \\ return 0;
200 \\}
201 , "");
202 }
135}203}
test/stage2/test.zig+34-1
...@@ -985,7 +985,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -985,7 +985,7 @@ pub fn addCases(ctx: *TestContext) !void {
985 "Hello, World!\n",985 "Hello, World!\n",
986 );986 );
987 try case.files.append(.{987 try case.files.append(.{
988 .src =988 .src =
989 \\pub fn print() void {989 \\pub fn print() void {
990 \\ asm volatile ("syscall"990 \\ asm volatile ("syscall"
991 \\ :991 \\ :
...@@ -1525,4 +1525,37 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1525,4 +1525,37 @@ pub fn addCases(ctx: *TestContext) !void {
1525 \\}1525 \\}
1526 , "");1526 , "");
1527 }1527 }
1528 {
1529 var case = ctx.exe("merge error sets", linux_x64);
1530
1531 case.addCompareOutput(
1532 \\export fn _start() noreturn {
1533 \\ const E = error{ A, B, D } || error { A, B, C };
1534 \\ const a = E.A;
1535 \\ const b = E.B;
1536 \\ const c = E.C;
1537 \\ const d = E.D;
1538 \\ const E2 = error { X, Y } || @TypeOf(error.Z);
1539 \\ const x = E2.X;
1540 \\ const y = E2.Y;
1541 \\ const z = E2.Z;
1542 \\ assert(anyerror || error { Z } == anyerror);
1543 \\ exit();
1544 \\}
1545 \\fn assert(b: bool) void {
1546 \\ if (!b) unreachable;
1547 \\}
1548 \\fn exit() noreturn {
1549 \\ asm volatile ("syscall"
1550 \\ :
1551 \\ : [number] "{rax}" (231),
1552 \\ [arg1] "{rdi}" (0)
1553 \\ : "rcx", "r11", "memory"
1554 \\ );
1555 \\ unreachable;
1556 \\}
1557 ,
1558 "",
1559 );
1560 }
1528}1561}
tools/update_clang_options.zig+17-1
...@@ -268,6 +268,10 @@ const known_options = [_]KnownOpt{...@@ -268,6 +268,10 @@ const known_options = [_]KnownOpt{
268 .name = "MD",268 .name = "MD",
269 .ident = "dep_file",269 .ident = "dep_file",
270 },270 },
271 .{
272 .name = "write-dependencies",
273 .ident = "dep_file",
274 },
271 .{275 .{
272 .name = "MV",276 .name = "MV",
273 .ident = "dep_file",277 .ident = "dep_file",
...@@ -284,18 +288,30 @@ const known_options = [_]KnownOpt{...@@ -284,18 +288,30 @@ const known_options = [_]KnownOpt{
284 .name = "MG",288 .name = "MG",
285 .ident = "dep_file",289 .ident = "dep_file",
286 },290 },
291 .{
292 .name = "print-missing-file-dependencies",
293 .ident = "dep_file",
294 },
287 .{295 .{
288 .name = "MJ",296 .name = "MJ",
289 .ident = "dep_file",297 .ident = "dep_file",
290 },298 },
291 .{299 .{
292 .name = "MM",300 .name = "MM",
293 .ident = "dep_file",301 .ident = "dep_file_mm",
302 },
303 .{
304 .name = "user-dependencies",
305 .ident = "dep_file_mm",
294 },306 },
295 .{307 .{
296 .name = "MMD",308 .name = "MMD",
297 .ident = "dep_file",309 .ident = "dep_file",
298 },310 },
311 .{
312 .name = "write-user-dependencies",
313 .ident = "dep_file",
314 },
299 .{315 .{
300 .name = "MP",316 .name = "MP",
301 .ident = "dep_file",317 .ident = "dep_file",