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()
801801
802802install(TARGETS zig DESTINATION bin)
803803
804set(ZIG_INSTALL_ARGS "build"
805 --override-lib-dir "${CMAKE_SOURCE_DIR}/lib"
806 "-Dlib-files-only"
807 --prefix "${CMAKE_INSTALL_PREFIX}"
808 "-Dconfig_h=${ZIG_CONFIG_H_OUT}"
809 install
810)
804set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL
805 "Disable copying lib/ files to install prefix during the build phase")
806
807if(NOT ZIG_SKIP_INSTALL_LIB_FILES)
808 set(ZIG_INSTALL_ARGS "build"
809 --override-lib-dir "${CMAKE_SOURCE_DIR}/lib"
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, therefore
813# when using Visual Studio build system generator we resort to running
814# `zig build install` during the build phase.
815if(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)
816 # CODE has no effect with Visual Studio build system generator, therefore
817 # when using Visual Studio build system generator we resort to running
818 # `zig build install` during the build phase.
819 if(MSVC)
819820 add_custom_target(zig_install_lib_files ALL
820821 COMMAND zig ${ZIG_INSTALL_ARGS}
821822 DEPENDS zig
822823 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
823824 )
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)
824831 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)
831832endif()
doc/langref.html.in+51-23
......@@ -10447,13 +10447,40 @@ fn readU32Be() u32 {}
1044710447 {#header_close#}
1044810448 {#header_open|Source Encoding#}
1044910449 <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>
1045110451 <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>
1045310453 <li>Non-Ascii Unicode line endings: U+0085 (NEL), U+2028 (LS), U+2029 (PS).</li>
1045410454 </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>
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>
10455 <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>
1045710484 {#header_close#}
1045810485
1045910486 {#header_open|Keyword Reference#}
......@@ -11373,6 +11400,7 @@ ExprList &lt;- (Expr COMMA)* Expr?
1137311400
1137411401# *** Tokens ***
1137511402eof &lt;- !.
11403eol &lt;- ('\r'? '\n') | eof
1137611404hex &lt;- [0-9a-fA-F]
1137711405hex_ &lt;- ('_'/hex)
1137811406dec &lt;- [0-9]
......@@ -11382,39 +11410,39 @@ dec_int &lt;- dec (dec_* dec)?
1138211410hex_int &lt;- hex (hex_* dec)?
1138311411
1138411412char_escape
11385 &lt;- &quot;\\x&quot; hex hex
11386 / &quot;\\u{&quot; hex+ &quot;}&quot;
11387 / &quot;\\&quot; [nr\\t'&quot;]
11413 &lt;- '\\x' hex hex
11414 / '\\u{' hex+ '}'
11415 / '\\' [nr\\t'&quot;]
1138811416char_char
1138911417 &lt;- char_escape
11390 / [^\\'\n]
11418 / [^\\'\r\n]
1139111419string_char
1139211420 &lt;- char_escape
11393 / [^\\&quot;\n]
11421 / [^\\&quot;\r\n]
1139411422
11395line_comment &lt;- '//'[^\n]*
11396line_string &lt;- (&quot;\\\\&quot; [^\n]* [ \n]*)+
11397skip &lt;- ([ \n] / line_comment)*
11423line_comment &lt;- '//'[^\r\n]* eol
11424line_string &lt;- ('\\\\' [^\r\n]* eol skip)+
11425skip &lt;- ([ \t] / eol / line_comment)*
1139811426
1139911427CHAR_LITERAL &lt;- &quot;'&quot; char_char &quot;'&quot; skip
1140011428FLOAT
11401 &lt;- &quot;0x&quot; hex_* hex &quot;.&quot; hex_int ([pP] [-+]? hex_int)? skip
11402 / dec_int &quot;.&quot; dec_int ([eE] [-+]? dec_int)? skip
11403 / &quot;0x&quot; hex_* hex &quot;.&quot;? [pP] [-+]? hex_int skip
11404 / dec_int &quot;.&quot;? [eE] [-+]? dec_int skip
11429 &lt;- '0x' hex_* hex '.' hex_int ([pP] [-+]? hex_int)? skip
11430 / dec_int '.' dec_int ([eE] [-+]? dec_int)? skip
11431 / '0x' hex_* hex '.'? [pP] [-+]? hex_int skip
11432 / dec_int '.'? [eE] [-+]? dec_int skip
1140511433INTEGER
11406 &lt;- &quot;0b&quot; [_01]* [01] skip
11407 / &quot;0o&quot; [_0-7]* [0-7] skip
11408 / &quot;0x&quot; hex_* hex skip
11434 &lt;- '0b' [_01]* [01] skip
11435 / '0o' [_0-7]* [0-7] skip
11436 / '0x' hex_* hex skip
1140911437 / dec_int skip
11410STRINGLITERALSINGLE &lt;- &quot;\&quot;&quot; string_char* &quot;\&quot;&quot; skip
11438STRINGLITERALSINGLE &lt;- '&quot;' string_char* '&quot;' skip
1141111439STRINGLITERAL
1141211440 &lt;- STRINGLITERALSINGLE
11413 / line_string skip
11441 / line_string skip
1141411442IDENTIFIER
1141511443 &lt;- !keyword [A-Za-z_] [A-Za-z0-9_]* skip
11416 / &quot;@\&quot;&quot; string_char* &quot;\&quot;&quot; skip
11417BUILTINIDENTIFIER &lt;- &quot;@&quot;[A-Za-z_][A-Za-z0-9_]* skip
11444 / '@&quot;' string_char* '&quot;' skip
11445BUILTINIDENTIFIER &lt;- '@'[A-Za-z_][A-Za-z0-9_]* skip
1141811446
1141911447
1142011448AMPERSAND &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 {
5151 .segments = ArrayList(*BinaryElfSegment).init(allocator),
5252 .sections = ArrayList(*BinaryElfSection).init(allocator),
5353 };
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);
5757 while (try section_headers.next()) |section| {
5858 if (sectionValidForOutput(section)) {
5959 const newSection = try allocator.create(BinaryElfSection);
......@@ -67,7 +67,7 @@ const BinaryElfOutput = struct {
6767 }
6868 }
6969
70 var program_headers = elf_hdr.program_header_iterator(elf_file);
70 var program_headers = elf_hdr.program_header_iterator(&elf_file);
7171 while (try program_headers.next()) |phdr| {
7272 if (phdr.p_type == elf.PT_LOAD) {
7373 const newSegment = try allocator.create(BinaryElfSegment);
lib/std/c/tokenizer.zig+30-2
......@@ -401,7 +401,9 @@ pub const Tokenizer = struct {
401401 Zero,
402402 IntegerLiteralOct,
403403 IntegerLiteralBinary,
404 IntegerLiteralBinaryFirst,
404405 IntegerLiteralHex,
406 IntegerLiteralHexFirst,
405407 IntegerLiteral,
406408 IntegerSuffix,
407409 IntegerSuffixU,
......@@ -1046,10 +1048,10 @@ pub const Tokenizer = struct {
10461048 state = .IntegerLiteralOct;
10471049 },
10481050 'b', 'B' => {
1049 state = .IntegerLiteralBinary;
1051 state = .IntegerLiteralBinaryFirst;
10501052 },
10511053 'x', 'X' => {
1052 state = .IntegerLiteralHex;
1054 state = .IntegerLiteralHexFirst;
10531055 },
10541056 '.' => {
10551057 state = .FloatFraction;
......@@ -1066,6 +1068,13 @@ pub const Tokenizer = struct {
10661068 self.index -= 1;
10671069 },
10681070 },
1071 .IntegerLiteralBinaryFirst => switch (c) {
1072 '0'...'7' => state = .IntegerLiteralBinary,
1073 else => {
1074 result.id = .Invalid;
1075 break;
1076 },
1077 },
10691078 .IntegerLiteralBinary => switch (c) {
10701079 '0', '1' => {},
10711080 else => {
......@@ -1073,6 +1082,19 @@ pub const Tokenizer = struct {
10731082 self.index -= 1;
10741083 },
10751084 },
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 },
10761098 .IntegerLiteralHex => switch (c) {
10771099 '0'...'9', 'a'...'f', 'A'...'F' => {},
10781100 '.' => {
......@@ -1238,6 +1260,8 @@ pub const Tokenizer = struct {
12381260 .MultiLineCommentAsterisk,
12391261 .FloatExponent,
12401262 .MacroString,
1263 .IntegerLiteralBinaryFirst,
1264 .IntegerLiteralHexFirst,
12411265 => result.id = .Invalid,
12421266
12431267 .FloatExponentDigits => result.id = if (counter == 0) .Invalid else .{ .FloatLiteral = .none },
......@@ -1523,6 +1547,7 @@ test "num suffixes" {
15231547 \\ 1.0f 1.0L 1.0 .0 1.
15241548 \\ 0l 0lu 0ll 0llu 0
15251549 \\ 1u 1ul 1ull 1
1550 \\ 0x 0b
15261551 \\
15271552 , &[_]Token.Id{
15281553 .{ .FloatLiteral = .f },
......@@ -1542,6 +1567,9 @@ test "num suffixes" {
15421567 .{ .IntegerLiteral = .llu },
15431568 .{ .IntegerLiteral = .none },
15441569 .Nl,
1570 .Invalid,
1571 .Invalid,
1572 .Nl,
15451573 });
15461574}
15471575
lib/std/crypto/25519/curve25519.zig+2-2
......@@ -115,9 +115,9 @@ test "curve25519" {
115115 const p = try Curve25519.basePoint.clampedMul(s);
116116 try p.rejectIdentity();
117117 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");
119119 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
122122 try Curve25519.rejectNonCanonical(s);
123123 s[31] |= 0x80;
lib/std/crypto/25519/ed25519.zig+3-3
......@@ -210,8 +210,8 @@ test "ed25519 key pair creation" {
210210 _ = try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
211211 const key_pair = try Ed25519.KeyPair.create(seed);
212212 var buf: [256]u8 = undefined;
213 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{key_pair.secret_key}), "8052030376D47112BE7F73ED7A019293DD12AD910B654455798B4667D73DE1662D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
214 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{key_pair.public_key}), "2D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
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, "{s}", .{std.fmt.fmtSliceHexUpper(&key_pair.public_key)}), "2D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
215215}
216216
217217test "ed25519 signature" {
......@@ -221,7 +221,7 @@ test "ed25519 signature" {
221221
222222 const sig = try Ed25519.sign("test", key_pair, null);
223223 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");
225225 try Ed25519.verify(sig, "test", key_pair.public_key);
226226 std.testing.expectError(error.InvalidSignature, Ed25519.verify(sig, "TEST", key_pair.public_key));
227227}
lib/std/crypto/25519/edwards25519.zig+1-1
......@@ -450,7 +450,7 @@ test "edwards25519 packing/unpacking" {
450450 var b = Edwards25519.basePoint;
451451 const pk = try b.mul(s);
452452 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
455455 const small_order_ss: [7][32]u8 = .{
456456 .{
lib/std/crypto/25519/ristretto255.zig+4-4
......@@ -170,21 +170,21 @@ pub const Ristretto255 = struct {
170170test "ristretto255" {
171171 const p = Ristretto255.basePoint;
172172 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
175175 var r: [Ristretto255.encoded_length]u8 = undefined;
176176 _ = try fmt.hexToBytes(r[0..], "6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919");
177177 var q = try Ristretto255.fromBytes(r);
178178 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
181181 const s = [_]u8{15} ++ [_]u8{0} ** 31;
182182 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
185185 std.testing.expect(p.dbl().dbl().dbl().dbl().equivalent(w.add(p)));
186186
187187 const h = [_]u8{69} ** 32 ++ [_]u8{42} ** 32;
188188 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");
190190}
lib/std/crypto/25519/scalar.zig+3-3
......@@ -771,10 +771,10 @@ test "scalar25519" {
771771 var y = x.toBytes();
772772 try rejectNonCanonical(y);
773773 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
776776 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");
778778}
779779
780780test "non-canonical scalar25519" {
......@@ -788,5 +788,5 @@ test "mulAdd overflow check" {
788788 const c: [32]u8 = [_]u8{0xff} ** 32;
789789 const x = mulAdd(a, b, c);
790790 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");
792792}
lib/std/crypto/chacha20.zig+2-2
......@@ -876,7 +876,7 @@ test "crypto.xchacha20" {
876876 var ciphertext: [input.len]u8 = undefined;
877877 XChaCha20IETF.xor(ciphertext[0..], input[0..], 0, key, nonce);
878878 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");
880880 }
881881 {
882882 const data = "Additional data";
......@@ -885,7 +885,7 @@ test "crypto.xchacha20" {
885885 var out: [input.len]u8 = undefined;
886886 try xchacha20poly1305Open(out[0..], ciphertext[0..], data, key, nonce);
887887 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");
889889 testing.expectEqualSlices(u8, out[0..], input);
890890 ciphertext[0] += 1;
891891 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 {
360360 };
361361 }
362362
363 // Negative offset of the saved BP wrt the frame pointer.
363 // Offset of the saved BP wrt the frame pointer.
364364 const fp_offset = if (builtin.arch.isRISCV())
365365 // On RISC-V the frame pointer points to the top of the saved register
366366 // area, on pretty much every other architecture it points to the stack
367367 // slot where the previous frame pointer is saved.
368368 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)
369372 else
370373 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
371381 // Positive offset of the saved PC wrt the frame pointer.
372382 const pc_offset = if (builtin.arch == .powerpc64le)
373383 2 * @sizeOf(usize)
......@@ -388,13 +398,17 @@ pub const StackIterator = struct {
388398 }
389399
390400 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
393407 // Sanity check.
394408 if (fp == 0 or !mem.isAligned(fp, @alignOf(usize)))
395409 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
399413 // Sanity check: the stack grows down thus all the parent frames must be
400414 // 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) {
335335};
336336
337337/// All integers are native endian.
338const Header = struct {
338pub const Header = struct {
339339 endian: builtin.Endian,
340340 is_64: bool,
341341 entry: u64,
......@@ -347,187 +347,200 @@ const Header = struct {
347347 shnum: u16,
348348 shstrndx: u16,
349349
350 pub fn program_header_iterator(self: Header, file: File) ProgramHeaderIterator {
351 return .{
350 pub fn program_header_iterator(self: Header, parse_source: anytype) ProgramHeaderIterator(@TypeOf(parse_source)) {
351 return ProgramHeaderIterator(@TypeOf(parse_source)){
352352 .elf_header = self,
353 .file = file,
353 .parse_source = parse_source,
354354 };
355355 }
356356
357 pub fn section_header_iterator(self: Header, file: File) SectionHeaderIterator {
358 return .{
357 pub fn section_header_iterator(self: Header, parse_source: anytype) SectionHeaderIterator(@TypeOf(parse_source)) {
358 return SectionHeaderIterator(@TypeOf(parse_source)){
359359 .elf_header = self,
360 .file = file,
360 .parse_source = parse_source,
361361 };
362362 }
363};
364363
365pub fn readHeader(file: File) !Header {
366 var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined;
367 try preadNoEof(file, &hdr_buf, 0);
368 const hdr32 = @ptrCast(*Elf32_Ehdr, &hdr_buf);
369 const hdr64 = @ptrCast(*Elf64_Ehdr, &hdr_buf);
370 if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
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;
364 pub fn read(parse_source: anytype) !Header {
365 var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined;
366 try parse_source.seekableStream().seekTo(0);
367 try parse_source.reader().readNoEof(&hdr_buf);
368 return Header.parse(&hdr_buf);
369 }
379370
380 const is_64 = switch (hdr32.e_ident[EI_CLASS]) {
381 ELFCLASS32 => false,
382 ELFCLASS64 => true,
383 else => return error.InvalidElfClass,
384 };
371 pub fn parse(hdr_buf: *align(@alignOf(Elf64_Ehdr)) const [@sizeOf(Elf64_Ehdr)]u8) !Header {
372 const hdr32 = @ptrCast(*const Elf32_Ehdr, hdr_buf);
373 const hdr64 = @ptrCast(*const Elf64_Ehdr, hdr_buf);
374 if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
375 if (hdr32.e_ident[EI_VERSION] != 1) return error.InvalidElfVersion;
385376
386 return @as(Header, .{
387 .endian = endian,
388 .is_64 = is_64,
389 .entry = int(is_64, need_bswap, hdr32.e_entry, hdr64.e_entry),
390 .phoff = int(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff),
391 .shoff = int(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff),
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}
377 const endian: std.builtin.Endian = switch (hdr32.e_ident[EI_DATA]) {
378 ELFDATA2LSB => .Little,
379 ELFDATA2MSB => .Big,
380 else => return error.InvalidElfEndian,
381 };
382 const need_bswap = endian != std.builtin.endian;
399383
400pub const ProgramHeaderIterator = struct {
401 elf_header: Header,
402 file: File,
403 index: usize = 0,
384 const is_64 = switch (hdr32.e_ident[EI_CLASS]) {
385 ELFCLASS32 => false,
386 ELFCLASS64 => true,
387 else => return error.InvalidElfClass,
388 };
404389
405 pub fn next(self: *ProgramHeaderIterator) !?Elf64_Phdr {
406 if (self.index >= self.elf_header.phnum) return null;
407 defer self.index += 1;
390 return @as(Header, .{
391 .endian = endian,
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) {
410 var phdr: Elf64_Phdr = undefined;
405pub fn ProgramHeaderIterator(ParseSource: anytype) type {
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;
411438 const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index;
412 try preadNoEof(self.file, mem.asBytes(&phdr), offset);
413
414 // ELF endianness matches native endianness.
415 if (self.elf_header.endian == std.builtin.endian) return phdr;
416
417 // Convert fields to native endianness.
439 try self.parse_source.seekableStream().seekTo(offset);
440 try self.parse_source.reader().readNoEof(mem.asBytes(&phdr));
441
442 // ELF endianness does NOT match native endianness.
443 if (self.elf_header.endian != std.builtin.endian) {
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.
418458 return Elf64_Phdr{
419 .p_type = @byteSwap(@TypeOf(phdr.p_type), phdr.p_type),
420 .p_offset = @byteSwap(@TypeOf(phdr.p_offset), phdr.p_offset),
421 .p_vaddr = @byteSwap(@TypeOf(phdr.p_vaddr), phdr.p_vaddr),
422 .p_paddr = @byteSwap(@TypeOf(phdr.p_paddr), phdr.p_paddr),
423 .p_filesz = @byteSwap(@TypeOf(phdr.p_filesz), phdr.p_filesz),
424 .p_memsz = @byteSwap(@TypeOf(phdr.p_memsz), phdr.p_memsz),
425 .p_flags = @byteSwap(@TypeOf(phdr.p_flags), phdr.p_flags),
426 .p_align = @byteSwap(@TypeOf(phdr.p_align), phdr.p_align),
459 .p_type = phdr.p_type,
460 .p_offset = phdr.p_offset,
461 .p_vaddr = phdr.p_vaddr,
462 .p_paddr = phdr.p_paddr,
463 .p_filesz = phdr.p_filesz,
464 .p_memsz = phdr.p_memsz,
465 .p_flags = phdr.p_flags,
466 .p_align = phdr.p_align,
427467 };
428468 }
469 };
470}
429471
430 var phdr: Elf32_Phdr = undefined;
431 const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index;
432 try preadNoEof(self.file, mem.asBytes(&phdr), offset);
433
434 // ELF endianness does NOT match native endianness.
435 if (self.elf_header.endian != std.builtin.endian) {
436 // Convert fields to native endianness.
437 phdr = .{
438 .p_type = @byteSwap(@TypeOf(phdr.p_type), phdr.p_type),
439 .p_offset = @byteSwap(@TypeOf(phdr.p_offset), phdr.p_offset),
440 .p_vaddr = @byteSwap(@TypeOf(phdr.p_vaddr), phdr.p_vaddr),
441 .p_paddr = @byteSwap(@TypeOf(phdr.p_paddr), phdr.p_paddr),
442 .p_filesz = @byteSwap(@TypeOf(phdr.p_filesz), phdr.p_filesz),
443 .p_memsz = @byteSwap(@TypeOf(phdr.p_memsz), phdr.p_memsz),
444 .p_flags = @byteSwap(@TypeOf(phdr.p_flags), phdr.p_flags),
445 .p_align = @byteSwap(@TypeOf(phdr.p_align), phdr.p_align),
446 };
447 }
448
449 // Convert 32-bit header to 64-bit.
450 return Elf64_Phdr{
451 .p_type = phdr.p_type,
452 .p_offset = phdr.p_offset,
453 .p_vaddr = phdr.p_vaddr,
454 .p_paddr = phdr.p_paddr,
455 .p_filesz = phdr.p_filesz,
456 .p_memsz = phdr.p_memsz,
457 .p_flags = phdr.p_flags,
458 .p_align = phdr.p_align,
459 };
460 }
461};
462
463pub const SectionHeaderIterator = struct {
464 elf_header: Header,
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;
472pub fn SectionHeaderIterator(ParseSource: anytype) type {
473 return struct {
474 elf_header: Header,
475 parse_source: ParseSource,
476 index: usize = 0,
477
478 pub fn next(self: *@This()) !?Elf64_Shdr {
479 if (self.index >= self.elf_header.shnum) return null;
480 defer self.index += 1;
481
482 if (self.elf_header.is_64) {
483 var shdr: Elf64_Shdr = undefined;
484 const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index;
485 try self.parse_source.seekableStream().seekTo(offset);
486 try self.parse_source.reader().readNoEof(mem.asBytes(&shdr));
487
488 // ELF endianness matches native endianness.
489 if (self.elf_header.endian == std.builtin.endian) return shdr;
490
491 // Convert fields to native endianness.
492 return Elf64_Shdr{
493 .sh_name = @byteSwap(@TypeOf(shdr.sh_name), shdr.sh_name),
494 .sh_type = @byteSwap(@TypeOf(shdr.sh_type), shdr.sh_type),
495 .sh_flags = @byteSwap(@TypeOf(shdr.sh_flags), shdr.sh_flags),
496 .sh_addr = @byteSwap(@TypeOf(shdr.sh_addr), shdr.sh_addr),
497 .sh_offset = @byteSwap(@TypeOf(shdr.sh_offset), shdr.sh_offset),
498 .sh_size = @byteSwap(@TypeOf(shdr.sh_size), shdr.sh_size),
499 .sh_link = @byteSwap(@TypeOf(shdr.sh_link), shdr.sh_link),
500 .sh_info = @byteSwap(@TypeOf(shdr.sh_info), shdr.sh_info),
501 .sh_addralign = @byteSwap(@TypeOf(shdr.sh_addralign), shdr.sh_addralign),
502 .sh_entsize = @byteSwap(@TypeOf(shdr.sh_entsize), shdr.sh_entsize),
503 };
504 }
505
506 var shdr: Elf32_Shdr = undefined;
474507 const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index;
475 try preadNoEof(self.file, mem.asBytes(&shdr), offset);
476
477 // ELF endianness matches native endianness.
478 if (self.elf_header.endian == std.builtin.endian) return shdr;
479
480 // Convert fields to native endianness.
508 try self.parse_source.seekableStream().seekTo(offset);
509 try self.parse_source.reader().readNoEof(mem.asBytes(&shdr));
510
511 // ELF endianness does NOT match native endianness.
512 if (self.elf_header.endian != std.builtin.endian) {
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.
481529 return Elf64_Shdr{
482 .sh_name = @byteSwap(@TypeOf(shdr.sh_name), shdr.sh_name),
483 .sh_type = @byteSwap(@TypeOf(shdr.sh_type), shdr.sh_type),
484 .sh_flags = @byteSwap(@TypeOf(shdr.sh_flags), shdr.sh_flags),
485 .sh_addr = @byteSwap(@TypeOf(shdr.sh_addr), shdr.sh_addr),
486 .sh_offset = @byteSwap(@TypeOf(shdr.sh_offset), shdr.sh_offset),
487 .sh_size = @byteSwap(@TypeOf(shdr.sh_size), shdr.sh_size),
488 .sh_link = @byteSwap(@TypeOf(shdr.sh_link), shdr.sh_link),
489 .sh_info = @byteSwap(@TypeOf(shdr.sh_info), shdr.sh_info),
490 .sh_addralign = @byteSwap(@TypeOf(shdr.sh_addralign), shdr.sh_addralign),
491 .sh_entsize = @byteSwap(@TypeOf(shdr.sh_entsize), shdr.sh_entsize),
530 .sh_name = shdr.sh_name,
531 .sh_type = shdr.sh_type,
532 .sh_flags = shdr.sh_flags,
533 .sh_addr = shdr.sh_addr,
534 .sh_offset = shdr.sh_offset,
535 .sh_size = shdr.sh_size,
536 .sh_link = shdr.sh_link,
537 .sh_info = shdr.sh_info,
538 .sh_addralign = shdr.sh_addralign,
539 .sh_entsize = shdr.sh_entsize,
492540 };
493541 }
494
495 var shdr: Elf32_Shdr = undefined;
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};
542 };
543}
531544
532545pub fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) {
533546 if (is_64) {
......@@ -549,28 +562,6 @@ pub fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 {
549562 }
550563}
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
574565pub const EI_NIDENT = 16;
575566
576567pub const EI_CLASS = 4;
lib/std/fmt.zig+104-26
......@@ -709,6 +709,87 @@ fn formatFloatValue(
709709 return formatBuf(buf_stream.getWritten(), options, writer);
710710}
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
712793pub fn formatText(
713794 bytes: []const u8,
714795 comptime fmt: []const u8,
......@@ -717,21 +798,18 @@ pub fn formatText(
717798) !void {
718799 if (comptime std.mem.eql(u8, fmt, "s")) {
719800 return formatBuf(bytes, options, writer);
720 } else if (comptime (std.mem.eql(u8, fmt, "x") or std.mem.eql(u8, fmt, "X"))) {
721 for (bytes) |c| {
722 try formatInt(c, 16, fmt[0] == 'X', FormatOptions{ .width = 2, .fill = '0' }, writer);
723 }
724 return;
725 } else if (comptime (std.mem.eql(u8, fmt, "e") or std.mem.eql(u8, fmt, "E"))) {
726 for (bytes) |c| {
727 if (std.ascii.isPrint(c)) {
728 try writer.writeByte(c);
729 } else {
730 try writer.writeAll("\\x");
731 try formatInt(c, 16, fmt[0] == 'E', FormatOptions{ .width = 2, .fill = '0' }, writer);
732 }
733 }
734 return;
801 } else if (comptime (std.mem.eql(u8, fmt, "x"))) {
802 @compileError("specifier 'x' has been deprecated, wrap your argument in std.fmt.fmtSliceHexLower instead");
803 } else if (comptime (std.mem.eql(u8, fmt, "X"))) {
804 @compileError("specifier 'X' has been deprecated, wrap your argument in std.fmt.fmtSliceHexUpper instead");
805 } else if (comptime (std.mem.eql(u8, fmt, "e"))) {
806 @compileError("specifier 'e' has been deprecated, wrap your argument in std.fmt.fmtSliceEscapeLower instead");
807 } else if (comptime (std.mem.eql(u8, fmt, "E"))) {
808 @compileError("specifier 'X' has been deprecated, wrap your argument in std.fmt.fmtSliceEscapeUpper instead");
809 } else if (comptime std.mem.eql(u8, fmt, "z")) {
810 @compileError("specifier 'z' has been deprecated, wrap your argument in std.zig.fmtId instead");
811 } else if (comptime std.mem.eql(u8, fmt, "Z")) {
812 @compileError("specifier 'Z' has been deprecated, wrap your argument in std.zig.fmtEscapes instead");
735813 } else {
736814 @compileError("Unsupported format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'");
737815 }
......@@ -1693,9 +1771,9 @@ test "slice" {
16931771}
16941772
16951773test "escape non-printable" {
1696 try expectFmt("abc", "{e}", .{"abc"});
1697 try expectFmt("ab\\xffc", "{e}", .{"ab\xffc"});
1698 try expectFmt("ab\\xFFc", "{E}", .{"ab\xffc"});
1774 try expectFmt("abc", "{s}", .{fmtSliceEscapeLower("abc")});
1775 try expectFmt("ab\\xffc", "{s}", .{fmtSliceEscapeLower("ab\xffc")});
1776 try expectFmt("ab\\xFFc", "{s}", .{fmtSliceEscapeUpper("ab\xffc")});
16991777}
17001778
17011779test "pointer" {
......@@ -1968,13 +2046,13 @@ test "struct.zero-size" {
19682046
19692047test "bytes.hex" {
19702048 const some_bytes = "\xCA\xFE\xBA\xBE";
1971 try expectFmt("lowercase: cafebabe\n", "lowercase: {x}\n", .{some_bytes});
1972 try expectFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", .{some_bytes});
2049 try expectFmt("lowercase: cafebabe\n", "lowercase: {x}\n", .{fmtSliceHexLower(some_bytes)});
2050 try expectFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", .{fmtSliceHexUpper(some_bytes)});
19732051 //Test Slices
1974 try expectFmt("uppercase: CAFE\n", "uppercase: {X}\n", .{some_bytes[0..2]});
1975 try expectFmt("lowercase: babe\n", "lowercase: {x}\n", .{some_bytes[2..]});
2052 try expectFmt("uppercase: CAFE\n", "uppercase: {X}\n", .{fmtSliceHexUpper(some_bytes[0..2])});
2053 try expectFmt("lowercase: babe\n", "lowercase: {x}\n", .{fmtSliceHexLower(some_bytes[2..])});
19762054 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)});
19782056}
19792057
19802058pub 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 {
20022080
20032081test "hexToBytes" {
20042082 var buf: [32]u8 = undefined;
2005 try expectFmt("90" ** 32, "{X}", .{try hexToBytes(&buf, "90" ** 32)});
2006 try expectFmt("ABCD", "{X}", .{try hexToBytes(&buf, "ABCD")});
2007 try expectFmt("", "{X}", .{try hexToBytes(&buf, "")});
2083 try expectFmt("90" ** 32, "{s}", .{fmtSliceHexUpper(try hexToBytes(&buf, "90" ** 32))});
2084 try expectFmt("ABCD", "{s}", .{fmtSliceHexUpper(try hexToBytes(&buf, "ABCD"))});
2085 try expectFmt("", "{s}", .{fmtSliceHexUpper(try hexToBytes(&buf, ""))});
20082086 std.testing.expectError(error.InvalidCharacter, hexToBytes(&buf, "012Z"));
20092087 std.testing.expectError(error.InvalidLength, hexToBytes(&buf, "AAA"));
20102088 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
6060 var dir_path_ptr: [*:0]u8 = undefined;
6161 // TODO look into directory_which
6262 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);
6464 const settings_dir = try allocator.dupeZ(u8, mem.spanZ(dir_path_ptr));
6565 defer allocator.free(settings_dir);
6666 switch (rc) {
lib/std/io/writer.zig+7
......@@ -4,6 +4,7 @@
44// The MIT license requires this copyright notice to be included in all copies
55// and substantial portions of the software.
66const std = @import("../std.zig");
7const assert = std.debug.assert;
78const builtin = std.builtin;
89const mem = std.mem;
910
......@@ -86,5 +87,11 @@ pub fn Writer(
8687 mem.writeInt(T, &bytes, value, endian);
8788 return self.writeAll(&bytes);
8889 }
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 }
8996 };
9097}
lib/std/math.zig+56
......@@ -1330,3 +1330,59 @@ test "math.comptime" {
13301330 comptime const v = sin(@as(f32, 1)) + ln(@as(f32, 5));
13311331 testing.expect(v == sin(@as(f32, 1)) + ln(@as(f32, 5)));
13321332}
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) {
2525 else => 4 * 1024,
2626};
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
2836pub const Allocator = @import("mem/Allocator.zig");
2937
3038/// 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 {
136136 const slices = self.slice();
137137 var result: S = undefined;
138138 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];
140140 }
141141 return result;
142142 }
lib/std/os/bits/haiku.zig+6-7
......@@ -180,8 +180,8 @@ pub const dirent = extern struct {
180180};
181181
182182pub const image_info = extern struct {
183 id: u32, //image_id
184 type: u32, // image_type
183 id: u32,
184 type: u32,
185185 sequence: i32,
186186 init_order: i32,
187187 init_routine: *c_void,
......@@ -806,17 +806,16 @@ pub const Sigaction = extern struct {
806806
807807pub const _SIG_WORDS = 4;
808808pub const _SIG_MAXSIG = 128;
809
810pub inline fn _SIG_IDX(sig: usize) usize {
809pub fn _SIG_IDX(sig: usize) callconv(.Inline) usize {
811810 return sig - 1;
812811}
813pub inline fn _SIG_WORD(sig: usize) usize {
812pub fn _SIG_WORD(sig: usize) callconv(.Inline) usize {
814813 return_SIG_IDX(sig) >> 5;
815814}
816pub inline fn _SIG_BIT(sig: usize) usize {
815pub fn _SIG_BIT(sig: usize) callconv(.Inline) usize {
817816 return 1 << (_SIG_IDX(sig) & 31);
818817}
819pub inline fn _SIG_VALID(sig: usize) usize {
818pub fn _SIG_VALID(sig: usize) callconv(.Inline) usize {
820819 return sig <= _SIG_MAXSIG and sig > 0;
821820}
822821
lib/std/os/bits/linux.zig+5
......@@ -2244,3 +2244,8 @@ pub const MADV_COLD = 20;
22442244pub const MADV_PAGEOUT = 21;
22452245pub const MADV_HWPOISON = 100;
22462246pub 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 {
526526 pub fn timeout(
527527 self: *IO_Uring,
528528 user_data: u64,
529 ts: *const os.timespec,
529 ts: *const os.__kernel_timespec,
530530 count: u32,
531531 flags: u32,
532532 ) !*io_uring_sqe {
......@@ -884,7 +884,7 @@ pub fn io_uring_prep_close(sqe: *io_uring_sqe, fd: os.fd_t) void {
884884
885885pub fn io_uring_prep_timeout(
886886 sqe: *io_uring_sqe,
887 ts: *const os.timespec,
887 ts: *const os.__kernel_timespec,
888888 count: u32,
889889 flags: u32,
890890) void {
......@@ -1339,7 +1339,7 @@ test "timeout (after a relative time)" {
13391339
13401340 const ms = 10;
13411341 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
13441344 const started = std.time.milliTimestamp();
13451345 const sqe = try ring.timeout(0x55555555, &ts, 0, 0);
......@@ -1366,7 +1366,7 @@ test "timeout (after a number of completions)" {
13661366 };
13671367 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 };
13701370 const count_completions: u64 = 1;
13711371 const sqe_timeout = try ring.timeout(0x66666666, &ts, count_completions, 0);
13721372 testing.expectEqual(linux.IORING_OP.TIMEOUT, sqe_timeout.opcode);
......@@ -1399,7 +1399,7 @@ test "timeout_remove" {
13991399 };
14001400 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 };
14031403 const sqe_timeout = try ring.timeout(0x88888888, &ts, 0, 0);
14041404 testing.expectEqual(linux.IORING_OP.TIMEOUT, sqe_timeout.opcode);
14051405 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;
1818pub const ChildProcess = @import("child_process.zig").ChildProcess;
1919pub const ComptimeStringMap = @import("comptime_string_map.zig").ComptimeStringMap;
2020pub const DynLib = @import("dynamic_library.zig").DynLib;
21pub const DynamicBitSet = bit_set.DynamicBitSet;
22pub const DynamicBitSetUnmanaged = bit_set.DynamicBitSetUnmanaged;
2123pub const HashMap = hash_map.HashMap;
2224pub const HashMapUnmanaged = hash_map.HashMapUnmanaged;
2325pub const MultiArrayList = @import("multi_array_list.zig").MultiArrayList;
......@@ -29,6 +31,7 @@ pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;
2931pub const Progress = @import("Progress.zig");
3032pub const SemanticVersion = @import("SemanticVersion.zig");
3133pub const SinglyLinkedList = @import("linked_list.zig").SinglyLinkedList;
34pub const StaticBitSet = bit_set.StaticBitSet;
3235pub const StringHashMap = hash_map.StringHashMap;
3336pub const StringHashMapUnmanaged = hash_map.StringHashMapUnmanaged;
3437pub const StringArrayHashMap = array_hash_map.StringArrayHashMap;
......@@ -40,6 +43,7 @@ pub const Thread = @import("Thread.zig");
4043pub const array_hash_map = @import("array_hash_map.zig");
4144pub const atomic = @import("atomic.zig");
4245pub const base64 = @import("base64.zig");
46pub const bit_set = @import("bit_set.zig");
4347pub const build = @import("build.zig");
4448pub const builtin = @import("builtin.zig");
4549pub const c = @import("c.zig");
lib/std/zig/parse.zig+12-20
......@@ -3714,7 +3714,6 @@ const Parser = struct {
37143714 if (p.eatToken(.r_paren)) |_| {
37153715 return SmallSpan{ .zero_or_one = 0 };
37163716 }
3717 continue;
37183717 },
37193718 .r_paren => return SmallSpan{ .zero_or_one = 0 },
37203719 else => {
......@@ -3728,14 +3727,7 @@ const Parser = struct {
37283727
37293728 const param_two = while (true) {
37303729 switch (p.token_tags[p.nextToken()]) {
3731 .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 },
3730 .comma => {},
37393731 .r_paren => return SmallSpan{ .zero_or_one = param_one },
37403732 .colon, .r_brace, .r_bracket => {
37413733 p.tok_i -= 1;
......@@ -3748,6 +3740,11 @@ const Parser = struct {
37483740 try p.warnExpected(.comma);
37493741 },
37503742 }
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;
37513748 } else unreachable;
37523749
37533750 var list = std.ArrayList(Node.Index).init(p.gpa);
......@@ -3757,17 +3754,7 @@ const Parser = struct {
37573754
37583755 while (true) {
37593756 switch (p.token_tags[p.nextToken()]) {
3760 .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 },
3757 .comma => {},
37713758 .r_paren => return SmallSpan{ .multi = list.toOwnedSlice() },
37723759 .colon, .r_brace, .r_bracket => {
37733760 p.tok_i -= 1;
......@@ -3780,6 +3767,11 @@ const Parser = struct {
37803767 try p.warnExpected(.comma);
37813768 },
37823769 }
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);
37833775 }
37843776 }
37853777
lib/std/zig/parser_test.zig+31
......@@ -1108,6 +1108,25 @@ test "zig fmt: comment to disable/enable zig fmt first" {
11081108 );
11091109}
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
11111130test "zig fmt: comment to disable/enable zig fmt" {
11121131 try testTransform(
11131132 \\const a = b;
......@@ -4549,6 +4568,18 @@ test "recovery: missing for payload" {
45494568 });
45504569}
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
45524583const std = @import("std");
45534584const mem = std.mem;
45544585const 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
23522352 }
23532353 }
23542354
2355 try ais.writer().print("{s}\n", .{trimmed_comment});
2356 index = 1 + (newline orelse return true);
2357
2358 if (ais.disabled_offset) |disabled_offset| {
2359 if (mem.eql(u8, trimmed_comment, "// zig fmt: on")) {
2360 // write the source for which formatting was disabled directly
2361 // to the underlying writer, fixing up invaild whitespace
2362 try writeFixingWhitespace(ais.underlying_writer, tree.source[disabled_offset..index]);
2363 ais.disabled_offset = null;
2364 }
2365 } else if (mem.eql(u8, trimmed_comment, "// zig fmt: off")) {
2355 index = 1 + (newline orelse end - 1);
2356
2357 const comment_content = mem.trimLeft(u8, trimmed_comment["//".len..], &std.ascii.spaces);
2358 if (ais.disabled_offset != null and mem.eql(u8, comment_content, "zig fmt: on")) {
2359 // Write the source for which formatting was disabled directly
2360 // to the underlying writer, fixing up invaild whitespace.
2361 const disabled_source = tree.source[ais.disabled_offset.?..comment_start];
2362 try writeFixingWhitespace(ais.underlying_writer, disabled_source);
2363 ais.disabled_offset = null;
2364 // Write with the canonical single space.
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");
23662369 ais.disabled_offset = index;
2370 } else {
2371 // Write the comment minus trailing whitespace.
2372 try ais.writer().print("{s}\n", .{trimmed_comment});
23672373 }
23682374 }
23692375
src/Cache.zig+20-4
......@@ -153,7 +153,11 @@ pub const HashHelper = struct {
153153 hh.hasher.final(&bin_digest);
154154
155155 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;
157161 return out_digest;
158162 }
159163};
......@@ -250,7 +254,11 @@ pub const Manifest = struct {
250254 var bin_digest: BinDigest = undefined;
251255 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
255263 self.hash.hasher = hasher_init;
256264 self.hash.hasher.update(&bin_digest);
......@@ -549,7 +557,11 @@ pub const Manifest = struct {
549557 self.hash.hasher.final(&bin_digest);
550558
551559 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
554566 return out_digest;
555567 }
......@@ -565,7 +577,11 @@ pub const Manifest = struct {
565577 var encoded_digest: [hex_digest_len]u8 = undefined;
566578
567579 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;
569585 try writer.print("{d} {d} {d} {s} {s}\n", .{
570586 file.stat.size,
571587 file.stat.inode,
src/Module.zig+6-6
......@@ -4083,15 +4083,15 @@ pub fn namedFieldPtr(
40834083 const child_type = try val.toType(scope.arena());
40844084 switch (child_type.zigTypeTag()) {
40854085 .ErrorSet => {
4086 var name: []const u8 = undefined;
40864087 // TODO resolve inferred error sets
4087 const entry = if (val.castTag(.error_set)) |payload|
4088 (payload.data.fields.getEntry(field_name) orelse
4089 return mod.fail(scope, src, "no error named '{s}' in '{}'", .{ field_name, child_type })).*
4088 if (val.castTag(.error_set)) |payload|
4089 name = (payload.data.fields.getEntry(field_name) orelse return mod.fail(scope, src, "no error named '{s}' in '{}'", .{ field_name, child_type })).key
40904090 else
4091 try mod.getErrorValue(field_name);
4091 name = (try mod.getErrorValue(field_name)).key;
40924092
40934093 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)
40954095 else
40964096 child_type;
40974097
......@@ -4100,7 +4100,7 @@ pub fn namedFieldPtr(
41004100 .val = try Value.Tag.ref_val.create(
41014101 scope.arena(),
41024102 try Value.Tag.@"error".create(scope.arena(), .{
4103 .name = entry.key,
4103 .name = name,
41044104 }),
41054105 ),
41064106 });
src/astgen.zig+48-11
......@@ -453,13 +453,23 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
453453 return rvalue(mod, scope, rl, result);
454454 },
455455 .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 };
461456 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 }
463473 },
464474 .block_two, .block_two_semicolon => {
465475 const statements = [2]ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs };
......@@ -1645,7 +1655,7 @@ fn errorSetDecl(
16451655 switch (token_tags[tok_i]) {
16461656 .doc_comment, .comma => {},
16471657 .identifier => count += 1,
1648 .r_paren => break :count count,
1658 .r_brace => break :count count,
16491659 else => unreachable,
16501660 }
16511661 } else unreachable; // TODO should not need else unreachable here
......@@ -1662,7 +1672,7 @@ fn errorSetDecl(
16621672 fields[field_i] = try mod.identifierTokenString(scope, tok_i);
16631673 field_i += 1;
16641674 },
1665 .r_paren => break,
1675 .r_brace => break,
16661676 else => unreachable,
16671677 }
16681678 }
......@@ -1699,9 +1709,13 @@ fn orelseCatchExpr(
16991709 setBlockResultLoc(&block_scope, rl);
17001710 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.
17031716 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);
17051719 const cond = try addZIRUnOp(mod, &block_scope.base, src, cond_op, operand);
17061720
17071721 const condbr = try addZIRInstSpecial(mod, &block_scope.base, src, zir.Inst.CondBr, .{
......@@ -1753,6 +1767,10 @@ fn orelseCatchExpr(
17531767
17541768 // This could be a pointer or value depending on `unwrap_op`.
17551769 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
17571775 return finishThenElseBlock(
17581776 mod,
......@@ -1766,7 +1784,7 @@ fn orelseCatchExpr(
17661784 src,
17671785 src,
17681786 then_result,
1769 unwrapped_payload,
1787 else_result,
17701788 block,
17711789 block,
17721790 );
......@@ -3955,6 +3973,25 @@ fn rlStrategy(rl: ResultLoc, block_scope: *Scope.GenZIR) ResultLoc.Strategy {
39553973 }
39563974}
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
39583995fn setBlockResultLoc(block_scope: *Scope.GenZIR, parent_rl: ResultLoc) void {
39593996 // Depending on whether the result location is a pointer or value, different
39603997 // 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"),
4646.{
4747 .name = "MM",
4848 .syntax = .flag,
49 .zig_equivalent = .dep_file,
49 .zig_equivalent = .dep_file_mm,
5050 .pd1 = true,
5151 .pd2 = false,
5252 .psl = false,
......@@ -1870,7 +1870,7 @@ flagpsl("MT"),
18701870.{
18711871 .name = "print-missing-file-dependencies",
18721872 .syntax = .flag,
1873 .zig_equivalent = .other,
1873 .zig_equivalent = .dep_file,
18741874 .pd1 = false,
18751875 .pd2 = true,
18761876 .psl = false,
......@@ -1990,7 +1990,7 @@ flagpsl("MT"),
19901990.{
19911991 .name = "user-dependencies",
19921992 .syntax = .flag,
1993 .zig_equivalent = .other,
1993 .zig_equivalent = .dep_file_mm,
19941994 .pd1 = false,
19951995 .pd2 = true,
19961996 .psl = false,
......@@ -2014,7 +2014,7 @@ flagpsl("MT"),
20142014.{
20152015 .name = "write-dependencies",
20162016 .syntax = .flag,
2017 .zig_equivalent = .other,
2017 .zig_equivalent = .dep_file,
20182018 .pd1 = false,
20192019 .pd2 = true,
20202020 .psl = false,
......@@ -2022,7 +2022,7 @@ flagpsl("MT"),
20222022.{
20232023 .name = "write-user-dependencies",
20242024 .syntax = .flag,
2025 .zig_equivalent = .other,
2025 .zig_equivalent = .dep_file,
20262026 .pd1 = false,
20272027 .pd2 = true,
20282028 .psl = false,
src/codegen.zig+43
......@@ -899,6 +899,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
899899 .load => return self.genLoad(inst.castTag(.load).?),
900900 .loop => return self.genLoop(inst.castTag(.loop).?),
901901 .not => return self.genNot(inst.castTag(.not).?),
902 .mul => return self.genMul(inst.castTag(.mul).?),
902903 .ptrtoint => return self.genPtrToInt(inst.castTag(.ptrtoint).?),
903904 .ref => return self.genRef(inst.castTag(.ref).?),
904905 .ret => return self.genRet(inst.castTag(.ret).?),
......@@ -1128,6 +1129,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
11281129 }
11291130 }
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
11311142 fn genBitAnd(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
11321143 // No side effects, so if it's unreferenced, do nothing.
11331144 if (inst.base.isUnused())
......@@ -1478,6 +1489,38 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
14781489 }
14791490 }
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
14811524 /// ADD, SUB, XOR, OR, AND
14821525 fn genX8664BinMath(self: *Self, inst: *ir.Inst, op_lhs: *ir.Inst, op_rhs: *ir.Inst, opx: u8, mr: u8) !MCValue {
14831526 try self.code.ensureCapacity(self.code.items.len + 8);
src/codegen/llvm.zig+105-8
......@@ -400,6 +400,7 @@ pub const LLVMIRModule = struct {
400400 .block => try self.genBlock(inst.castTag(.block).?),
401401 .br => try self.genBr(inst.castTag(.br).?),
402402 .breakpoint => try self.genBreakpoint(inst.castTag(.breakpoint).?),
403 .br_void => try self.genBrVoid(inst.castTag(.br_void).?),
403404 .call => try self.genCall(inst.castTag(.call).?),
404405 .cmp_eq => try self.genCmp(inst.castTag(.cmp_eq).?, .eq),
405406 .cmp_gt => try self.genCmp(inst.castTag(.cmp_gt).?, .gt),
......@@ -409,6 +410,10 @@ pub const LLVMIRModule = struct {
409410 .cmp_neq => try self.genCmp(inst.castTag(.cmp_neq).?, .neq),
410411 .condbr => try self.genCondBr(inst.castTag(.condbr).?),
411412 .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),
412417 .load => try self.genLoad(inst.castTag(.load).?),
413418 .loop => try self.genLoop(inst.castTag(.loop).?),
414419 .not => try self.genNot(inst.castTag(.not).?),
......@@ -417,6 +422,8 @@ pub const LLVMIRModule = struct {
417422 .store => try self.genStore(inst.castTag(.store).?),
418423 .sub => try self.genSub(inst.castTag(.sub).?),
419424 .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),
420427 .dbg_stmt => blk: {
421428 // TODO: implement debug info
422429 break :blk null;
......@@ -537,21 +544,29 @@ pub const LLVMIRModule = struct {
537544 }
538545
539546 fn genBr(self: *LLVMIRModule, inst: *Inst.Br) !?*const llvm.Value {
540 // Get the block that we want to break to.
541547 var block = self.blocks.get(inst.block).?;
542 _ = self.builder.buildBr(block.parent_bb);
543548
544549 // If the break doesn't break a value, then we don't have to add
545550 // 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 the
549 // break instructions.
550 try block.break_bbs.append(self.gpa, self.builder.getInsertBlock());
557 // For the phi node, we need the basic blocks and the values of the
558 // break instructions.
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);
553 try block.break_vals.append(self.gpa, val);
562 _ = self.builder.buildBr(block.parent_bb);
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);
555570 return null;
556571 }
557572
......@@ -594,6 +609,44 @@ pub const LLVMIRModule = struct {
594609 return null;
595610 }
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
597650 fn genAdd(self: *LLVMIRModule, inst: *Inst.BinOp) !?*const llvm.Value {
598651 const lhs = try self.resolveInst(inst.lhs);
599652 const rhs = try self.resolveInst(inst.rhs);
......@@ -754,6 +807,13 @@ pub const LLVMIRModule = struct {
754807 // TODO: consider using buildInBoundsGEP2 for opaque pointers
755808 return self.builder.buildInBoundsGEP(val, &indices, 2, "");
756809 },
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 },
757817 else => return self.fail(src, "TODO implement const of pointer type '{}'", .{tv.ty}),
758818 },
759819 .Array => {
......@@ -768,6 +828,29 @@ pub const LLVMIRModule = struct {
768828 return self.fail(src, "TODO handle more array values", .{});
769829 }
770830 },
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 },
771854 else => return self.fail(src, "TODO implement const of type '{}'", .{tv.ty}),
772855 }
773856 }
......@@ -793,6 +876,20 @@ pub const LLVMIRModule = struct {
793876 const elem_type = try self.getLLVMType(t.elemType(), src);
794877 return elem_type.arrayType(@intCast(c_uint, t.abiSize(self.module.getTarget())));
795878 },
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 },
796893 else => return self.fail(src, "TODO implement getLLVMType for type '{}'", .{t}),
797894 }
798895 }
src/codegen/llvm/bindings.zig+9
......@@ -21,9 +21,15 @@ pub const Context = opaque {
2121 pub const voidType = LLVMVoidTypeInContext;
2222 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
2427 pub const constString = LLVMConstStringInContext;
2528 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
2733 pub const createBasicBlock = LLVMCreateBasicBlockInContext;
2834 extern fn LLVMCreateBasicBlockInContext(C: *const Context, Name: [*:0]const u8) *const BasicBlock;
2935
......@@ -204,6 +210,9 @@ pub const Builder = opaque {
204210
205211 pub const buildPhi = LLVMBuildPhi;
206212 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;
207216};
208217
209218pub const IntPredicate = extern enum {
src/ir.zig+2
......@@ -106,6 +106,7 @@ pub const Inst = struct {
106106 store,
107107 sub,
108108 unreach,
109 mul,
109110 not,
110111 floatcast,
111112 intcast,
......@@ -165,6 +166,7 @@ pub const Inst = struct {
165166
166167 .add,
167168 .sub,
169 .mul,
168170 .cmp_lt,
169171 .cmp_lte,
170172 .cmp_eq,
src/link.zig+2-2
......@@ -550,11 +550,11 @@ pub const File = struct {
550550 id_symlink_basename,
551551 &prev_digest_buf,
552552 ) 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) });
554554 break :b prev_digest_buf[0..0];
555555 };
556556 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)});
558558 base.lock = man.toOwnedLock();
559559 return;
560560 }
src/link/Coff.zig+3-3
......@@ -892,17 +892,17 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
892892 id_symlink_basename,
893893 &prev_digest_buf,
894894 ) 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) });
896896 // Handle this as a cache miss.
897897 break :blk prev_digest_buf[0..0];
898898 };
899899 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)});
901901 // Hot diggity dog! The output binary is already there.
902902 self.base.lock = man.toOwnedLock();
903903 return;
904904 }
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
907907 // We are about to change the output file to be different, so we invalidate the build hash now.
908908 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 {
13651365 id_symlink_basename,
13661366 &prev_digest_buf,
13671367 ) 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) });
13691369 // Handle this as a cache miss.
13701370 break :blk prev_digest_buf[0..0];
13711371 };
13721372 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)});
13741374 // Hot diggity dog! The output binary is already there.
13751375 self.base.lock = man.toOwnedLock();
13761376 return;
13771377 }
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
13801380 // We are about to change the output file to be different, so we invalidate the build hash now.
13811381 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 {
556556 id_symlink_basename,
557557 &prev_digest_buf,
558558 ) 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) });
560560 // Handle this as a cache miss.
561561 break :blk prev_digest_buf[0..0];
562562 };
563563 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)});
565565 // Hot diggity dog! The output binary is already there.
566566 self.base.lock = man.toOwnedLock();
567567 return;
568568 }
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
571571 // We are about to change the output file to be different, so we invalidate the build hash now.
572572 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 {
391391 id_symlink_basename,
392392 &prev_digest_buf,
393393 ) 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) });
395395 // Handle this as a cache miss.
396396 break :blk prev_digest_buf[0..0];
397397 };
398398 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)});
400400 // Hot diggity dog! The output binary is already there.
401401 self.base.lock = man.toOwnedLock();
402402 return;
403403 }
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
406406 // We are about to change the output file to be different, so we invalidate the build hash now.
407407 directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {
src/main.zig+18-2
......@@ -448,6 +448,15 @@ const Emit = union(enum) {
448448 }
449449};
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
451460fn optionalStringEnvVar(arena: *Allocator, name: []const u8) !?[]const u8 {
452461 if (std.process.getEnvVarOwned(arena, name)) |value| {
453462 return value;
......@@ -482,8 +491,8 @@ fn buildOutputType(
482491 var single_threaded = false;
483492 var function_sections = false;
484493 var watch = false;
485 var verbose_link = false;
486 var verbose_cc = false;
494 var verbose_link = try optionalBoolEnvVar(arena, "ZIG_VERBOSE_LINK");
495 var verbose_cc = try optionalBoolEnvVar(arena, "ZIG_VERBOSE_CC");
487496 var verbose_tokenize = false;
488497 var verbose_ast = false;
489498 var verbose_ir = false;
......@@ -1183,6 +1192,12 @@ fn buildOutputType(
11831192 disable_c_depfile = true;
11841193 try clang_argv.appendSlice(it.other_args);
11851194 },
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 },
11861201 .framework_dir => try framework_dirs.append(it.only_arg),
11871202 .framework => try frameworks.append(it.only_arg),
11881203 .nostdlibinc => want_native_include_dirs = false,
......@@ -3046,6 +3061,7 @@ pub const ClangArgIterator = struct {
30463061 lib_dir,
30473062 mcpu,
30483063 dep_file,
3064 dep_file_mm,
30493065 framework_dir,
30503066 framework,
30513067 nostdlibinc,
src/stage1/codegen.cpp+9-1
......@@ -4126,7 +4126,15 @@ static LLVMValueRef gen_frame_size(CodeGen *g, LLVMValueRef fn_val) {
41264126 LLVMValueRef casted_fn_val = LLVMBuildBitCast(g->builder, fn_val, ptr_usize_llvm_type, "");
41274127 LLVMValueRef negative_one = LLVMConstInt(LLVMInt32Type(), -1, true);
41284128 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;
41304138}
41314139
41324140static 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 {
10301030 var file = try tmp_dir.openFile(bin_name, .{ .read = true });
10311031 defer file.close();
10321032
1033 const header = try std.elf.readHeader(file);
1034 var iterator = header.program_header_iterator(file);
1033 const header = try std.elf.Header.read(&file);
1034 var iterator = header.program_header_iterator(&file);
10351035
10361036 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
46084608 if (slice[0] != '\'' or slice[1] == '\\' or slice.len == 3) {
46094609 return Tag.char_literal.create(c.arena, try zigifyEscapeSequences(c, m));
46104610 } 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])});
46124612 return Tag.integer_literal.create(c.arena, str);
46134613 }
46144614 },
src/value.zig+1-1
......@@ -2144,7 +2144,7 @@ pub const Value = extern union {
21442144 base: Payload = .{ .tag = base_tag },
21452145 data: struct {
21462146 /// TODO revisit this when we have the concept of the error tag type
2147 fields: std.StringHashMapUnmanaged(u16),
2147 fields: std.StringHashMapUnmanaged(void),
21482148 decl: *Module.Decl,
21492149 },
21502150 };
src/zir.zig+7
......@@ -299,6 +299,9 @@ pub const Inst = struct {
299299 xor,
300300 /// Create an optional type '?T'
301301 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,
302305 /// Create a union type.
303306 union_type,
304307 /// ?T => T with safety.
......@@ -397,6 +400,7 @@ pub const Inst = struct {
397400 .mut_slice_type,
398401 .const_slice_type,
399402 .optional_type,
403 .optional_type_from_ptr_elem,
400404 .optional_payload_safe,
401405 .optional_payload_unsafe,
402406 .optional_payload_safe_ptr,
......@@ -597,6 +601,7 @@ pub const Inst = struct {
597601 .typeof,
598602 .xor,
599603 .optional_type,
604 .optional_type_from_ptr_elem,
600605 .optional_payload_safe,
601606 .optional_payload_unsafe,
602607 .optional_payload_safe_ptr,
......@@ -1649,6 +1654,7 @@ const DumpTzir = struct {
16491654
16501655 .add,
16511656 .sub,
1657 .mul,
16521658 .cmp_lt,
16531659 .cmp_lte,
16541660 .cmp_eq,
......@@ -1771,6 +1777,7 @@ const DumpTzir = struct {
17711777
17721778 .add,
17731779 .sub,
1780 .mul,
17741781 .cmp_lt,
17751782 .cmp_lte,
17761783 .cmp_eq,
src/zir_sema.zig+86-2
......@@ -131,6 +131,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
131131 .typeof => return zirTypeof(mod, scope, old_inst.castTag(.typeof).?),
132132 .typeof_peer => return zirTypeofPeer(mod, scope, old_inst.castTag(.typeof_peer).?),
133133 .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).?),
134135 .optional_payload_safe => return zirOptionalPayload(mod, scope, old_inst.castTag(.optional_payload_safe).?, true),
135136 .optional_payload_unsafe => return zirOptionalPayload(mod, scope, old_inst.castTag(.optional_payload_unsafe).?, false),
136137 .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
10931094 return mod.constType(scope, optional.base.src, try mod.optionalType(scope, child_type));
10941095}
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
10961107fn zirArrayType(mod: *Module, scope: *Scope, array: *zir.Inst.BinOp) InnerError!*Inst {
10971108 const tracy = trace(@src());
10981109 defer tracy.end();
......@@ -1154,7 +1165,7 @@ fn zirErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) InnerError
11541165
11551166 for (inst.positionals.fields) |field_name| {
11561167 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, {})) |_| {
11581169 return mod.fail(scope, inst.base.src, "duplicate error: '{s}'", .{field_name});
11591170 }
11601171 }
......@@ -1185,7 +1196,79 @@ fn zirErrorValue(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorValue) InnerE
11851196fn zirMergeErrorSets(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
11861197 const tracy = trace(@src());
11871198 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);
11891272}
11901273
11911274fn 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!
20752158 const ir_tag = switch (inst.base.tag) {
20762159 .add => Inst.Tag.add,
20772160 .sub => Inst.Tag.sub,
2161 .mul => Inst.Tag.mul,
20782162 else => return mod.fail(scope, inst.base.src, "TODO implement arithmetic for operand '{s}''", .{@tagName(inst.base.tag)}),
20792163 };
20802164
test/run_translated_c.zig+2
......@@ -27,6 +27,8 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
2727 \\#define FOO =
2828 \\#define PtrToPtr64(p) ((void *POINTER_64) p)
2929 \\#define STRUC_ALIGNED_STACK_COPY(t,s) ((CONST t *)(s))
30 \\#define bar = 0x
31 \\#define baz = 0b
3032 \\int main(void) {}
3133 , "");
3234
test/stage1/behavior.zig+1-1
......@@ -141,5 +141,5 @@ comptime {
141141 _ = @import("behavior/while.zig");
142142 _ = @import("behavior/widening.zig");
143143 _ = @import("behavior/src.zig");
144 // _ = @import("behavior/translate_c_macros.zig");
144 _ = @import("behavior/translate_c_macros.zig");
145145}
test/stage2/arm.zig+34
......@@ -344,4 +344,38 @@ pub fn addCases(ctx: *TestContext) !void {
344344 "",
345345 );
346346 }
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 }
347381}
test/stage2/llvm.zig+68
......@@ -132,4 +132,72 @@ pub fn addCases(ctx: *TestContext) !void {
132132 \\}
133133 , "");
134134 }
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 }
135203}
test/stage2/test.zig+34-1
......@@ -985,7 +985,7 @@ pub fn addCases(ctx: *TestContext) !void {
985985 "Hello, World!\n",
986986 );
987987 try case.files.append(.{
988 .src =
988 .src =
989989 \\pub fn print() void {
990990 \\ asm volatile ("syscall"
991991 \\ :
......@@ -1525,4 +1525,37 @@ pub fn addCases(ctx: *TestContext) !void {
15251525 \\}
15261526 , "");
15271527 }
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 }
15281561}
tools/update_clang_options.zig+17-1
......@@ -268,6 +268,10 @@ const known_options = [_]KnownOpt{
268268 .name = "MD",
269269 .ident = "dep_file",
270270 },
271 .{
272 .name = "write-dependencies",
273 .ident = "dep_file",
274 },
271275 .{
272276 .name = "MV",
273277 .ident = "dep_file",
......@@ -284,18 +288,30 @@ const known_options = [_]KnownOpt{
284288 .name = "MG",
285289 .ident = "dep_file",
286290 },
291 .{
292 .name = "print-missing-file-dependencies",
293 .ident = "dep_file",
294 },
287295 .{
288296 .name = "MJ",
289297 .ident = "dep_file",
290298 },
291299 .{
292300 .name = "MM",
293 .ident = "dep_file",
301 .ident = "dep_file_mm",
302 },
303 .{
304 .name = "user-dependencies",
305 .ident = "dep_file_mm",
294306 },
295307 .{
296308 .name = "MMD",
297309 .ident = "dep_file",
298310 },
311 .{
312 .name = "write-user-dependencies",
313 .ident = "dep_file",
314 },
299315 .{
300316 .name = "MP",
301317 .ident = "dep_file",