mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
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.
This commit is contained in:
commit
bccef44196
@ -801,31 +801,32 @@ endif()
|
||||
|
||||
install(TARGETS zig DESTINATION bin)
|
||||
|
||||
set(ZIG_INSTALL_ARGS "build"
|
||||
--override-lib-dir "${CMAKE_SOURCE_DIR}/lib"
|
||||
"-Dlib-files-only"
|
||||
--prefix "${CMAKE_INSTALL_PREFIX}"
|
||||
"-Dconfig_h=${ZIG_CONFIG_H_OUT}"
|
||||
install
|
||||
)
|
||||
set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL
|
||||
"Disable copying lib/ files to install prefix during the build phase")
|
||||
|
||||
# CODE has no effect with Visual Studio build system generator, therefore
|
||||
# when using Visual Studio build system generator we resort to running
|
||||
# `zig build install` during the build phase.
|
||||
if(MSVC)
|
||||
set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL
|
||||
"Windows-only: Disable copying lib/ files to install prefix during the build phase")
|
||||
if(NOT ZIG_SKIP_INSTALL_LIB_FILES)
|
||||
if(NOT ZIG_SKIP_INSTALL_LIB_FILES)
|
||||
set(ZIG_INSTALL_ARGS "build"
|
||||
--override-lib-dir "${CMAKE_SOURCE_DIR}/lib"
|
||||
"-Dlib-files-only"
|
||||
--prefix "${CMAKE_INSTALL_PREFIX}"
|
||||
"-Dconfig_h=${ZIG_CONFIG_H_OUT}"
|
||||
install
|
||||
)
|
||||
|
||||
# CODE has no effect with Visual Studio build system generator, therefore
|
||||
# when using Visual Studio build system generator we resort to running
|
||||
# `zig build install` during the build phase.
|
||||
if(MSVC)
|
||||
add_custom_target(zig_install_lib_files ALL
|
||||
COMMAND zig ${ZIG_INSTALL_ARGS}
|
||||
DEPENDS zig
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
||||
)
|
||||
else()
|
||||
get_target_property(zig_BINARY_DIR zig BINARY_DIR)
|
||||
install(CODE "set(zig_EXE \"${ZIG_EXECUTABLE}\")")
|
||||
install(CODE "set(ZIG_INSTALL_ARGS \"${ZIG_INSTALL_ARGS}\")")
|
||||
install(CODE "set(CMAKE_SOURCE_DIR \"${CMAKE_SOURCE_DIR}\")")
|
||||
install(SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/cmake/install.cmake)
|
||||
endif()
|
||||
else()
|
||||
get_target_property(zig_BINARY_DIR zig BINARY_DIR)
|
||||
install(CODE "set(zig_EXE \"${ZIG_EXECUTABLE}\")")
|
||||
install(CODE "set(ZIG_INSTALL_ARGS \"${ZIG_INSTALL_ARGS}\")")
|
||||
install(CODE "set(CMAKE_SOURCE_DIR \"${CMAKE_SOURCE_DIR}\")")
|
||||
install(SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/cmake/install.cmake)
|
||||
endif()
|
||||
|
||||
@ -10447,13 +10447,40 @@ fn readU32Be() u32 {}
|
||||
{#header_close#}
|
||||
{#header_open|Source Encoding#}
|
||||
<p>Zig source code is encoded in UTF-8. An invalid UTF-8 byte sequence results in a compile error.</p>
|
||||
<p>Throughout all zig source code (including in comments), some codepoints are never allowed:</p>
|
||||
<p>Throughout all zig source code (including in comments), some code points are never allowed:</p>
|
||||
<ul>
|
||||
<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>
|
||||
<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>
|
||||
<li>Non-Ascii Unicode line endings: U+0085 (NEL), U+2028 (LS), U+2029 (PS).</li>
|
||||
</ul>
|
||||
<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>
|
||||
<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>
|
||||
<p>
|
||||
LF (byte value 0x0a, code point U+000a, {#syntax#}'\n'{#endsyntax#}) is the line terminator in Zig source code.
|
||||
This byte value terminates every line of zig source code except the last line of the file.
|
||||
It is recommended that non-empty source files end with an empty line, which means the last byte would be 0x0a (LF).
|
||||
</p>
|
||||
<p>
|
||||
Each LF may be immediately preceded by a single CR (byte value 0x0d, code point U+000d, {#syntax#}'\r'{#endsyntax#})
|
||||
to form a Windows style line ending, but this is discouraged.
|
||||
A CR in any other context is not allowed.
|
||||
</p>
|
||||
<p>
|
||||
HT hard tabs (byte value 0x09, code point U+0009, {#syntax#}'\t'{#endsyntax#}) are interchangeable with
|
||||
SP spaces (byte value 0x20, code point U+0020, {#syntax#}' '{#endsyntax#}) as a token separator,
|
||||
but use of hard tabs is discouraged. See {#link|Grammar#}.
|
||||
</p>
|
||||
<p>
|
||||
Note that running <code>zig fmt</code> on a source file will implement all recommendations mentioned here.
|
||||
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.
|
||||
</p>
|
||||
<p>
|
||||
Note that a tool reading Zig source code can make assumptions if the source code is assumed to be correct Zig code.
|
||||
For example, when identifying the ends of lines, a tool can use a naive search such as <code>/\n/</code>,
|
||||
or an <a href="https://msdn.microsoft.com/en-us/library/dd409797.aspx">advanced</a>
|
||||
search such as <code>/\r\n?|[\n\u0085\u2028\u2029]/</code>, and in either case line endings will be correctly identified.
|
||||
For another example, when identifying the whitespace before the first token on a line,
|
||||
a tool can either use a naive search such as <code>/[ \t]/</code>,
|
||||
or an <a href="https://tc39.es/ecma262/#sec-characterclassescape">advanced</a> search such as <code>/\s/</code>,
|
||||
and in either case whitespace will be correctly identified.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|Keyword Reference#}
|
||||
@ -11373,6 +11400,7 @@ ExprList <- (Expr COMMA)* Expr?
|
||||
|
||||
# *** Tokens ***
|
||||
eof <- !.
|
||||
eol <- ('\r'? '\n') | eof
|
||||
hex <- [0-9a-fA-F]
|
||||
hex_ <- ('_'/hex)
|
||||
dec <- [0-9]
|
||||
@ -11382,39 +11410,39 @@ dec_int <- dec (dec_* dec)?
|
||||
hex_int <- hex (hex_* dec)?
|
||||
|
||||
char_escape
|
||||
<- "\\x" hex hex
|
||||
/ "\\u{" hex+ "}"
|
||||
/ "\\" [nr\\t'"]
|
||||
<- '\\x' hex hex
|
||||
/ '\\u{' hex+ '}'
|
||||
/ '\\' [nr\\t'"]
|
||||
char_char
|
||||
<- char_escape
|
||||
/ [^\\'\n]
|
||||
/ [^\\'\r\n]
|
||||
string_char
|
||||
<- char_escape
|
||||
/ [^\\"\n]
|
||||
/ [^\\"\r\n]
|
||||
|
||||
line_comment <- '//'[^\n]*
|
||||
line_string <- ("\\\\" [^\n]* [ \n]*)+
|
||||
skip <- ([ \n] / line_comment)*
|
||||
line_comment <- '//'[^\r\n]* eol
|
||||
line_string <- ('\\\\' [^\r\n]* eol skip)+
|
||||
skip <- ([ \t] / eol / line_comment)*
|
||||
|
||||
CHAR_LITERAL <- "'" char_char "'" skip
|
||||
FLOAT
|
||||
<- "0x" hex_* hex "." hex_int ([pP] [-+]? hex_int)? skip
|
||||
/ dec_int "." dec_int ([eE] [-+]? dec_int)? skip
|
||||
/ "0x" hex_* hex "."? [pP] [-+]? hex_int skip
|
||||
/ dec_int "."? [eE] [-+]? dec_int skip
|
||||
<- '0x' hex_* hex '.' hex_int ([pP] [-+]? hex_int)? skip
|
||||
/ dec_int '.' dec_int ([eE] [-+]? dec_int)? skip
|
||||
/ '0x' hex_* hex '.'? [pP] [-+]? hex_int skip
|
||||
/ dec_int '.'? [eE] [-+]? dec_int skip
|
||||
INTEGER
|
||||
<- "0b" [_01]* [01] skip
|
||||
/ "0o" [_0-7]* [0-7] skip
|
||||
/ "0x" hex_* hex skip
|
||||
<- '0b' [_01]* [01] skip
|
||||
/ '0o' [_0-7]* [0-7] skip
|
||||
/ '0x' hex_* hex skip
|
||||
/ dec_int skip
|
||||
STRINGLITERALSINGLE <- "\"" string_char* "\"" skip
|
||||
STRINGLITERALSINGLE <- '"' string_char* '"' skip
|
||||
STRINGLITERAL
|
||||
<- STRINGLITERALSINGLE
|
||||
/ line_string skip
|
||||
/ line_string skip
|
||||
IDENTIFIER
|
||||
<- !keyword [A-Za-z_] [A-Za-z0-9_]* skip
|
||||
/ "@\"" string_char* "\"" skip
|
||||
BUILTINIDENTIFIER <- "@"[A-Za-z_][A-Za-z0-9_]* skip
|
||||
/ '@"' string_char* '"' skip
|
||||
BUILTINIDENTIFIER <- '@'[A-Za-z_][A-Za-z0-9_]* skip
|
||||
|
||||
|
||||
AMPERSAND <- '&' ![=] skip
|
||||
|
||||
1255
lib/std/bit_set.zig
Normal file
1255
lib/std/bit_set.zig
Normal file
File diff suppressed because it is too large
Load Diff
@ -51,9 +51,9 @@ const BinaryElfOutput = struct {
|
||||
.segments = ArrayList(*BinaryElfSegment).init(allocator),
|
||||
.sections = ArrayList(*BinaryElfSection).init(allocator),
|
||||
};
|
||||
const elf_hdr = try std.elf.readHeader(elf_file);
|
||||
const elf_hdr = try std.elf.Header.read(&elf_file);
|
||||
|
||||
var section_headers = elf_hdr.section_header_iterator(elf_file);
|
||||
var section_headers = elf_hdr.section_header_iterator(&elf_file);
|
||||
while (try section_headers.next()) |section| {
|
||||
if (sectionValidForOutput(section)) {
|
||||
const newSection = try allocator.create(BinaryElfSection);
|
||||
@ -67,7 +67,7 @@ const BinaryElfOutput = struct {
|
||||
}
|
||||
}
|
||||
|
||||
var program_headers = elf_hdr.program_header_iterator(elf_file);
|
||||
var program_headers = elf_hdr.program_header_iterator(&elf_file);
|
||||
while (try program_headers.next()) |phdr| {
|
||||
if (phdr.p_type == elf.PT_LOAD) {
|
||||
const newSegment = try allocator.create(BinaryElfSegment);
|
||||
|
||||
@ -401,7 +401,9 @@ pub const Tokenizer = struct {
|
||||
Zero,
|
||||
IntegerLiteralOct,
|
||||
IntegerLiteralBinary,
|
||||
IntegerLiteralBinaryFirst,
|
||||
IntegerLiteralHex,
|
||||
IntegerLiteralHexFirst,
|
||||
IntegerLiteral,
|
||||
IntegerSuffix,
|
||||
IntegerSuffixU,
|
||||
@ -1046,10 +1048,10 @@ pub const Tokenizer = struct {
|
||||
state = .IntegerLiteralOct;
|
||||
},
|
||||
'b', 'B' => {
|
||||
state = .IntegerLiteralBinary;
|
||||
state = .IntegerLiteralBinaryFirst;
|
||||
},
|
||||
'x', 'X' => {
|
||||
state = .IntegerLiteralHex;
|
||||
state = .IntegerLiteralHexFirst;
|
||||
},
|
||||
'.' => {
|
||||
state = .FloatFraction;
|
||||
@ -1066,6 +1068,13 @@ pub const Tokenizer = struct {
|
||||
self.index -= 1;
|
||||
},
|
||||
},
|
||||
.IntegerLiteralBinaryFirst => switch (c) {
|
||||
'0'...'7' => state = .IntegerLiteralBinary,
|
||||
else => {
|
||||
result.id = .Invalid;
|
||||
break;
|
||||
},
|
||||
},
|
||||
.IntegerLiteralBinary => switch (c) {
|
||||
'0', '1' => {},
|
||||
else => {
|
||||
@ -1073,6 +1082,19 @@ pub const Tokenizer = struct {
|
||||
self.index -= 1;
|
||||
},
|
||||
},
|
||||
.IntegerLiteralHexFirst => switch (c) {
|
||||
'0'...'9', 'a'...'f', 'A'...'F' => state = .IntegerLiteralHex,
|
||||
'.' => {
|
||||
state = .FloatFractionHex;
|
||||
},
|
||||
'p', 'P' => {
|
||||
state = .FloatExponent;
|
||||
},
|
||||
else => {
|
||||
result.id = .Invalid;
|
||||
break;
|
||||
},
|
||||
},
|
||||
.IntegerLiteralHex => switch (c) {
|
||||
'0'...'9', 'a'...'f', 'A'...'F' => {},
|
||||
'.' => {
|
||||
@ -1238,6 +1260,8 @@ pub const Tokenizer = struct {
|
||||
.MultiLineCommentAsterisk,
|
||||
.FloatExponent,
|
||||
.MacroString,
|
||||
.IntegerLiteralBinaryFirst,
|
||||
.IntegerLiteralHexFirst,
|
||||
=> result.id = .Invalid,
|
||||
|
||||
.FloatExponentDigits => result.id = if (counter == 0) .Invalid else .{ .FloatLiteral = .none },
|
||||
@ -1523,6 +1547,7 @@ test "num suffixes" {
|
||||
\\ 1.0f 1.0L 1.0 .0 1.
|
||||
\\ 0l 0lu 0ll 0llu 0
|
||||
\\ 1u 1ul 1ull 1
|
||||
\\ 0x 0b
|
||||
\\
|
||||
, &[_]Token.Id{
|
||||
.{ .FloatLiteral = .f },
|
||||
@ -1542,6 +1567,9 @@ test "num suffixes" {
|
||||
.{ .IntegerLiteral = .llu },
|
||||
.{ .IntegerLiteral = .none },
|
||||
.Nl,
|
||||
.Invalid,
|
||||
.Invalid,
|
||||
.Nl,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -115,9 +115,9 @@ test "curve25519" {
|
||||
const p = try Curve25519.basePoint.clampedMul(s);
|
||||
try p.rejectIdentity();
|
||||
var buf: [128]u8 = undefined;
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{p.toBytes()}), "E6F2A4D1C28EE5C7AD0329268255A468AD407D2672824C0C0EB30EA6EF450145");
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&p.toBytes())}), "E6F2A4D1C28EE5C7AD0329268255A468AD407D2672824C0C0EB30EA6EF450145");
|
||||
const q = try p.clampedMul(s);
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{q.toBytes()}), "3614E119FFE55EC55B87D6B19971A9F4CBC78EFE80BEC55B96392BABCC712537");
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&q.toBytes())}), "3614E119FFE55EC55B87D6B19971A9F4CBC78EFE80BEC55B96392BABCC712537");
|
||||
|
||||
try Curve25519.rejectNonCanonical(s);
|
||||
s[31] |= 0x80;
|
||||
|
||||
@ -210,8 +210,8 @@ test "ed25519 key pair creation" {
|
||||
_ = try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
|
||||
const key_pair = try Ed25519.KeyPair.create(seed);
|
||||
var buf: [256]u8 = undefined;
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{key_pair.secret_key}), "8052030376D47112BE7F73ED7A019293DD12AD910B654455798B4667D73DE1662D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{key_pair.public_key}), "2D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&key_pair.secret_key)}), "8052030376D47112BE7F73ED7A019293DD12AD910B654455798B4667D73DE1662D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&key_pair.public_key)}), "2D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
|
||||
}
|
||||
|
||||
test "ed25519 signature" {
|
||||
@ -221,7 +221,7 @@ test "ed25519 signature" {
|
||||
|
||||
const sig = try Ed25519.sign("test", key_pair, null);
|
||||
var buf: [128]u8 = undefined;
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{sig}), "10A442B4A80CC4225B154F43BEF28D2472CA80221951262EB8E0DF9091575E2687CC486E77263C3418C757522D54F84B0359236ABBBD4ACD20DC297FDCA66808");
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&sig)}), "10A442B4A80CC4225B154F43BEF28D2472CA80221951262EB8E0DF9091575E2687CC486E77263C3418C757522D54F84B0359236ABBBD4ACD20DC297FDCA66808");
|
||||
try Ed25519.verify(sig, "test", key_pair.public_key);
|
||||
std.testing.expectError(error.InvalidSignature, Ed25519.verify(sig, "TEST", key_pair.public_key));
|
||||
}
|
||||
|
||||
@ -450,7 +450,7 @@ test "edwards25519 packing/unpacking" {
|
||||
var b = Edwards25519.basePoint;
|
||||
const pk = try b.mul(s);
|
||||
var buf: [128]u8 = undefined;
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{pk.toBytes()}), "074BC7E0FCBD587FDBC0969444245FADC562809C8F6E97E949AF62484B5B81A6");
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&pk.toBytes())}), "074BC7E0FCBD587FDBC0969444245FADC562809C8F6E97E949AF62484B5B81A6");
|
||||
|
||||
const small_order_ss: [7][32]u8 = .{
|
||||
.{
|
||||
|
||||
@ -170,21 +170,21 @@ pub const Ristretto255 = struct {
|
||||
test "ristretto255" {
|
||||
const p = Ristretto255.basePoint;
|
||||
var buf: [256]u8 = undefined;
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{p.toBytes()}), "E2F2AE0A6ABC4E71A884A961C500515F58E30B6AA582DD8DB6A65945E08D2D76");
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&p.toBytes())}), "E2F2AE0A6ABC4E71A884A961C500515F58E30B6AA582DD8DB6A65945E08D2D76");
|
||||
|
||||
var r: [Ristretto255.encoded_length]u8 = undefined;
|
||||
_ = try fmt.hexToBytes(r[0..], "6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919");
|
||||
var q = try Ristretto255.fromBytes(r);
|
||||
q = q.dbl().add(p);
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{q.toBytes()}), "E882B131016B52C1D3337080187CF768423EFCCBB517BB495AB812C4160FF44E");
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&q.toBytes())}), "E882B131016B52C1D3337080187CF768423EFCCBB517BB495AB812C4160FF44E");
|
||||
|
||||
const s = [_]u8{15} ++ [_]u8{0} ** 31;
|
||||
const w = try p.mul(s);
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{w.toBytes()}), "E0C418F7C8D9C4CDD7395B93EA124F3AD99021BB681DFC3302A9D99A2E53E64E");
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&w.toBytes())}), "E0C418F7C8D9C4CDD7395B93EA124F3AD99021BB681DFC3302A9D99A2E53E64E");
|
||||
|
||||
std.testing.expect(p.dbl().dbl().dbl().dbl().equivalent(w.add(p)));
|
||||
|
||||
const h = [_]u8{69} ** 32 ++ [_]u8{42} ** 32;
|
||||
const ph = Ristretto255.fromUniform(h);
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{ph.toBytes()}), "DCCA54E037A4311EFBEEF413ACD21D35276518970B7A61DC88F8587B493D5E19");
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&ph.toBytes())}), "DCCA54E037A4311EFBEEF413ACD21D35276518970B7A61DC88F8587B493D5E19");
|
||||
}
|
||||
|
||||
@ -771,10 +771,10 @@ test "scalar25519" {
|
||||
var y = x.toBytes();
|
||||
try rejectNonCanonical(y);
|
||||
var buf: [128]u8 = undefined;
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{y}), "1E979B917937F3DE71D18077F961F6CEFF01030405060708010203040506070F");
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&y)}), "1E979B917937F3DE71D18077F961F6CEFF01030405060708010203040506070F");
|
||||
|
||||
const reduced = reduce(field_size);
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{reduced}), "0000000000000000000000000000000000000000000000000000000000000000");
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&reduced)}), "0000000000000000000000000000000000000000000000000000000000000000");
|
||||
}
|
||||
|
||||
test "non-canonical scalar25519" {
|
||||
@ -788,5 +788,5 @@ test "mulAdd overflow check" {
|
||||
const c: [32]u8 = [_]u8{0xff} ** 32;
|
||||
const x = mulAdd(a, b, c);
|
||||
var buf: [128]u8 = undefined;
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{x}), "D14DF91389432C25AD60FF9791B9FD1D67BEF517D273ECCE3D9A307C1B419903");
|
||||
std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&x)}), "D14DF91389432C25AD60FF9791B9FD1D67BEF517D273ECCE3D9A307C1B419903");
|
||||
}
|
||||
|
||||
@ -876,7 +876,7 @@ test "crypto.xchacha20" {
|
||||
var ciphertext: [input.len]u8 = undefined;
|
||||
XChaCha20IETF.xor(ciphertext[0..], input[0..], 0, key, nonce);
|
||||
var buf: [2 * ciphertext.len]u8 = undefined;
|
||||
testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{ciphertext}), "E0A1BCF939654AFDBDC1746EC49832647C19D891F0D1A81FC0C1703B4514BDEA584B512F6908C2C5E9DD18D5CBC1805DE5803FE3B9CA5F193FB8359E91FAB0C3BB40309A292EB1CF49685C65C4A3ADF4F11DB0CD2B6B67FBC174BC2E860E8F769FD3565BBFAD1C845E05A0FED9BE167C240D");
|
||||
testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&ciphertext)}), "E0A1BCF939654AFDBDC1746EC49832647C19D891F0D1A81FC0C1703B4514BDEA584B512F6908C2C5E9DD18D5CBC1805DE5803FE3B9CA5F193FB8359E91FAB0C3BB40309A292EB1CF49685C65C4A3ADF4F11DB0CD2B6B67FBC174BC2E860E8F769FD3565BBFAD1C845E05A0FED9BE167C240D");
|
||||
}
|
||||
{
|
||||
const data = "Additional data";
|
||||
@ -885,7 +885,7 @@ test "crypto.xchacha20" {
|
||||
var out: [input.len]u8 = undefined;
|
||||
try xchacha20poly1305Open(out[0..], ciphertext[0..], data, key, nonce);
|
||||
var buf: [2 * ciphertext.len]u8 = undefined;
|
||||
testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{ciphertext}), "994D2DD32333F48E53650C02C7A2ABB8E018B0836D7175AEC779F52E961780768F815C58F1AA52D211498DB89B9216763F569C9433A6BBFCEFB4D4A49387A4C5207FBB3B5A92B5941294DF30588C6740D39DC16FA1F0E634F7246CF7CDCB978E44347D89381B7A74EB7084F754B90BDE9AAF5A94B8F2A85EFD0B50692AE2D425E234");
|
||||
testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&ciphertext)}), "994D2DD32333F48E53650C02C7A2ABB8E018B0836D7175AEC779F52E961780768F815C58F1AA52D211498DB89B9216763F569C9433A6BBFCEFB4D4A49387A4C5207FBB3B5A92B5941294DF30588C6740D39DC16FA1F0E634F7246CF7CDCB978E44347D89381B7A74EB7084F754B90BDE9AAF5A94B8F2A85EFD0B50692AE2D425E234");
|
||||
testing.expectEqualSlices(u8, out[0..], input);
|
||||
ciphertext[0] += 1;
|
||||
testing.expectError(error.AuthenticationFailed, xchacha20poly1305Open(out[0..], ciphertext[0..], data, key, nonce));
|
||||
|
||||
@ -360,14 +360,24 @@ pub const StackIterator = struct {
|
||||
};
|
||||
}
|
||||
|
||||
// Negative offset of the saved BP wrt the frame pointer.
|
||||
// Offset of the saved BP wrt the frame pointer.
|
||||
const fp_offset = if (builtin.arch.isRISCV())
|
||||
// On RISC-V the frame pointer points to the top of the saved register
|
||||
// area, on pretty much every other architecture it points to the stack
|
||||
// slot where the previous frame pointer is saved.
|
||||
2 * @sizeOf(usize)
|
||||
else if (builtin.arch.isSPARC())
|
||||
// On SPARC the previous frame pointer is stored at 14 slots past %fp+BIAS.
|
||||
14 * @sizeOf(usize)
|
||||
else
|
||||
0;
|
||||
|
||||
const fp_bias = if (builtin.arch.isSPARC())
|
||||
// On SPARC frame pointers are biased by a constant.
|
||||
2047
|
||||
else
|
||||
0;
|
||||
|
||||
// Positive offset of the saved PC wrt the frame pointer.
|
||||
const pc_offset = if (builtin.arch == .powerpc64le)
|
||||
2 * @sizeOf(usize)
|
||||
@ -388,13 +398,17 @@ pub const StackIterator = struct {
|
||||
}
|
||||
|
||||
fn next_internal(self: *StackIterator) ?usize {
|
||||
const fp = math.sub(usize, self.fp, fp_offset) catch return null;
|
||||
const fp = if (builtin.arch.isSPARC())
|
||||
// On SPARC the offset is positive. (!)
|
||||
math.add(usize, self.fp, fp_offset) catch return null
|
||||
else
|
||||
math.sub(usize, self.fp, fp_offset) catch return null;
|
||||
|
||||
// Sanity check.
|
||||
if (fp == 0 or !mem.isAligned(fp, @alignOf(usize)))
|
||||
return null;
|
||||
|
||||
const new_fp = @intToPtr(*const usize, fp).*;
|
||||
const new_fp = math.add(usize, @intToPtr(*const usize, fp).*, fp_bias) catch return null;
|
||||
|
||||
// Sanity check: the stack grows down thus all the parent frames must be
|
||||
// be at addresses that are greater (or equal) than the previous one.
|
||||
|
||||
351
lib/std/elf.zig
351
lib/std/elf.zig
@ -335,7 +335,7 @@ pub const ET = extern enum(u16) {
|
||||
};
|
||||
|
||||
/// All integers are native endian.
|
||||
const Header = struct {
|
||||
pub const Header = struct {
|
||||
endian: builtin.Endian,
|
||||
is_64: bool,
|
||||
entry: u64,
|
||||
@ -347,187 +347,200 @@ const Header = struct {
|
||||
shnum: u16,
|
||||
shstrndx: u16,
|
||||
|
||||
pub fn program_header_iterator(self: Header, file: File) ProgramHeaderIterator {
|
||||
return .{
|
||||
pub fn program_header_iterator(self: Header, parse_source: anytype) ProgramHeaderIterator(@TypeOf(parse_source)) {
|
||||
return ProgramHeaderIterator(@TypeOf(parse_source)){
|
||||
.elf_header = self,
|
||||
.file = file,
|
||||
.parse_source = parse_source,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn section_header_iterator(self: Header, file: File) SectionHeaderIterator {
|
||||
return .{
|
||||
pub fn section_header_iterator(self: Header, parse_source: anytype) SectionHeaderIterator(@TypeOf(parse_source)) {
|
||||
return SectionHeaderIterator(@TypeOf(parse_source)){
|
||||
.elf_header = self,
|
||||
.file = file,
|
||||
.parse_source = parse_source,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn read(parse_source: anytype) !Header {
|
||||
var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined;
|
||||
try parse_source.seekableStream().seekTo(0);
|
||||
try parse_source.reader().readNoEof(&hdr_buf);
|
||||
return Header.parse(&hdr_buf);
|
||||
}
|
||||
|
||||
pub fn parse(hdr_buf: *align(@alignOf(Elf64_Ehdr)) const [@sizeOf(Elf64_Ehdr)]u8) !Header {
|
||||
const hdr32 = @ptrCast(*const Elf32_Ehdr, hdr_buf);
|
||||
const hdr64 = @ptrCast(*const Elf64_Ehdr, hdr_buf);
|
||||
if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
|
||||
if (hdr32.e_ident[EI_VERSION] != 1) return error.InvalidElfVersion;
|
||||
|
||||
const endian: std.builtin.Endian = switch (hdr32.e_ident[EI_DATA]) {
|
||||
ELFDATA2LSB => .Little,
|
||||
ELFDATA2MSB => .Big,
|
||||
else => return error.InvalidElfEndian,
|
||||
};
|
||||
const need_bswap = endian != std.builtin.endian;
|
||||
|
||||
const is_64 = switch (hdr32.e_ident[EI_CLASS]) {
|
||||
ELFCLASS32 => false,
|
||||
ELFCLASS64 => true,
|
||||
else => return error.InvalidElfClass,
|
||||
};
|
||||
|
||||
return @as(Header, .{
|
||||
.endian = endian,
|
||||
.is_64 = is_64,
|
||||
.entry = int(is_64, need_bswap, hdr32.e_entry, hdr64.e_entry),
|
||||
.phoff = int(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff),
|
||||
.shoff = int(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff),
|
||||
.phentsize = int(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize),
|
||||
.phnum = int(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum),
|
||||
.shentsize = int(is_64, need_bswap, hdr32.e_shentsize, hdr64.e_shentsize),
|
||||
.shnum = int(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum),
|
||||
.shstrndx = int(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
pub fn readHeader(file: File) !Header {
|
||||
var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined;
|
||||
try preadNoEof(file, &hdr_buf, 0);
|
||||
const hdr32 = @ptrCast(*Elf32_Ehdr, &hdr_buf);
|
||||
const hdr64 = @ptrCast(*Elf64_Ehdr, &hdr_buf);
|
||||
if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
|
||||
if (hdr32.e_ident[EI_VERSION] != 1) return error.InvalidElfVersion;
|
||||
pub fn ProgramHeaderIterator(ParseSource: anytype) type {
|
||||
return struct {
|
||||
elf_header: Header,
|
||||
parse_source: ParseSource,
|
||||
index: usize = 0,
|
||||
|
||||
const endian: std.builtin.Endian = switch (hdr32.e_ident[EI_DATA]) {
|
||||
ELFDATA2LSB => .Little,
|
||||
ELFDATA2MSB => .Big,
|
||||
else => return error.InvalidElfEndian,
|
||||
pub fn next(self: *@This()) !?Elf64_Phdr {
|
||||
if (self.index >= self.elf_header.phnum) return null;
|
||||
defer self.index += 1;
|
||||
|
||||
if (self.elf_header.is_64) {
|
||||
var phdr: Elf64_Phdr = undefined;
|
||||
const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index;
|
||||
try self.parse_source.seekableStream().seekTo(offset);
|
||||
try self.parse_source.reader().readNoEof(mem.asBytes(&phdr));
|
||||
|
||||
// ELF endianness matches native endianness.
|
||||
if (self.elf_header.endian == std.builtin.endian) return phdr;
|
||||
|
||||
// Convert fields to native endianness.
|
||||
return Elf64_Phdr{
|
||||
.p_type = @byteSwap(@TypeOf(phdr.p_type), phdr.p_type),
|
||||
.p_offset = @byteSwap(@TypeOf(phdr.p_offset), phdr.p_offset),
|
||||
.p_vaddr = @byteSwap(@TypeOf(phdr.p_vaddr), phdr.p_vaddr),
|
||||
.p_paddr = @byteSwap(@TypeOf(phdr.p_paddr), phdr.p_paddr),
|
||||
.p_filesz = @byteSwap(@TypeOf(phdr.p_filesz), phdr.p_filesz),
|
||||
.p_memsz = @byteSwap(@TypeOf(phdr.p_memsz), phdr.p_memsz),
|
||||
.p_flags = @byteSwap(@TypeOf(phdr.p_flags), phdr.p_flags),
|
||||
.p_align = @byteSwap(@TypeOf(phdr.p_align), phdr.p_align),
|
||||
};
|
||||
}
|
||||
|
||||
var phdr: Elf32_Phdr = undefined;
|
||||
const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index;
|
||||
try self.parse_source.seekableStream().seekTo(offset);
|
||||
try self.parse_source.reader().readNoEof(mem.asBytes(&phdr));
|
||||
|
||||
// ELF endianness does NOT match native endianness.
|
||||
if (self.elf_header.endian != std.builtin.endian) {
|
||||
// Convert fields to native endianness.
|
||||
phdr = .{
|
||||
.p_type = @byteSwap(@TypeOf(phdr.p_type), phdr.p_type),
|
||||
.p_offset = @byteSwap(@TypeOf(phdr.p_offset), phdr.p_offset),
|
||||
.p_vaddr = @byteSwap(@TypeOf(phdr.p_vaddr), phdr.p_vaddr),
|
||||
.p_paddr = @byteSwap(@TypeOf(phdr.p_paddr), phdr.p_paddr),
|
||||
.p_filesz = @byteSwap(@TypeOf(phdr.p_filesz), phdr.p_filesz),
|
||||
.p_memsz = @byteSwap(@TypeOf(phdr.p_memsz), phdr.p_memsz),
|
||||
.p_flags = @byteSwap(@TypeOf(phdr.p_flags), phdr.p_flags),
|
||||
.p_align = @byteSwap(@TypeOf(phdr.p_align), phdr.p_align),
|
||||
};
|
||||
}
|
||||
|
||||
// Convert 32-bit header to 64-bit.
|
||||
return Elf64_Phdr{
|
||||
.p_type = phdr.p_type,
|
||||
.p_offset = phdr.p_offset,
|
||||
.p_vaddr = phdr.p_vaddr,
|
||||
.p_paddr = phdr.p_paddr,
|
||||
.p_filesz = phdr.p_filesz,
|
||||
.p_memsz = phdr.p_memsz,
|
||||
.p_flags = phdr.p_flags,
|
||||
.p_align = phdr.p_align,
|
||||
};
|
||||
}
|
||||
};
|
||||
const need_bswap = endian != std.builtin.endian;
|
||||
|
||||
const is_64 = switch (hdr32.e_ident[EI_CLASS]) {
|
||||
ELFCLASS32 => false,
|
||||
ELFCLASS64 => true,
|
||||
else => return error.InvalidElfClass,
|
||||
};
|
||||
|
||||
return @as(Header, .{
|
||||
.endian = endian,
|
||||
.is_64 = is_64,
|
||||
.entry = int(is_64, need_bswap, hdr32.e_entry, hdr64.e_entry),
|
||||
.phoff = int(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff),
|
||||
.shoff = int(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff),
|
||||
.phentsize = int(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize),
|
||||
.phnum = int(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum),
|
||||
.shentsize = int(is_64, need_bswap, hdr32.e_shentsize, hdr64.e_shentsize),
|
||||
.shnum = int(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum),
|
||||
.shstrndx = int(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx),
|
||||
});
|
||||
}
|
||||
|
||||
pub const ProgramHeaderIterator = struct {
|
||||
elf_header: Header,
|
||||
file: File,
|
||||
index: usize = 0,
|
||||
pub fn SectionHeaderIterator(ParseSource: anytype) type {
|
||||
return struct {
|
||||
elf_header: Header,
|
||||
parse_source: ParseSource,
|
||||
index: usize = 0,
|
||||
|
||||
pub fn next(self: *ProgramHeaderIterator) !?Elf64_Phdr {
|
||||
if (self.index >= self.elf_header.phnum) return null;
|
||||
defer self.index += 1;
|
||||
pub fn next(self: *@This()) !?Elf64_Shdr {
|
||||
if (self.index >= self.elf_header.shnum) return null;
|
||||
defer self.index += 1;
|
||||
|
||||
if (self.elf_header.is_64) {
|
||||
var phdr: Elf64_Phdr = undefined;
|
||||
const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index;
|
||||
try preadNoEof(self.file, mem.asBytes(&phdr), offset);
|
||||
if (self.elf_header.is_64) {
|
||||
var shdr: Elf64_Shdr = undefined;
|
||||
const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index;
|
||||
try self.parse_source.seekableStream().seekTo(offset);
|
||||
try self.parse_source.reader().readNoEof(mem.asBytes(&shdr));
|
||||
|
||||
// ELF endianness matches native endianness.
|
||||
if (self.elf_header.endian == std.builtin.endian) return phdr;
|
||||
// ELF endianness matches native endianness.
|
||||
if (self.elf_header.endian == std.builtin.endian) return shdr;
|
||||
|
||||
// Convert fields to native endianness.
|
||||
return Elf64_Phdr{
|
||||
.p_type = @byteSwap(@TypeOf(phdr.p_type), phdr.p_type),
|
||||
.p_offset = @byteSwap(@TypeOf(phdr.p_offset), phdr.p_offset),
|
||||
.p_vaddr = @byteSwap(@TypeOf(phdr.p_vaddr), phdr.p_vaddr),
|
||||
.p_paddr = @byteSwap(@TypeOf(phdr.p_paddr), phdr.p_paddr),
|
||||
.p_filesz = @byteSwap(@TypeOf(phdr.p_filesz), phdr.p_filesz),
|
||||
.p_memsz = @byteSwap(@TypeOf(phdr.p_memsz), phdr.p_memsz),
|
||||
.p_flags = @byteSwap(@TypeOf(phdr.p_flags), phdr.p_flags),
|
||||
.p_align = @byteSwap(@TypeOf(phdr.p_align), phdr.p_align),
|
||||
};
|
||||
}
|
||||
// Convert fields to native endianness.
|
||||
return Elf64_Shdr{
|
||||
.sh_name = @byteSwap(@TypeOf(shdr.sh_name), shdr.sh_name),
|
||||
.sh_type = @byteSwap(@TypeOf(shdr.sh_type), shdr.sh_type),
|
||||
.sh_flags = @byteSwap(@TypeOf(shdr.sh_flags), shdr.sh_flags),
|
||||
.sh_addr = @byteSwap(@TypeOf(shdr.sh_addr), shdr.sh_addr),
|
||||
.sh_offset = @byteSwap(@TypeOf(shdr.sh_offset), shdr.sh_offset),
|
||||
.sh_size = @byteSwap(@TypeOf(shdr.sh_size), shdr.sh_size),
|
||||
.sh_link = @byteSwap(@TypeOf(shdr.sh_link), shdr.sh_link),
|
||||
.sh_info = @byteSwap(@TypeOf(shdr.sh_info), shdr.sh_info),
|
||||
.sh_addralign = @byteSwap(@TypeOf(shdr.sh_addralign), shdr.sh_addralign),
|
||||
.sh_entsize = @byteSwap(@TypeOf(shdr.sh_entsize), shdr.sh_entsize),
|
||||
};
|
||||
}
|
||||
|
||||
var phdr: Elf32_Phdr = undefined;
|
||||
const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index;
|
||||
try preadNoEof(self.file, mem.asBytes(&phdr), offset);
|
||||
|
||||
// ELF endianness does NOT match native endianness.
|
||||
if (self.elf_header.endian != std.builtin.endian) {
|
||||
// Convert fields to native endianness.
|
||||
phdr = .{
|
||||
.p_type = @byteSwap(@TypeOf(phdr.p_type), phdr.p_type),
|
||||
.p_offset = @byteSwap(@TypeOf(phdr.p_offset), phdr.p_offset),
|
||||
.p_vaddr = @byteSwap(@TypeOf(phdr.p_vaddr), phdr.p_vaddr),
|
||||
.p_paddr = @byteSwap(@TypeOf(phdr.p_paddr), phdr.p_paddr),
|
||||
.p_filesz = @byteSwap(@TypeOf(phdr.p_filesz), phdr.p_filesz),
|
||||
.p_memsz = @byteSwap(@TypeOf(phdr.p_memsz), phdr.p_memsz),
|
||||
.p_flags = @byteSwap(@TypeOf(phdr.p_flags), phdr.p_flags),
|
||||
.p_align = @byteSwap(@TypeOf(phdr.p_align), phdr.p_align),
|
||||
};
|
||||
}
|
||||
|
||||
// Convert 32-bit header to 64-bit.
|
||||
return Elf64_Phdr{
|
||||
.p_type = phdr.p_type,
|
||||
.p_offset = phdr.p_offset,
|
||||
.p_vaddr = phdr.p_vaddr,
|
||||
.p_paddr = phdr.p_paddr,
|
||||
.p_filesz = phdr.p_filesz,
|
||||
.p_memsz = phdr.p_memsz,
|
||||
.p_flags = phdr.p_flags,
|
||||
.p_align = phdr.p_align,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const SectionHeaderIterator = struct {
|
||||
elf_header: Header,
|
||||
file: File,
|
||||
index: usize = 0,
|
||||
|
||||
pub fn next(self: *SectionHeaderIterator) !?Elf64_Shdr {
|
||||
if (self.index >= self.elf_header.shnum) return null;
|
||||
defer self.index += 1;
|
||||
|
||||
if (self.elf_header.is_64) {
|
||||
var shdr: Elf64_Shdr = undefined;
|
||||
var shdr: Elf32_Shdr = undefined;
|
||||
const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index;
|
||||
try preadNoEof(self.file, mem.asBytes(&shdr), offset);
|
||||
try self.parse_source.seekableStream().seekTo(offset);
|
||||
try self.parse_source.reader().readNoEof(mem.asBytes(&shdr));
|
||||
|
||||
// ELF endianness matches native endianness.
|
||||
if (self.elf_header.endian == std.builtin.endian) return shdr;
|
||||
// ELF endianness does NOT match native endianness.
|
||||
if (self.elf_header.endian != std.builtin.endian) {
|
||||
// Convert fields to native endianness.
|
||||
shdr = .{
|
||||
.sh_name = @byteSwap(@TypeOf(shdr.sh_name), shdr.sh_name),
|
||||
.sh_type = @byteSwap(@TypeOf(shdr.sh_type), shdr.sh_type),
|
||||
.sh_flags = @byteSwap(@TypeOf(shdr.sh_flags), shdr.sh_flags),
|
||||
.sh_addr = @byteSwap(@TypeOf(shdr.sh_addr), shdr.sh_addr),
|
||||
.sh_offset = @byteSwap(@TypeOf(shdr.sh_offset), shdr.sh_offset),
|
||||
.sh_size = @byteSwap(@TypeOf(shdr.sh_size), shdr.sh_size),
|
||||
.sh_link = @byteSwap(@TypeOf(shdr.sh_link), shdr.sh_link),
|
||||
.sh_info = @byteSwap(@TypeOf(shdr.sh_info), shdr.sh_info),
|
||||
.sh_addralign = @byteSwap(@TypeOf(shdr.sh_addralign), shdr.sh_addralign),
|
||||
.sh_entsize = @byteSwap(@TypeOf(shdr.sh_entsize), shdr.sh_entsize),
|
||||
};
|
||||
}
|
||||
|
||||
// Convert fields to native endianness.
|
||||
// Convert 32-bit header to 64-bit.
|
||||
return Elf64_Shdr{
|
||||
.sh_name = @byteSwap(@TypeOf(shdr.sh_name), shdr.sh_name),
|
||||
.sh_type = @byteSwap(@TypeOf(shdr.sh_type), shdr.sh_type),
|
||||
.sh_flags = @byteSwap(@TypeOf(shdr.sh_flags), shdr.sh_flags),
|
||||
.sh_addr = @byteSwap(@TypeOf(shdr.sh_addr), shdr.sh_addr),
|
||||
.sh_offset = @byteSwap(@TypeOf(shdr.sh_offset), shdr.sh_offset),
|
||||
.sh_size = @byteSwap(@TypeOf(shdr.sh_size), shdr.sh_size),
|
||||
.sh_link = @byteSwap(@TypeOf(shdr.sh_link), shdr.sh_link),
|
||||
.sh_info = @byteSwap(@TypeOf(shdr.sh_info), shdr.sh_info),
|
||||
.sh_addralign = @byteSwap(@TypeOf(shdr.sh_addralign), shdr.sh_addralign),
|
||||
.sh_entsize = @byteSwap(@TypeOf(shdr.sh_entsize), shdr.sh_entsize),
|
||||
.sh_name = shdr.sh_name,
|
||||
.sh_type = shdr.sh_type,
|
||||
.sh_flags = shdr.sh_flags,
|
||||
.sh_addr = shdr.sh_addr,
|
||||
.sh_offset = shdr.sh_offset,
|
||||
.sh_size = shdr.sh_size,
|
||||
.sh_link = shdr.sh_link,
|
||||
.sh_info = shdr.sh_info,
|
||||
.sh_addralign = shdr.sh_addralign,
|
||||
.sh_entsize = shdr.sh_entsize,
|
||||
};
|
||||
}
|
||||
|
||||
var shdr: Elf32_Shdr = undefined;
|
||||
const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index;
|
||||
try preadNoEof(self.file, mem.asBytes(&shdr), offset);
|
||||
|
||||
// ELF endianness does NOT match native endianness.
|
||||
if (self.elf_header.endian != std.builtin.endian) {
|
||||
// Convert fields to native endianness.
|
||||
shdr = .{
|
||||
.sh_name = @byteSwap(@TypeOf(shdr.sh_name), shdr.sh_name),
|
||||
.sh_type = @byteSwap(@TypeOf(shdr.sh_type), shdr.sh_type),
|
||||
.sh_flags = @byteSwap(@TypeOf(shdr.sh_flags), shdr.sh_flags),
|
||||
.sh_addr = @byteSwap(@TypeOf(shdr.sh_addr), shdr.sh_addr),
|
||||
.sh_offset = @byteSwap(@TypeOf(shdr.sh_offset), shdr.sh_offset),
|
||||
.sh_size = @byteSwap(@TypeOf(shdr.sh_size), shdr.sh_size),
|
||||
.sh_link = @byteSwap(@TypeOf(shdr.sh_link), shdr.sh_link),
|
||||
.sh_info = @byteSwap(@TypeOf(shdr.sh_info), shdr.sh_info),
|
||||
.sh_addralign = @byteSwap(@TypeOf(shdr.sh_addralign), shdr.sh_addralign),
|
||||
.sh_entsize = @byteSwap(@TypeOf(shdr.sh_entsize), shdr.sh_entsize),
|
||||
};
|
||||
}
|
||||
|
||||
// Convert 32-bit header to 64-bit.
|
||||
return Elf64_Shdr{
|
||||
.sh_name = shdr.sh_name,
|
||||
.sh_type = shdr.sh_type,
|
||||
.sh_flags = shdr.sh_flags,
|
||||
.sh_addr = shdr.sh_addr,
|
||||
.sh_offset = shdr.sh_offset,
|
||||
.sh_size = shdr.sh_size,
|
||||
.sh_link = shdr.sh_link,
|
||||
.sh_info = shdr.sh_info,
|
||||
.sh_addralign = shdr.sh_addralign,
|
||||
.sh_entsize = shdr.sh_entsize,
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
pub fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) {
|
||||
if (is_64) {
|
||||
@ -549,28 +562,6 @@ pub fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 {
|
||||
}
|
||||
}
|
||||
|
||||
fn preadNoEof(file: std.fs.File, buf: []u8, offset: u64) !void {
|
||||
var i: usize = 0;
|
||||
while (i < buf.len) {
|
||||
const len = file.pread(buf[i .. buf.len - i], offset + i) catch |err| switch (err) {
|
||||
error.SystemResources => return error.SystemResources,
|
||||
error.IsDir => return error.UnableToReadElfFile,
|
||||
error.OperationAborted => return error.UnableToReadElfFile,
|
||||
error.BrokenPipe => return error.UnableToReadElfFile,
|
||||
error.Unseekable => return error.UnableToReadElfFile,
|
||||
error.ConnectionResetByPeer => return error.UnableToReadElfFile,
|
||||
error.ConnectionTimedOut => return error.UnableToReadElfFile,
|
||||
error.InputOutput => return error.FileSystem,
|
||||
error.Unexpected => return error.Unexpected,
|
||||
error.WouldBlock => return error.Unexpected,
|
||||
error.NotOpenForReading => return error.Unexpected,
|
||||
error.AccessDenied => return error.Unexpected,
|
||||
};
|
||||
if (len == 0) return error.UnexpectedEndOfFile;
|
||||
i += len;
|
||||
}
|
||||
}
|
||||
|
||||
pub const EI_NIDENT = 16;
|
||||
|
||||
pub const EI_CLASS = 4;
|
||||
|
||||
130
lib/std/fmt.zig
130
lib/std/fmt.zig
@ -709,6 +709,87 @@ fn formatFloatValue(
|
||||
return formatBuf(buf_stream.getWritten(), options, writer);
|
||||
}
|
||||
|
||||
fn formatSliceHexImpl(comptime uppercase: bool) type {
|
||||
const charset = "0123456789" ++ if (uppercase) "ABCDEF" else "abcdef";
|
||||
|
||||
return struct {
|
||||
pub fn f(
|
||||
bytes: []const u8,
|
||||
comptime fmt: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
var buf: [2]u8 = undefined;
|
||||
|
||||
for (bytes) |c| {
|
||||
buf[0] = charset[c >> 4];
|
||||
buf[1] = charset[c & 15];
|
||||
try writer.writeAll(&buf);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const formatSliceHexLower = formatSliceHexImpl(false).f;
|
||||
const formatSliceHexUpper = formatSliceHexImpl(true).f;
|
||||
|
||||
/// Return a Formatter for a []const u8 where every byte is formatted as a pair
|
||||
/// of lowercase hexadecimal digits.
|
||||
pub fn fmtSliceHexLower(bytes: []const u8) std.fmt.Formatter(formatSliceHexLower) {
|
||||
return .{ .data = bytes };
|
||||
}
|
||||
|
||||
/// Return a Formatter for a []const u8 where every byte is formatted as a pair
|
||||
/// of uppercase hexadecimal digits.
|
||||
pub fn fmtSliceHexUpper(bytes: []const u8) std.fmt.Formatter(formatSliceHexUpper) {
|
||||
return .{ .data = bytes };
|
||||
}
|
||||
|
||||
fn formatSliceEscapeImpl(comptime uppercase: bool) type {
|
||||
const charset = "0123456789" ++ if (uppercase) "ABCDEF" else "abcdef";
|
||||
|
||||
return struct {
|
||||
pub fn f(
|
||||
bytes: []const u8,
|
||||
comptime fmt: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
var buf: [4]u8 = undefined;
|
||||
|
||||
buf[0] = '\\';
|
||||
buf[1] = 'x';
|
||||
|
||||
for (bytes) |c| {
|
||||
if (std.ascii.isPrint(c)) {
|
||||
try writer.writeByte(c);
|
||||
} else {
|
||||
buf[2] = charset[c >> 4];
|
||||
buf[3] = charset[c & 15];
|
||||
try writer.writeAll(&buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const formatSliceEscapeLower = formatSliceEscapeImpl(false).f;
|
||||
const formatSliceEscapeUpper = formatSliceEscapeImpl(true).f;
|
||||
|
||||
/// Return a Formatter for a []const u8 where every non-printable ASCII
|
||||
/// character is escaped as \xNN, where NN is the character in lowercase
|
||||
/// hexadecimal notation.
|
||||
pub fn fmtSliceEscapeLower(bytes: []const u8) std.fmt.Formatter(formatSliceEscapeLower) {
|
||||
return .{ .data = bytes };
|
||||
}
|
||||
|
||||
/// Return a Formatter for a []const u8 where every non-printable ASCII
|
||||
/// character is escaped as \xNN, where NN is the character in uppercase
|
||||
/// hexadecimal notation.
|
||||
pub fn fmtSliceEscapeUpper(bytes: []const u8) std.fmt.Formatter(formatSliceEscapeUpper) {
|
||||
return .{ .data = bytes };
|
||||
}
|
||||
|
||||
pub fn formatText(
|
||||
bytes: []const u8,
|
||||
comptime fmt: []const u8,
|
||||
@ -717,21 +798,18 @@ pub fn formatText(
|
||||
) !void {
|
||||
if (comptime std.mem.eql(u8, fmt, "s")) {
|
||||
return formatBuf(bytes, options, writer);
|
||||
} else if (comptime (std.mem.eql(u8, fmt, "x") or std.mem.eql(u8, fmt, "X"))) {
|
||||
for (bytes) |c| {
|
||||
try formatInt(c, 16, fmt[0] == 'X', FormatOptions{ .width = 2, .fill = '0' }, writer);
|
||||
}
|
||||
return;
|
||||
} else if (comptime (std.mem.eql(u8, fmt, "e") or std.mem.eql(u8, fmt, "E"))) {
|
||||
for (bytes) |c| {
|
||||
if (std.ascii.isPrint(c)) {
|
||||
try writer.writeByte(c);
|
||||
} else {
|
||||
try writer.writeAll("\\x");
|
||||
try formatInt(c, 16, fmt[0] == 'E', FormatOptions{ .width = 2, .fill = '0' }, writer);
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else if (comptime (std.mem.eql(u8, fmt, "x"))) {
|
||||
@compileError("specifier 'x' has been deprecated, wrap your argument in std.fmt.fmtSliceHexLower instead");
|
||||
} else if (comptime (std.mem.eql(u8, fmt, "X"))) {
|
||||
@compileError("specifier 'X' has been deprecated, wrap your argument in std.fmt.fmtSliceHexUpper instead");
|
||||
} else if (comptime (std.mem.eql(u8, fmt, "e"))) {
|
||||
@compileError("specifier 'e' has been deprecated, wrap your argument in std.fmt.fmtSliceEscapeLower instead");
|
||||
} else if (comptime (std.mem.eql(u8, fmt, "E"))) {
|
||||
@compileError("specifier 'X' has been deprecated, wrap your argument in std.fmt.fmtSliceEscapeUpper instead");
|
||||
} else if (comptime std.mem.eql(u8, fmt, "z")) {
|
||||
@compileError("specifier 'z' has been deprecated, wrap your argument in std.zig.fmtId instead");
|
||||
} else if (comptime std.mem.eql(u8, fmt, "Z")) {
|
||||
@compileError("specifier 'Z' has been deprecated, wrap your argument in std.zig.fmtEscapes instead");
|
||||
} else {
|
||||
@compileError("Unsupported format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'");
|
||||
}
|
||||
@ -1693,9 +1771,9 @@ test "slice" {
|
||||
}
|
||||
|
||||
test "escape non-printable" {
|
||||
try expectFmt("abc", "{e}", .{"abc"});
|
||||
try expectFmt("ab\\xffc", "{e}", .{"ab\xffc"});
|
||||
try expectFmt("ab\\xFFc", "{E}", .{"ab\xffc"});
|
||||
try expectFmt("abc", "{s}", .{fmtSliceEscapeLower("abc")});
|
||||
try expectFmt("ab\\xffc", "{s}", .{fmtSliceEscapeLower("ab\xffc")});
|
||||
try expectFmt("ab\\xFFc", "{s}", .{fmtSliceEscapeUpper("ab\xffc")});
|
||||
}
|
||||
|
||||
test "pointer" {
|
||||
@ -1968,13 +2046,13 @@ test "struct.zero-size" {
|
||||
|
||||
test "bytes.hex" {
|
||||
const some_bytes = "\xCA\xFE\xBA\xBE";
|
||||
try expectFmt("lowercase: cafebabe\n", "lowercase: {x}\n", .{some_bytes});
|
||||
try expectFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", .{some_bytes});
|
||||
try expectFmt("lowercase: cafebabe\n", "lowercase: {x}\n", .{fmtSliceHexLower(some_bytes)});
|
||||
try expectFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", .{fmtSliceHexUpper(some_bytes)});
|
||||
//Test Slices
|
||||
try expectFmt("uppercase: CAFE\n", "uppercase: {X}\n", .{some_bytes[0..2]});
|
||||
try expectFmt("lowercase: babe\n", "lowercase: {x}\n", .{some_bytes[2..]});
|
||||
try expectFmt("uppercase: CAFE\n", "uppercase: {X}\n", .{fmtSliceHexUpper(some_bytes[0..2])});
|
||||
try expectFmt("lowercase: babe\n", "lowercase: {x}\n", .{fmtSliceHexLower(some_bytes[2..])});
|
||||
const bytes_with_zeros = "\x00\x0E\xBA\xBE";
|
||||
try expectFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", .{bytes_with_zeros});
|
||||
try expectFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", .{fmtSliceHexLower(bytes_with_zeros)});
|
||||
}
|
||||
|
||||
pub 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 {
|
||||
|
||||
test "hexToBytes" {
|
||||
var buf: [32]u8 = undefined;
|
||||
try expectFmt("90" ** 32, "{X}", .{try hexToBytes(&buf, "90" ** 32)});
|
||||
try expectFmt("ABCD", "{X}", .{try hexToBytes(&buf, "ABCD")});
|
||||
try expectFmt("", "{X}", .{try hexToBytes(&buf, "")});
|
||||
try expectFmt("90" ** 32, "{s}", .{fmtSliceHexUpper(try hexToBytes(&buf, "90" ** 32))});
|
||||
try expectFmt("ABCD", "{s}", .{fmtSliceHexUpper(try hexToBytes(&buf, "ABCD"))});
|
||||
try expectFmt("", "{s}", .{fmtSliceHexUpper(try hexToBytes(&buf, ""))});
|
||||
std.testing.expectError(error.InvalidCharacter, hexToBytes(&buf, "012Z"));
|
||||
std.testing.expectError(error.InvalidLength, hexToBytes(&buf, "AAA"));
|
||||
std.testing.expectError(error.NoSpaceLeft, hexToBytes(buf[0..1], "ABAB"));
|
||||
|
||||
@ -60,7 +60,7 @@ pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataD
|
||||
var dir_path_ptr: [*:0]u8 = undefined;
|
||||
// TODO look into directory_which
|
||||
const be_user_settings = 0xbbe;
|
||||
const rc = os.system.find_directory(be_user_settings, -1, true, dir_path_ptr, 1) ;
|
||||
const rc = os.system.find_directory(be_user_settings, -1, true, dir_path_ptr, 1);
|
||||
const settings_dir = try allocator.dupeZ(u8, mem.spanZ(dir_path_ptr));
|
||||
defer allocator.free(settings_dir);
|
||||
switch (rc) {
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
// The MIT license requires this copyright notice to be included in all copies
|
||||
// and substantial portions of the software.
|
||||
const std = @import("../std.zig");
|
||||
const assert = std.debug.assert;
|
||||
const builtin = std.builtin;
|
||||
const mem = std.mem;
|
||||
|
||||
@ -86,5 +87,11 @@ pub fn Writer(
|
||||
mem.writeInt(T, &bytes, value, endian);
|
||||
return self.writeAll(&bytes);
|
||||
}
|
||||
|
||||
pub fn writeStruct(self: Self, value: anytype) Error!void {
|
||||
// Only extern and packed structs have defined in-memory layout.
|
||||
comptime assert(@typeInfo(@TypeOf(value)).Struct.layout != builtin.TypeInfo.ContainerLayout.Auto);
|
||||
return self.writeAll(mem.asBytes(&value));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -1330,3 +1330,59 @@ test "math.comptime" {
|
||||
comptime const v = sin(@as(f32, 1)) + ln(@as(f32, 5));
|
||||
testing.expect(v == sin(@as(f32, 1)) + ln(@as(f32, 5)));
|
||||
}
|
||||
|
||||
/// Returns a mask of all ones if value is true,
|
||||
/// and a mask of all zeroes if value is false.
|
||||
/// Compiles to one instruction for register sized integers.
|
||||
pub fn boolMask(comptime MaskInt: type, value: bool) callconv(.Inline) MaskInt {
|
||||
if (@typeInfo(MaskInt) != .Int)
|
||||
@compileError("boolMask requires an integer mask type.");
|
||||
|
||||
if (MaskInt == u0 or MaskInt == i0)
|
||||
@compileError("boolMask cannot convert to u0 or i0, they are too small.");
|
||||
|
||||
// The u1 and i1 cases tend to overflow,
|
||||
// so we special case them here.
|
||||
if (MaskInt == u1) return @boolToInt(value);
|
||||
if (MaskInt == i1) {
|
||||
// The @as here is a workaround for #7950
|
||||
return @bitCast(i1, @as(u1, @boolToInt(value)));
|
||||
}
|
||||
|
||||
// At comptime, -% is disallowed on unsigned values.
|
||||
// So we need to jump through some hoops in that case.
|
||||
// This is a workaround for #7951
|
||||
if (@typeInfo(@TypeOf(.{value})).Struct.fields[0].is_comptime) {
|
||||
// Since it's comptime, we don't need this to generate nice code.
|
||||
// We can just do a branch here.
|
||||
return if (value) ~@as(MaskInt, 0) else 0;
|
||||
}
|
||||
|
||||
return -%@intCast(MaskInt, @boolToInt(value));
|
||||
}
|
||||
|
||||
test "boolMask" {
|
||||
const runTest = struct {
|
||||
fn runTest() void {
|
||||
testing.expectEqual(@as(u1, 0), boolMask(u1, false));
|
||||
testing.expectEqual(@as(u1, 1), boolMask(u1, true));
|
||||
|
||||
testing.expectEqual(@as(i1, 0), boolMask(i1, false));
|
||||
testing.expectEqual(@as(i1, -1), boolMask(i1, true));
|
||||
|
||||
testing.expectEqual(@as(u13, 0), boolMask(u13, false));
|
||||
testing.expectEqual(@as(u13, 0x1FFF), boolMask(u13, true));
|
||||
|
||||
testing.expectEqual(@as(i13, 0), boolMask(i13, false));
|
||||
testing.expectEqual(@as(i13, -1), boolMask(i13, true));
|
||||
|
||||
testing.expectEqual(@as(u32, 0), boolMask(u32, false));
|
||||
testing.expectEqual(@as(u32, 0xFFFF_FFFF), boolMask(u32, true));
|
||||
|
||||
testing.expectEqual(@as(i32, 0), boolMask(i32, false));
|
||||
testing.expectEqual(@as(i32, -1), boolMask(i32, true));
|
||||
}
|
||||
}.runTest;
|
||||
runTest();
|
||||
comptime runTest();
|
||||
}
|
||||
|
||||
@ -25,6 +25,14 @@ pub const page_size = switch (builtin.arch) {
|
||||
else => 4 * 1024,
|
||||
};
|
||||
|
||||
/// The standard library currently thoroughly depends on byte size
|
||||
/// being 8 bits. (see the use of u8 throughout allocation code as
|
||||
/// the "byte" type.) Code which depends on this can reference this
|
||||
/// declaration. If we ever try to port the standard library to a
|
||||
/// non-8-bit-byte platform, this will allow us to search for things
|
||||
/// which need to be updated.
|
||||
pub const byte_size_in_bits = 8;
|
||||
|
||||
pub const Allocator = @import("mem/Allocator.zig");
|
||||
|
||||
/// Detects and asserts if the std.mem.Allocator interface is violated by the caller
|
||||
|
||||
@ -136,7 +136,7 @@ pub fn MultiArrayList(comptime S: type) type {
|
||||
const slices = self.slice();
|
||||
var result: S = undefined;
|
||||
inline for (fields) |field_info, i| {
|
||||
@field(elem, field_info.name) = slices.items(@intToEnum(Field, i))[index];
|
||||
@field(result, field_info.name) = slices.items(@intToEnum(Field, i))[index];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -180,8 +180,8 @@ pub const dirent = extern struct {
|
||||
};
|
||||
|
||||
pub const image_info = extern struct {
|
||||
id: u32, //image_id
|
||||
type: u32, // image_type
|
||||
id: u32,
|
||||
type: u32,
|
||||
sequence: i32,
|
||||
init_order: i32,
|
||||
init_routine: *c_void,
|
||||
@ -806,17 +806,16 @@ pub const Sigaction = extern struct {
|
||||
|
||||
pub const _SIG_WORDS = 4;
|
||||
pub const _SIG_MAXSIG = 128;
|
||||
|
||||
pub inline fn _SIG_IDX(sig: usize) usize {
|
||||
pub fn _SIG_IDX(sig: usize) callconv(.Inline) usize {
|
||||
return sig - 1;
|
||||
}
|
||||
pub inline fn _SIG_WORD(sig: usize) usize {
|
||||
pub fn _SIG_WORD(sig: usize) callconv(.Inline) usize {
|
||||
return_SIG_IDX(sig) >> 5;
|
||||
}
|
||||
pub inline fn _SIG_BIT(sig: usize) usize {
|
||||
pub fn _SIG_BIT(sig: usize) callconv(.Inline) usize {
|
||||
return 1 << (_SIG_IDX(sig) & 31);
|
||||
}
|
||||
pub inline fn _SIG_VALID(sig: usize) usize {
|
||||
pub fn _SIG_VALID(sig: usize) callconv(.Inline) usize {
|
||||
return sig <= _SIG_MAXSIG and sig > 0;
|
||||
}
|
||||
|
||||
|
||||
@ -2244,3 +2244,8 @@ pub const MADV_COLD = 20;
|
||||
pub const MADV_PAGEOUT = 21;
|
||||
pub const MADV_HWPOISON = 100;
|
||||
pub const MADV_SOFT_OFFLINE = 101;
|
||||
|
||||
pub const __kernel_timespec = extern struct {
|
||||
tv_sec: i64,
|
||||
tv_nsec: i64,
|
||||
};
|
||||
|
||||
@ -526,7 +526,7 @@ pub const IO_Uring = struct {
|
||||
pub fn timeout(
|
||||
self: *IO_Uring,
|
||||
user_data: u64,
|
||||
ts: *const os.timespec,
|
||||
ts: *const os.__kernel_timespec,
|
||||
count: u32,
|
||||
flags: u32,
|
||||
) !*io_uring_sqe {
|
||||
@ -884,7 +884,7 @@ pub fn io_uring_prep_close(sqe: *io_uring_sqe, fd: os.fd_t) void {
|
||||
|
||||
pub fn io_uring_prep_timeout(
|
||||
sqe: *io_uring_sqe,
|
||||
ts: *const os.timespec,
|
||||
ts: *const os.__kernel_timespec,
|
||||
count: u32,
|
||||
flags: u32,
|
||||
) void {
|
||||
@ -1339,7 +1339,7 @@ test "timeout (after a relative time)" {
|
||||
|
||||
const ms = 10;
|
||||
const margin = 5;
|
||||
const ts = os.timespec{ .tv_sec = 0, .tv_nsec = ms * 1000000 };
|
||||
const ts = os.__kernel_timespec{ .tv_sec = 0, .tv_nsec = ms * 1000000 };
|
||||
|
||||
const started = std.time.milliTimestamp();
|
||||
const sqe = try ring.timeout(0x55555555, &ts, 0, 0);
|
||||
@ -1366,7 +1366,7 @@ test "timeout (after a number of completions)" {
|
||||
};
|
||||
defer ring.deinit();
|
||||
|
||||
const ts = os.timespec{ .tv_sec = 3, .tv_nsec = 0 };
|
||||
const ts = os.__kernel_timespec{ .tv_sec = 3, .tv_nsec = 0 };
|
||||
const count_completions: u64 = 1;
|
||||
const sqe_timeout = try ring.timeout(0x66666666, &ts, count_completions, 0);
|
||||
testing.expectEqual(linux.IORING_OP.TIMEOUT, sqe_timeout.opcode);
|
||||
@ -1399,7 +1399,7 @@ test "timeout_remove" {
|
||||
};
|
||||
defer ring.deinit();
|
||||
|
||||
const ts = os.timespec{ .tv_sec = 3, .tv_nsec = 0 };
|
||||
const ts = os.__kernel_timespec{ .tv_sec = 3, .tv_nsec = 0 };
|
||||
const sqe_timeout = try ring.timeout(0x88888888, &ts, 0, 0);
|
||||
testing.expectEqual(linux.IORING_OP.TIMEOUT, sqe_timeout.opcode);
|
||||
testing.expectEqual(@as(u64, 0x88888888), sqe_timeout.user_data);
|
||||
|
||||
@ -18,6 +18,8 @@ pub const BufSet = @import("buf_set.zig").BufSet;
|
||||
pub const ChildProcess = @import("child_process.zig").ChildProcess;
|
||||
pub const ComptimeStringMap = @import("comptime_string_map.zig").ComptimeStringMap;
|
||||
pub const DynLib = @import("dynamic_library.zig").DynLib;
|
||||
pub const DynamicBitSet = bit_set.DynamicBitSet;
|
||||
pub const DynamicBitSetUnmanaged = bit_set.DynamicBitSetUnmanaged;
|
||||
pub const HashMap = hash_map.HashMap;
|
||||
pub const HashMapUnmanaged = hash_map.HashMapUnmanaged;
|
||||
pub const MultiArrayList = @import("multi_array_list.zig").MultiArrayList;
|
||||
@ -29,6 +31,7 @@ pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;
|
||||
pub const Progress = @import("Progress.zig");
|
||||
pub const SemanticVersion = @import("SemanticVersion.zig");
|
||||
pub const SinglyLinkedList = @import("linked_list.zig").SinglyLinkedList;
|
||||
pub const StaticBitSet = bit_set.StaticBitSet;
|
||||
pub const StringHashMap = hash_map.StringHashMap;
|
||||
pub const StringHashMapUnmanaged = hash_map.StringHashMapUnmanaged;
|
||||
pub const StringArrayHashMap = array_hash_map.StringArrayHashMap;
|
||||
@ -40,6 +43,7 @@ pub const Thread = @import("Thread.zig");
|
||||
pub const array_hash_map = @import("array_hash_map.zig");
|
||||
pub const atomic = @import("atomic.zig");
|
||||
pub const base64 = @import("base64.zig");
|
||||
pub const bit_set = @import("bit_set.zig");
|
||||
pub const build = @import("build.zig");
|
||||
pub const builtin = @import("builtin.zig");
|
||||
pub const c = @import("c.zig");
|
||||
|
||||
@ -3714,7 +3714,6 @@ const Parser = struct {
|
||||
if (p.eatToken(.r_paren)) |_| {
|
||||
return SmallSpan{ .zero_or_one = 0 };
|
||||
}
|
||||
continue;
|
||||
},
|
||||
.r_paren => return SmallSpan{ .zero_or_one = 0 },
|
||||
else => {
|
||||
@ -3728,14 +3727,7 @@ const Parser = struct {
|
||||
|
||||
const param_two = while (true) {
|
||||
switch (p.token_tags[p.nextToken()]) {
|
||||
.comma => {
|
||||
if (p.eatToken(.r_paren)) |_| {
|
||||
return SmallSpan{ .zero_or_one = param_one };
|
||||
}
|
||||
const param = try p.expectParamDecl();
|
||||
if (param != 0) break param;
|
||||
continue;
|
||||
},
|
||||
.comma => {},
|
||||
.r_paren => return SmallSpan{ .zero_or_one = param_one },
|
||||
.colon, .r_brace, .r_bracket => {
|
||||
p.tok_i -= 1;
|
||||
@ -3748,6 +3740,11 @@ const Parser = struct {
|
||||
try p.warnExpected(.comma);
|
||||
},
|
||||
}
|
||||
if (p.eatToken(.r_paren)) |_| {
|
||||
return SmallSpan{ .zero_or_one = param_one };
|
||||
}
|
||||
const param = try p.expectParamDecl();
|
||||
if (param != 0) break param;
|
||||
} else unreachable;
|
||||
|
||||
var list = std.ArrayList(Node.Index).init(p.gpa);
|
||||
@ -3757,17 +3754,7 @@ const Parser = struct {
|
||||
|
||||
while (true) {
|
||||
switch (p.token_tags[p.nextToken()]) {
|
||||
.comma => {
|
||||
if (p.token_tags[p.tok_i] == .r_paren) {
|
||||
p.tok_i += 1;
|
||||
return SmallSpan{ .multi = list.toOwnedSlice() };
|
||||
}
|
||||
const param = try p.expectParamDecl();
|
||||
if (param != 0) {
|
||||
try list.append(param);
|
||||
}
|
||||
continue;
|
||||
},
|
||||
.comma => {},
|
||||
.r_paren => return SmallSpan{ .multi = list.toOwnedSlice() },
|
||||
.colon, .r_brace, .r_bracket => {
|
||||
p.tok_i -= 1;
|
||||
@ -3780,6 +3767,11 @@ const Parser = struct {
|
||||
try p.warnExpected(.comma);
|
||||
},
|
||||
}
|
||||
if (p.eatToken(.r_paren)) |_| {
|
||||
return SmallSpan{ .multi = list.toOwnedSlice() };
|
||||
}
|
||||
const param = try p.expectParamDecl();
|
||||
if (param != 0) try list.append(param);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1108,6 +1108,25 @@ test "zig fmt: comment to disable/enable zig fmt first" {
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: 'zig fmt: (off|on)' can be surrounded by arbitrary whitespace" {
|
||||
try testTransform(
|
||||
\\// Test trailing comma syntax
|
||||
\\// zig fmt: off
|
||||
\\
|
||||
\\const struct_trailing_comma = struct { x: i32, y: i32, };
|
||||
\\
|
||||
\\// zig fmt: on
|
||||
,
|
||||
\\// Test trailing comma syntax
|
||||
\\// zig fmt: off
|
||||
\\
|
||||
\\const struct_trailing_comma = struct { x: i32, y: i32, };
|
||||
\\
|
||||
\\// zig fmt: on
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: comment to disable/enable zig fmt" {
|
||||
try testTransform(
|
||||
\\const a = b;
|
||||
@ -4549,6 +4568,18 @@ test "recovery: missing for payload" {
|
||||
});
|
||||
}
|
||||
|
||||
test "recovery: missing comma in params" {
|
||||
try testError(
|
||||
\\fn foo(comptime bool what what) void { }
|
||||
\\fn bar(a: i32, b: i32 c) void { }
|
||||
\\
|
||||
, &[_]Error{
|
||||
.expected_token,
|
||||
.expected_token,
|
||||
.expected_token,
|
||||
});
|
||||
}
|
||||
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const warn = std.debug.warn;
|
||||
|
||||
@ -2352,18 +2352,24 @@ fn renderComments(ais: *Ais, tree: ast.Tree, start: usize, end: usize) Error!boo
|
||||
}
|
||||
}
|
||||
|
||||
try ais.writer().print("{s}\n", .{trimmed_comment});
|
||||
index = 1 + (newline orelse return true);
|
||||
index = 1 + (newline orelse end - 1);
|
||||
|
||||
if (ais.disabled_offset) |disabled_offset| {
|
||||
if (mem.eql(u8, trimmed_comment, "// zig fmt: on")) {
|
||||
// write the source for which formatting was disabled directly
|
||||
// to the underlying writer, fixing up invaild whitespace
|
||||
try writeFixingWhitespace(ais.underlying_writer, tree.source[disabled_offset..index]);
|
||||
ais.disabled_offset = null;
|
||||
}
|
||||
} else if (mem.eql(u8, trimmed_comment, "// zig fmt: off")) {
|
||||
const comment_content = mem.trimLeft(u8, trimmed_comment["//".len..], &std.ascii.spaces);
|
||||
if (ais.disabled_offset != null and mem.eql(u8, comment_content, "zig fmt: on")) {
|
||||
// Write the source for which formatting was disabled directly
|
||||
// to the underlying writer, fixing up invaild whitespace.
|
||||
const disabled_source = tree.source[ais.disabled_offset.?..comment_start];
|
||||
try writeFixingWhitespace(ais.underlying_writer, disabled_source);
|
||||
ais.disabled_offset = null;
|
||||
// Write with the canonical single space.
|
||||
try ais.writer().writeAll("// zig fmt: on\n");
|
||||
} else if (ais.disabled_offset == null and mem.eql(u8, comment_content, "zig fmt: off")) {
|
||||
// Write with the canonical single space.
|
||||
try ais.writer().writeAll("// zig fmt: off\n");
|
||||
ais.disabled_offset = index;
|
||||
} else {
|
||||
// Write the comment minus trailing whitespace.
|
||||
try ais.writer().print("{s}\n", .{trimmed_comment});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -153,7 +153,11 @@ pub const HashHelper = struct {
|
||||
hh.hasher.final(&bin_digest);
|
||||
|
||||
var out_digest: [hex_digest_len]u8 = undefined;
|
||||
_ = std.fmt.bufPrint(&out_digest, "{x}", .{bin_digest}) catch unreachable;
|
||||
_ = std.fmt.bufPrint(
|
||||
&out_digest,
|
||||
"{s}",
|
||||
.{std.fmt.fmtSliceHexLower(&bin_digest)},
|
||||
) catch unreachable;
|
||||
return out_digest;
|
||||
}
|
||||
};
|
||||
@ -250,7 +254,11 @@ pub const Manifest = struct {
|
||||
var bin_digest: BinDigest = undefined;
|
||||
self.hash.hasher.final(&bin_digest);
|
||||
|
||||
_ = std.fmt.bufPrint(&self.hex_digest, "{x}", .{bin_digest}) catch unreachable;
|
||||
_ = std.fmt.bufPrint(
|
||||
&self.hex_digest,
|
||||
"{s}",
|
||||
.{std.fmt.fmtSliceHexLower(&bin_digest)},
|
||||
) catch unreachable;
|
||||
|
||||
self.hash.hasher = hasher_init;
|
||||
self.hash.hasher.update(&bin_digest);
|
||||
@ -549,7 +557,11 @@ pub const Manifest = struct {
|
||||
self.hash.hasher.final(&bin_digest);
|
||||
|
||||
var out_digest: [hex_digest_len]u8 = undefined;
|
||||
_ = std.fmt.bufPrint(&out_digest, "{x}", .{bin_digest}) catch unreachable;
|
||||
_ = std.fmt.bufPrint(
|
||||
&out_digest,
|
||||
"{s}",
|
||||
.{std.fmt.fmtSliceHexLower(&bin_digest)},
|
||||
) catch unreachable;
|
||||
|
||||
return out_digest;
|
||||
}
|
||||
@ -565,7 +577,11 @@ pub const Manifest = struct {
|
||||
var encoded_digest: [hex_digest_len]u8 = undefined;
|
||||
|
||||
for (self.files.items) |file| {
|
||||
_ = std.fmt.bufPrint(&encoded_digest, "{x}", .{file.bin_digest}) catch unreachable;
|
||||
_ = std.fmt.bufPrint(
|
||||
&encoded_digest,
|
||||
"{s}",
|
||||
.{std.fmt.fmtSliceHexLower(&file.bin_digest)},
|
||||
) catch unreachable;
|
||||
try writer.print("{d} {d} {d} {s} {s}\n", .{
|
||||
file.stat.size,
|
||||
file.stat.inode,
|
||||
|
||||
@ -4083,15 +4083,15 @@ pub fn namedFieldPtr(
|
||||
const child_type = try val.toType(scope.arena());
|
||||
switch (child_type.zigTypeTag()) {
|
||||
.ErrorSet => {
|
||||
var name: []const u8 = undefined;
|
||||
// TODO resolve inferred error sets
|
||||
const entry = if (val.castTag(.error_set)) |payload|
|
||||
(payload.data.fields.getEntry(field_name) orelse
|
||||
return mod.fail(scope, src, "no error named '{s}' in '{}'", .{ field_name, child_type })).*
|
||||
if (val.castTag(.error_set)) |payload|
|
||||
name = (payload.data.fields.getEntry(field_name) orelse return mod.fail(scope, src, "no error named '{s}' in '{}'", .{ field_name, child_type })).key
|
||||
else
|
||||
try mod.getErrorValue(field_name);
|
||||
name = (try mod.getErrorValue(field_name)).key;
|
||||
|
||||
const result_type = if (child_type.tag() == .anyerror)
|
||||
try Type.Tag.error_set_single.create(scope.arena(), entry.key)
|
||||
try Type.Tag.error_set_single.create(scope.arena(), name)
|
||||
else
|
||||
child_type;
|
||||
|
||||
@ -4100,7 +4100,7 @@ pub fn namedFieldPtr(
|
||||
.val = try Value.Tag.ref_val.create(
|
||||
scope.arena(),
|
||||
try Value.Tag.@"error".create(scope.arena(), .{
|
||||
.name = entry.key,
|
||||
.name = name,
|
||||
}),
|
||||
),
|
||||
});
|
||||
|
||||
@ -453,13 +453,23 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
|
||||
return rvalue(mod, scope, rl, result);
|
||||
},
|
||||
.unwrap_optional => {
|
||||
const operand = try expr(mod, scope, rl, node_datas[node].lhs);
|
||||
const op: zir.Inst.Tag = switch (rl) {
|
||||
.ref => .optional_payload_safe_ptr,
|
||||
else => .optional_payload_safe,
|
||||
};
|
||||
const src = token_starts[main_tokens[node]];
|
||||
return addZIRUnOp(mod, scope, src, op, operand);
|
||||
switch (rl) {
|
||||
.ref => return addZIRUnOp(
|
||||
mod,
|
||||
scope,
|
||||
src,
|
||||
.optional_payload_safe_ptr,
|
||||
try expr(mod, scope, .ref, node_datas[node].lhs),
|
||||
),
|
||||
else => return rvalue(mod, scope, rl, try addZIRUnOp(
|
||||
mod,
|
||||
scope,
|
||||
src,
|
||||
.optional_payload_safe,
|
||||
try expr(mod, scope, .none, node_datas[node].lhs),
|
||||
)),
|
||||
}
|
||||
},
|
||||
.block_two, .block_two_semicolon => {
|
||||
const statements = [2]ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs };
|
||||
@ -1645,7 +1655,7 @@ fn errorSetDecl(
|
||||
switch (token_tags[tok_i]) {
|
||||
.doc_comment, .comma => {},
|
||||
.identifier => count += 1,
|
||||
.r_paren => break :count count,
|
||||
.r_brace => break :count count,
|
||||
else => unreachable,
|
||||
}
|
||||
} else unreachable; // TODO should not need else unreachable here
|
||||
@ -1662,7 +1672,7 @@ fn errorSetDecl(
|
||||
fields[field_i] = try mod.identifierTokenString(scope, tok_i);
|
||||
field_i += 1;
|
||||
},
|
||||
.r_paren => break,
|
||||
.r_brace => break,
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
@ -1699,9 +1709,13 @@ fn orelseCatchExpr(
|
||||
setBlockResultLoc(&block_scope, rl);
|
||||
defer block_scope.instructions.deinit(mod.gpa);
|
||||
|
||||
// This could be a pointer or value depending on the `rl` parameter.
|
||||
// This could be a pointer or value depending on the `operand_rl` parameter.
|
||||
// We cannot use `block_scope.break_result_loc` because that has the bare
|
||||
// type, whereas this expression has the optional type. Later we make
|
||||
// up for this fact by calling rvalue on the else branch.
|
||||
block_scope.break_count += 1;
|
||||
const operand = try expr(mod, &block_scope.base, block_scope.break_result_loc, lhs);
|
||||
const operand_rl = try makeOptionalTypeResultLoc(mod, &block_scope.base, src, block_scope.break_result_loc);
|
||||
const operand = try expr(mod, &block_scope.base, operand_rl, lhs);
|
||||
const cond = try addZIRUnOp(mod, &block_scope.base, src, cond_op, operand);
|
||||
|
||||
const condbr = try addZIRInstSpecial(mod, &block_scope.base, src, zir.Inst.CondBr, .{
|
||||
@ -1753,6 +1767,10 @@ fn orelseCatchExpr(
|
||||
|
||||
// This could be a pointer or value depending on `unwrap_op`.
|
||||
const unwrapped_payload = try addZIRUnOp(mod, &else_scope.base, src, unwrap_op, operand);
|
||||
const else_result = switch (rl) {
|
||||
.ref => unwrapped_payload,
|
||||
else => try rvalue(mod, &else_scope.base, block_scope.break_result_loc, unwrapped_payload),
|
||||
};
|
||||
|
||||
return finishThenElseBlock(
|
||||
mod,
|
||||
@ -1766,7 +1784,7 @@ fn orelseCatchExpr(
|
||||
src,
|
||||
src,
|
||||
then_result,
|
||||
unwrapped_payload,
|
||||
else_result,
|
||||
block,
|
||||
block,
|
||||
);
|
||||
@ -3955,6 +3973,25 @@ fn rlStrategy(rl: ResultLoc, block_scope: *Scope.GenZIR) ResultLoc.Strategy {
|
||||
}
|
||||
}
|
||||
|
||||
/// If the input ResultLoc is ref, returns ResultLoc.ref. Otherwise:
|
||||
/// Returns ResultLoc.ty, where the type is determined by the input
|
||||
/// ResultLoc type, wrapped in an optional type. If the input ResultLoc
|
||||
/// has no type, .none is returned.
|
||||
fn makeOptionalTypeResultLoc(mod: *Module, scope: *Scope, src: usize, rl: ResultLoc) !ResultLoc {
|
||||
switch (rl) {
|
||||
.ref => return ResultLoc.ref,
|
||||
.discard, .none, .block_ptr, .inferred_ptr, .bitcasted_ptr => return ResultLoc.none,
|
||||
.ty => |elem_ty| {
|
||||
const wrapped_ty = try addZIRUnOp(mod, scope, src, .optional_type, elem_ty);
|
||||
return ResultLoc{ .ty = wrapped_ty };
|
||||
},
|
||||
.ptr => |ptr_ty| {
|
||||
const wrapped_ty = try addZIRUnOp(mod, scope, src, .optional_type_from_ptr_elem, ptr_ty);
|
||||
return ResultLoc{ .ty = wrapped_ty };
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn setBlockResultLoc(block_scope: *Scope.GenZIR, parent_rl: ResultLoc) void {
|
||||
// Depending on whether the result location is a pointer or value, different
|
||||
// ZIR needs to be generated. In the former case we rely on storing to the
|
||||
|
||||
@ -46,7 +46,7 @@ flagpd1("M"),
|
||||
.{
|
||||
.name = "MM",
|
||||
.syntax = .flag,
|
||||
.zig_equivalent = .dep_file,
|
||||
.zig_equivalent = .dep_file_mm,
|
||||
.pd1 = true,
|
||||
.pd2 = false,
|
||||
.psl = false,
|
||||
@ -1870,7 +1870,7 @@ flagpsl("MT"),
|
||||
.{
|
||||
.name = "print-missing-file-dependencies",
|
||||
.syntax = .flag,
|
||||
.zig_equivalent = .other,
|
||||
.zig_equivalent = .dep_file,
|
||||
.pd1 = false,
|
||||
.pd2 = true,
|
||||
.psl = false,
|
||||
@ -1990,7 +1990,7 @@ flagpsl("MT"),
|
||||
.{
|
||||
.name = "user-dependencies",
|
||||
.syntax = .flag,
|
||||
.zig_equivalent = .other,
|
||||
.zig_equivalent = .dep_file_mm,
|
||||
.pd1 = false,
|
||||
.pd2 = true,
|
||||
.psl = false,
|
||||
@ -2014,7 +2014,7 @@ flagpsl("MT"),
|
||||
.{
|
||||
.name = "write-dependencies",
|
||||
.syntax = .flag,
|
||||
.zig_equivalent = .other,
|
||||
.zig_equivalent = .dep_file,
|
||||
.pd1 = false,
|
||||
.pd2 = true,
|
||||
.psl = false,
|
||||
@ -2022,7 +2022,7 @@ flagpsl("MT"),
|
||||
.{
|
||||
.name = "write-user-dependencies",
|
||||
.syntax = .flag,
|
||||
.zig_equivalent = .other,
|
||||
.zig_equivalent = .dep_file,
|
||||
.pd1 = false,
|
||||
.pd2 = true,
|
||||
.psl = false,
|
||||
|
||||
@ -899,6 +899,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
.load => return self.genLoad(inst.castTag(.load).?),
|
||||
.loop => return self.genLoop(inst.castTag(.loop).?),
|
||||
.not => return self.genNot(inst.castTag(.not).?),
|
||||
.mul => return self.genMul(inst.castTag(.mul).?),
|
||||
.ptrtoint => return self.genPtrToInt(inst.castTag(.ptrtoint).?),
|
||||
.ref => return self.genRef(inst.castTag(.ref).?),
|
||||
.ret => return self.genRet(inst.castTag(.ret).?),
|
||||
@ -1128,6 +1129,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
}
|
||||
}
|
||||
|
||||
fn genMul(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
|
||||
// No side effects, so if it's unreferenced, do nothing.
|
||||
if (inst.base.isUnused())
|
||||
return MCValue.dead;
|
||||
switch (arch) {
|
||||
.arm, .armeb => return try self.genArmMul(&inst.base, inst.lhs, inst.rhs),
|
||||
else => return self.fail(inst.base.src, "TODO implement mul for {}", .{self.target.cpu.arch}),
|
||||
}
|
||||
}
|
||||
|
||||
fn genBitAnd(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
|
||||
// No side effects, so if it's unreferenced, do nothing.
|
||||
if (inst.base.isUnused())
|
||||
@ -1478,6 +1489,38 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
}
|
||||
}
|
||||
|
||||
fn genArmMul(self: *Self, inst: *ir.Inst, op_lhs: *ir.Inst, op_rhs: *ir.Inst) !MCValue {
|
||||
const lhs = try self.resolveInst(op_lhs);
|
||||
const rhs = try self.resolveInst(op_rhs);
|
||||
|
||||
// Destination must be a register
|
||||
// LHS must be a register
|
||||
// RHS must be a register
|
||||
var dst_mcv: MCValue = undefined;
|
||||
var lhs_mcv: MCValue = undefined;
|
||||
var rhs_mcv: MCValue = undefined;
|
||||
if (self.reuseOperand(inst, 0, lhs)) {
|
||||
// LHS is the destination
|
||||
lhs_mcv = if (lhs != .register) try self.copyToNewRegister(inst, lhs) else lhs;
|
||||
rhs_mcv = if (rhs != .register) try self.copyToNewRegister(inst, rhs) else rhs;
|
||||
dst_mcv = lhs_mcv;
|
||||
} else if (self.reuseOperand(inst, 1, rhs)) {
|
||||
// RHS is the destination
|
||||
lhs_mcv = if (lhs != .register) try self.copyToNewRegister(inst, lhs) else lhs;
|
||||
rhs_mcv = if (rhs != .register) try self.copyToNewRegister(inst, rhs) else rhs;
|
||||
dst_mcv = rhs_mcv;
|
||||
} else {
|
||||
// TODO save 1 copy instruction by directly allocating the destination register
|
||||
// LHS is the destination
|
||||
lhs_mcv = try self.copyToNewRegister(inst, lhs);
|
||||
rhs_mcv = if (rhs != .register) try self.copyToNewRegister(inst, rhs) else rhs;
|
||||
dst_mcv = lhs_mcv;
|
||||
}
|
||||
|
||||
writeInt(u32, try self.code.addManyAsArray(4), Instruction.mul(.al, dst_mcv.register, lhs_mcv.register, rhs_mcv.register).toU32());
|
||||
return dst_mcv;
|
||||
}
|
||||
|
||||
/// ADD, SUB, XOR, OR, AND
|
||||
fn genX8664BinMath(self: *Self, inst: *ir.Inst, op_lhs: *ir.Inst, op_rhs: *ir.Inst, opx: u8, mr: u8) !MCValue {
|
||||
try self.code.ensureCapacity(self.code.items.len + 8);
|
||||
|
||||
@ -400,6 +400,7 @@ pub const LLVMIRModule = struct {
|
||||
.block => try self.genBlock(inst.castTag(.block).?),
|
||||
.br => try self.genBr(inst.castTag(.br).?),
|
||||
.breakpoint => try self.genBreakpoint(inst.castTag(.breakpoint).?),
|
||||
.br_void => try self.genBrVoid(inst.castTag(.br_void).?),
|
||||
.call => try self.genCall(inst.castTag(.call).?),
|
||||
.cmp_eq => try self.genCmp(inst.castTag(.cmp_eq).?, .eq),
|
||||
.cmp_gt => try self.genCmp(inst.castTag(.cmp_gt).?, .gt),
|
||||
@ -409,6 +410,10 @@ pub const LLVMIRModule = struct {
|
||||
.cmp_neq => try self.genCmp(inst.castTag(.cmp_neq).?, .neq),
|
||||
.condbr => try self.genCondBr(inst.castTag(.condbr).?),
|
||||
.intcast => try self.genIntCast(inst.castTag(.intcast).?),
|
||||
.is_non_null => try self.genIsNonNull(inst.castTag(.is_non_null).?, false),
|
||||
.is_non_null_ptr => try self.genIsNonNull(inst.castTag(.is_non_null_ptr).?, true),
|
||||
.is_null => try self.genIsNull(inst.castTag(.is_null).?, false),
|
||||
.is_null_ptr => try self.genIsNull(inst.castTag(.is_null_ptr).?, true),
|
||||
.load => try self.genLoad(inst.castTag(.load).?),
|
||||
.loop => try self.genLoop(inst.castTag(.loop).?),
|
||||
.not => try self.genNot(inst.castTag(.not).?),
|
||||
@ -417,6 +422,8 @@ pub const LLVMIRModule = struct {
|
||||
.store => try self.genStore(inst.castTag(.store).?),
|
||||
.sub => try self.genSub(inst.castTag(.sub).?),
|
||||
.unreach => self.genUnreach(inst.castTag(.unreach).?),
|
||||
.optional_payload => try self.genOptionalPayload(inst.castTag(.optional_payload).?, false),
|
||||
.optional_payload_ptr => try self.genOptionalPayload(inst.castTag(.optional_payload_ptr).?, true),
|
||||
.dbg_stmt => blk: {
|
||||
// TODO: implement debug info
|
||||
break :blk null;
|
||||
@ -537,21 +544,29 @@ pub const LLVMIRModule = struct {
|
||||
}
|
||||
|
||||
fn genBr(self: *LLVMIRModule, inst: *Inst.Br) !?*const llvm.Value {
|
||||
// Get the block that we want to break to.
|
||||
var block = self.blocks.get(inst.block).?;
|
||||
_ = self.builder.buildBr(block.parent_bb);
|
||||
|
||||
// If the break doesn't break a value, then we don't have to add
|
||||
// the values to the lists.
|
||||
if (!inst.operand.ty.hasCodeGenBits()) return null;
|
||||
if (!inst.operand.ty.hasCodeGenBits()) {
|
||||
// TODO: in astgen these instructions should turn into `br_void` instructions.
|
||||
_ = self.builder.buildBr(block.parent_bb);
|
||||
} else {
|
||||
const val = try self.resolveInst(inst.operand);
|
||||
|
||||
// For the phi node, we need the basic blocks and the values of the
|
||||
// break instructions.
|
||||
try block.break_bbs.append(self.gpa, self.builder.getInsertBlock());
|
||||
// For the phi node, we need the basic blocks and the values of the
|
||||
// break instructions.
|
||||
try block.break_bbs.append(self.gpa, self.builder.getInsertBlock());
|
||||
try block.break_vals.append(self.gpa, val);
|
||||
|
||||
const val = try self.resolveInst(inst.operand);
|
||||
try block.break_vals.append(self.gpa, val);
|
||||
_ = self.builder.buildBr(block.parent_bb);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
fn genBrVoid(self: *LLVMIRModule, inst: *Inst.BrVoid) !?*const llvm.Value {
|
||||
var block = self.blocks.get(inst.block).?;
|
||||
_ = self.builder.buildBr(block.parent_bb);
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -594,6 +609,44 @@ pub const LLVMIRModule = struct {
|
||||
return null;
|
||||
}
|
||||
|
||||
fn genIsNonNull(self: *LLVMIRModule, inst: *Inst.UnOp, operand_is_ptr: bool) !?*const llvm.Value {
|
||||
const operand = try self.resolveInst(inst.operand);
|
||||
|
||||
if (operand_is_ptr) {
|
||||
const index_type = self.context.intType(32);
|
||||
|
||||
var indices: [2]*const llvm.Value = .{
|
||||
index_type.constNull(),
|
||||
index_type.constInt(1, false),
|
||||
};
|
||||
|
||||
return self.builder.buildLoad(self.builder.buildInBoundsGEP(operand, &indices, 2, ""), "");
|
||||
} else {
|
||||
return self.builder.buildExtractValue(operand, 1, "");
|
||||
}
|
||||
}
|
||||
|
||||
fn genIsNull(self: *LLVMIRModule, inst: *Inst.UnOp, operand_is_ptr: bool) !?*const llvm.Value {
|
||||
return self.builder.buildNot((try self.genIsNonNull(inst, operand_is_ptr)).?, "");
|
||||
}
|
||||
|
||||
fn genOptionalPayload(self: *LLVMIRModule, inst: *Inst.UnOp, operand_is_ptr: bool) !?*const llvm.Value {
|
||||
const operand = try self.resolveInst(inst.operand);
|
||||
|
||||
if (operand_is_ptr) {
|
||||
const index_type = self.context.intType(32);
|
||||
|
||||
var indices: [2]*const llvm.Value = .{
|
||||
index_type.constNull(),
|
||||
index_type.constNull(),
|
||||
};
|
||||
|
||||
return self.builder.buildInBoundsGEP(operand, &indices, 2, "");
|
||||
} else {
|
||||
return self.builder.buildExtractValue(operand, 0, "");
|
||||
}
|
||||
}
|
||||
|
||||
fn genAdd(self: *LLVMIRModule, inst: *Inst.BinOp) !?*const llvm.Value {
|
||||
const lhs = try self.resolveInst(inst.lhs);
|
||||
const rhs = try self.resolveInst(inst.rhs);
|
||||
@ -754,6 +807,13 @@ pub const LLVMIRModule = struct {
|
||||
// TODO: consider using buildInBoundsGEP2 for opaque pointers
|
||||
return self.builder.buildInBoundsGEP(val, &indices, 2, "");
|
||||
},
|
||||
.ref_val => {
|
||||
const elem_value = tv.val.castTag(.ref_val).?.data;
|
||||
const elem_type = tv.ty.castPointer().?.data;
|
||||
const alloca = self.buildAlloca(try self.getLLVMType(elem_type, src));
|
||||
_ = self.builder.buildStore(try self.genTypedValue(src, .{ .ty = elem_type, .val = elem_value }), alloca);
|
||||
return alloca;
|
||||
},
|
||||
else => return self.fail(src, "TODO implement const of pointer type '{}'", .{tv.ty}),
|
||||
},
|
||||
.Array => {
|
||||
@ -768,6 +828,29 @@ pub const LLVMIRModule = struct {
|
||||
return self.fail(src, "TODO handle more array values", .{});
|
||||
}
|
||||
},
|
||||
.Optional => {
|
||||
if (!tv.ty.isPtrLikeOptional()) {
|
||||
var buf: Type.Payload.ElemType = undefined;
|
||||
const child_type = tv.ty.optionalChild(&buf);
|
||||
const llvm_child_type = try self.getLLVMType(child_type, src);
|
||||
|
||||
if (tv.val.tag() == .null_value) {
|
||||
var optional_values: [2]*const llvm.Value = .{
|
||||
llvm_child_type.constNull(),
|
||||
self.context.intType(1).constNull(),
|
||||
};
|
||||
return self.context.constStruct(&optional_values, 2, false);
|
||||
} else {
|
||||
var optional_values: [2]*const llvm.Value = .{
|
||||
try self.genTypedValue(src, .{ .ty = child_type, .val = tv.val }),
|
||||
self.context.intType(1).constAllOnes(),
|
||||
};
|
||||
return self.context.constStruct(&optional_values, 2, false);
|
||||
}
|
||||
} else {
|
||||
return self.fail(src, "TODO implement const of optional pointer", .{});
|
||||
}
|
||||
},
|
||||
else => return self.fail(src, "TODO implement const of type '{}'", .{tv.ty}),
|
||||
}
|
||||
}
|
||||
@ -793,6 +876,20 @@ pub const LLVMIRModule = struct {
|
||||
const elem_type = try self.getLLVMType(t.elemType(), src);
|
||||
return elem_type.arrayType(@intCast(c_uint, t.abiSize(self.module.getTarget())));
|
||||
},
|
||||
.Optional => {
|
||||
if (!t.isPtrLikeOptional()) {
|
||||
var buf: Type.Payload.ElemType = undefined;
|
||||
const child_type = t.optionalChild(&buf);
|
||||
|
||||
var optional_types: [2]*const llvm.Type = .{
|
||||
try self.getLLVMType(child_type, src),
|
||||
self.context.intType(1),
|
||||
};
|
||||
return self.context.structType(&optional_types, 2, false);
|
||||
} else {
|
||||
return self.fail(src, "TODO implement optional pointers as actual pointers", .{});
|
||||
}
|
||||
},
|
||||
else => return self.fail(src, "TODO implement getLLVMType for type '{}'", .{t}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,9 +21,15 @@ pub const Context = opaque {
|
||||
pub const voidType = LLVMVoidTypeInContext;
|
||||
extern fn LLVMVoidTypeInContext(C: *const Context) *const Type;
|
||||
|
||||
pub const structType = LLVMStructTypeInContext;
|
||||
extern fn LLVMStructTypeInContext(C: *const Context, ElementTypes: [*]*const Type, ElementCount: c_uint, Packed: LLVMBool) *const Type;
|
||||
|
||||
pub const constString = LLVMConstStringInContext;
|
||||
extern fn LLVMConstStringInContext(C: *const Context, Str: [*]const u8, Length: c_uint, DontNullTerminate: LLVMBool) *const Value;
|
||||
|
||||
pub const constStruct = LLVMConstStructInContext;
|
||||
extern fn LLVMConstStructInContext(C: *const Context, ConstantVals: [*]*const Value, Count: c_uint, Packed: LLVMBool) *const Value;
|
||||
|
||||
pub const createBasicBlock = LLVMCreateBasicBlockInContext;
|
||||
extern fn LLVMCreateBasicBlockInContext(C: *const Context, Name: [*:0]const u8) *const BasicBlock;
|
||||
|
||||
@ -204,6 +210,9 @@ pub const Builder = opaque {
|
||||
|
||||
pub const buildPhi = LLVMBuildPhi;
|
||||
extern fn LLVMBuildPhi(*const Builder, Ty: *const Type, Name: [*:0]const u8) *const Value;
|
||||
|
||||
pub const buildExtractValue = LLVMBuildExtractValue;
|
||||
extern fn LLVMBuildExtractValue(*const Builder, AggVal: *const Value, Index: c_uint, Name: [*:0]const u8) *const Value;
|
||||
};
|
||||
|
||||
pub const IntPredicate = extern enum {
|
||||
|
||||
@ -106,6 +106,7 @@ pub const Inst = struct {
|
||||
store,
|
||||
sub,
|
||||
unreach,
|
||||
mul,
|
||||
not,
|
||||
floatcast,
|
||||
intcast,
|
||||
@ -165,6 +166,7 @@ pub const Inst = struct {
|
||||
|
||||
.add,
|
||||
.sub,
|
||||
.mul,
|
||||
.cmp_lt,
|
||||
.cmp_lte,
|
||||
.cmp_eq,
|
||||
|
||||
@ -550,11 +550,11 @@ pub const File = struct {
|
||||
id_symlink_basename,
|
||||
&prev_digest_buf,
|
||||
) catch |err| b: {
|
||||
log.debug("archive new_digest={x} readFile error: {s}", .{ digest, @errorName(err) });
|
||||
log.debug("archive new_digest={s} readFile error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) });
|
||||
break :b prev_digest_buf[0..0];
|
||||
};
|
||||
if (mem.eql(u8, prev_digest, &digest)) {
|
||||
log.debug("archive digest={x} match - skipping invocation", .{digest});
|
||||
log.debug("archive digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)});
|
||||
base.lock = man.toOwnedLock();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -892,17 +892,17 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
|
||||
id_symlink_basename,
|
||||
&prev_digest_buf,
|
||||
) catch |err| blk: {
|
||||
log.debug("COFF LLD new_digest={x} error: {s}", .{ digest, @errorName(err) });
|
||||
log.debug("COFF LLD new_digest={s} error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) });
|
||||
// Handle this as a cache miss.
|
||||
break :blk prev_digest_buf[0..0];
|
||||
};
|
||||
if (mem.eql(u8, prev_digest, &digest)) {
|
||||
log.debug("COFF LLD digest={x} match - skipping invocation", .{digest});
|
||||
log.debug("COFF LLD digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)});
|
||||
// Hot diggity dog! The output binary is already there.
|
||||
self.base.lock = man.toOwnedLock();
|
||||
return;
|
||||
}
|
||||
log.debug("COFF LLD prev_digest={x} new_digest={x}", .{ prev_digest, digest });
|
||||
log.debug("COFF LLD prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) });
|
||||
|
||||
// We are about to change the output file to be different, so we invalidate the build hash now.
|
||||
directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {
|
||||
|
||||
@ -1365,17 +1365,17 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
|
||||
id_symlink_basename,
|
||||
&prev_digest_buf,
|
||||
) catch |err| blk: {
|
||||
log.debug("ELF LLD new_digest={x} error: {s}", .{ digest, @errorName(err) });
|
||||
log.debug("ELF LLD new_digest={s} error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) });
|
||||
// Handle this as a cache miss.
|
||||
break :blk prev_digest_buf[0..0];
|
||||
};
|
||||
if (mem.eql(u8, prev_digest, &digest)) {
|
||||
log.debug("ELF LLD digest={x} match - skipping invocation", .{digest});
|
||||
log.debug("ELF LLD digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)});
|
||||
// Hot diggity dog! The output binary is already there.
|
||||
self.base.lock = man.toOwnedLock();
|
||||
return;
|
||||
}
|
||||
log.debug("ELF LLD prev_digest={x} new_digest={x}", .{ prev_digest, digest });
|
||||
log.debug("ELF LLD prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) });
|
||||
|
||||
// We are about to change the output file to be different, so we invalidate the build hash now.
|
||||
directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {
|
||||
|
||||
@ -556,17 +556,17 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
|
||||
id_symlink_basename,
|
||||
&prev_digest_buf,
|
||||
) catch |err| blk: {
|
||||
log.debug("MachO LLD new_digest={x} error: {s}", .{ digest, @errorName(err) });
|
||||
log.debug("MachO LLD new_digest={s} error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) });
|
||||
// Handle this as a cache miss.
|
||||
break :blk prev_digest_buf[0..0];
|
||||
};
|
||||
if (mem.eql(u8, prev_digest, &digest)) {
|
||||
log.debug("MachO LLD digest={x} match - skipping invocation", .{digest});
|
||||
log.debug("MachO LLD digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)});
|
||||
// Hot diggity dog! The output binary is already there.
|
||||
self.base.lock = man.toOwnedLock();
|
||||
return;
|
||||
}
|
||||
log.debug("MachO LLD prev_digest={x} new_digest={x}", .{ prev_digest, digest });
|
||||
log.debug("MachO LLD prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) });
|
||||
|
||||
// We are about to change the output file to be different, so we invalidate the build hash now.
|
||||
directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {
|
||||
|
||||
@ -391,17 +391,17 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
|
||||
id_symlink_basename,
|
||||
&prev_digest_buf,
|
||||
) catch |err| blk: {
|
||||
log.debug("WASM LLD new_digest={x} error: {s}", .{ digest, @errorName(err) });
|
||||
log.debug("WASM LLD new_digest={s} error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) });
|
||||
// Handle this as a cache miss.
|
||||
break :blk prev_digest_buf[0..0];
|
||||
};
|
||||
if (mem.eql(u8, prev_digest, &digest)) {
|
||||
log.debug("WASM LLD digest={x} match - skipping invocation", .{digest});
|
||||
log.debug("WASM LLD digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)});
|
||||
// Hot diggity dog! The output binary is already there.
|
||||
self.base.lock = man.toOwnedLock();
|
||||
return;
|
||||
}
|
||||
log.debug("WASM LLD prev_digest={x} new_digest={x}", .{ prev_digest, digest });
|
||||
log.debug("WASM LLD prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) });
|
||||
|
||||
// We are about to change the output file to be different, so we invalidate the build hash now.
|
||||
directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {
|
||||
|
||||
20
src/main.zig
20
src/main.zig
@ -448,6 +448,15 @@ const Emit = union(enum) {
|
||||
}
|
||||
};
|
||||
|
||||
fn optionalBoolEnvVar(arena: *Allocator, name: []const u8) !bool {
|
||||
if (std.process.getEnvVarOwned(arena, name)) |value| {
|
||||
return true;
|
||||
} else |err| switch (err) {
|
||||
error.EnvironmentVariableNotFound => return false,
|
||||
else => |e| return e,
|
||||
}
|
||||
}
|
||||
|
||||
fn optionalStringEnvVar(arena: *Allocator, name: []const u8) !?[]const u8 {
|
||||
if (std.process.getEnvVarOwned(arena, name)) |value| {
|
||||
return value;
|
||||
@ -482,8 +491,8 @@ fn buildOutputType(
|
||||
var single_threaded = false;
|
||||
var function_sections = false;
|
||||
var watch = false;
|
||||
var verbose_link = false;
|
||||
var verbose_cc = false;
|
||||
var verbose_link = try optionalBoolEnvVar(arena, "ZIG_VERBOSE_LINK");
|
||||
var verbose_cc = try optionalBoolEnvVar(arena, "ZIG_VERBOSE_CC");
|
||||
var verbose_tokenize = false;
|
||||
var verbose_ast = false;
|
||||
var verbose_ir = false;
|
||||
@ -1183,6 +1192,12 @@ fn buildOutputType(
|
||||
disable_c_depfile = true;
|
||||
try clang_argv.appendSlice(it.other_args);
|
||||
},
|
||||
.dep_file_mm => { // -MM
|
||||
// "Like -MMD, but also implies -E and writes to stdout by default"
|
||||
c_out_mode = .preprocessor;
|
||||
disable_c_depfile = true;
|
||||
try clang_argv.appendSlice(it.other_args);
|
||||
},
|
||||
.framework_dir => try framework_dirs.append(it.only_arg),
|
||||
.framework => try frameworks.append(it.only_arg),
|
||||
.nostdlibinc => want_native_include_dirs = false,
|
||||
@ -3046,6 +3061,7 @@ pub const ClangArgIterator = struct {
|
||||
lib_dir,
|
||||
mcpu,
|
||||
dep_file,
|
||||
dep_file_mm,
|
||||
framework_dir,
|
||||
framework,
|
||||
nostdlibinc,
|
||||
|
||||
@ -4126,7 +4126,15 @@ static LLVMValueRef gen_frame_size(CodeGen *g, LLVMValueRef fn_val) {
|
||||
LLVMValueRef casted_fn_val = LLVMBuildBitCast(g->builder, fn_val, ptr_usize_llvm_type, "");
|
||||
LLVMValueRef negative_one = LLVMConstInt(LLVMInt32Type(), -1, true);
|
||||
LLVMValueRef prefix_ptr = LLVMBuildInBoundsGEP(g->builder, casted_fn_val, &negative_one, 1, "");
|
||||
return LLVMBuildLoad(g->builder, prefix_ptr, "");
|
||||
LLVMValueRef load_inst = LLVMBuildLoad(g->builder, prefix_ptr, "");
|
||||
|
||||
// Some architectures (e.g SPARCv9) has different alignment requirements between a
|
||||
// function/usize pointer and also require all loads to be aligned.
|
||||
// On those architectures, not explicitly setting the alignment will lead into @frameSize
|
||||
// generating usize-aligned load instruction that could crash if the function pointer
|
||||
// happens to be not usize-aligned.
|
||||
LLVMSetAlignment(load_inst, 1);
|
||||
return load_inst;
|
||||
}
|
||||
|
||||
static void gen_init_stack_trace(CodeGen *g, LLVMValueRef trace_field_ptr, LLVMValueRef addrs_field_ptr) {
|
||||
|
||||
@ -1030,8 +1030,8 @@ pub const TestContext = struct {
|
||||
var file = try tmp_dir.openFile(bin_name, .{ .read = true });
|
||||
defer file.close();
|
||||
|
||||
const header = try std.elf.readHeader(file);
|
||||
var iterator = header.program_header_iterator(file);
|
||||
const header = try std.elf.Header.read(&file);
|
||||
var iterator = header.program_header_iterator(&file);
|
||||
|
||||
var none_loaded = true;
|
||||
|
||||
|
||||
@ -4608,7 +4608,7 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
|
||||
if (slice[0] != '\'' or slice[1] == '\\' or slice.len == 3) {
|
||||
return Tag.char_literal.create(c.arena, try zigifyEscapeSequences(c, m));
|
||||
} else {
|
||||
const str = try std.fmt.allocPrint(c.arena, "0x{x}", .{slice[1 .. slice.len - 1]});
|
||||
const str = try std.fmt.allocPrint(c.arena, "0x{s}", .{std.fmt.fmtSliceHexLower(slice[1 .. slice.len - 1])});
|
||||
return Tag.integer_literal.create(c.arena, str);
|
||||
}
|
||||
},
|
||||
|
||||
@ -2144,7 +2144,7 @@ pub const Value = extern union {
|
||||
base: Payload = .{ .tag = base_tag },
|
||||
data: struct {
|
||||
/// TODO revisit this when we have the concept of the error tag type
|
||||
fields: std.StringHashMapUnmanaged(u16),
|
||||
fields: std.StringHashMapUnmanaged(void),
|
||||
decl: *Module.Decl,
|
||||
},
|
||||
};
|
||||
|
||||
@ -299,6 +299,9 @@ pub const Inst = struct {
|
||||
xor,
|
||||
/// Create an optional type '?T'
|
||||
optional_type,
|
||||
/// Create an optional type '?T'. The operand is a pointer value. The optional type will
|
||||
/// be the type of the pointer element, wrapped in an optional.
|
||||
optional_type_from_ptr_elem,
|
||||
/// Create a union type.
|
||||
union_type,
|
||||
/// ?T => T with safety.
|
||||
@ -397,6 +400,7 @@ pub const Inst = struct {
|
||||
.mut_slice_type,
|
||||
.const_slice_type,
|
||||
.optional_type,
|
||||
.optional_type_from_ptr_elem,
|
||||
.optional_payload_safe,
|
||||
.optional_payload_unsafe,
|
||||
.optional_payload_safe_ptr,
|
||||
@ -597,6 +601,7 @@ pub const Inst = struct {
|
||||
.typeof,
|
||||
.xor,
|
||||
.optional_type,
|
||||
.optional_type_from_ptr_elem,
|
||||
.optional_payload_safe,
|
||||
.optional_payload_unsafe,
|
||||
.optional_payload_safe_ptr,
|
||||
@ -1649,6 +1654,7 @@ const DumpTzir = struct {
|
||||
|
||||
.add,
|
||||
.sub,
|
||||
.mul,
|
||||
.cmp_lt,
|
||||
.cmp_lte,
|
||||
.cmp_eq,
|
||||
@ -1771,6 +1777,7 @@ const DumpTzir = struct {
|
||||
|
||||
.add,
|
||||
.sub,
|
||||
.mul,
|
||||
.cmp_lt,
|
||||
.cmp_lte,
|
||||
.cmp_eq,
|
||||
|
||||
@ -131,6 +131,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
|
||||
.typeof => return zirTypeof(mod, scope, old_inst.castTag(.typeof).?),
|
||||
.typeof_peer => return zirTypeofPeer(mod, scope, old_inst.castTag(.typeof_peer).?),
|
||||
.optional_type => return zirOptionalType(mod, scope, old_inst.castTag(.optional_type).?),
|
||||
.optional_type_from_ptr_elem => return zirOptionalTypeFromPtrElem(mod, scope, old_inst.castTag(.optional_type_from_ptr_elem).?),
|
||||
.optional_payload_safe => return zirOptionalPayload(mod, scope, old_inst.castTag(.optional_payload_safe).?, true),
|
||||
.optional_payload_unsafe => return zirOptionalPayload(mod, scope, old_inst.castTag(.optional_payload_unsafe).?, false),
|
||||
.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
|
||||
return mod.constType(scope, optional.base.src, try mod.optionalType(scope, child_type));
|
||||
}
|
||||
|
||||
fn zirOptionalTypeFromPtrElem(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const ptr = try resolveInst(mod, scope, inst.positionals.operand);
|
||||
const elem_ty = ptr.ty.elemType();
|
||||
|
||||
return mod.constType(scope, inst.base.src, try mod.optionalType(scope, elem_ty));
|
||||
}
|
||||
|
||||
fn zirArrayType(mod: *Module, scope: *Scope, array: *zir.Inst.BinOp) InnerError!*Inst {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
@ -1154,7 +1165,7 @@ fn zirErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) InnerError
|
||||
|
||||
for (inst.positionals.fields) |field_name| {
|
||||
const entry = try mod.getErrorValue(field_name);
|
||||
if (payload.data.fields.fetchPutAssumeCapacity(entry.key, entry.value)) |prev| {
|
||||
if (payload.data.fields.fetchPutAssumeCapacity(entry.key, {})) |_| {
|
||||
return mod.fail(scope, inst.base.src, "duplicate error: '{s}'", .{field_name});
|
||||
}
|
||||
}
|
||||
@ -1185,7 +1196,79 @@ fn zirErrorValue(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorValue) InnerE
|
||||
fn zirMergeErrorSets(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
return mod.fail(scope, inst.base.src, "TODO implement merge_error_sets", .{});
|
||||
|
||||
const rhs_ty = try resolveType(mod, scope, inst.positionals.rhs);
|
||||
const lhs_ty = try resolveType(mod, scope, inst.positionals.lhs);
|
||||
if (rhs_ty.zigTypeTag() != .ErrorSet)
|
||||
return mod.fail(scope, inst.positionals.rhs.src, "expected error set type, found {}", .{rhs_ty});
|
||||
if (lhs_ty.zigTypeTag() != .ErrorSet)
|
||||
return mod.fail(scope, inst.positionals.lhs.src, "expected error set type, found {}", .{lhs_ty});
|
||||
|
||||
// anything merged with anyerror is anyerror
|
||||
if (lhs_ty.tag() == .anyerror or rhs_ty.tag() == .anyerror)
|
||||
return mod.constInst(scope, inst.base.src, .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.anyerror_type),
|
||||
});
|
||||
// The declarations arena will store the hashmap.
|
||||
var new_decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
|
||||
errdefer new_decl_arena.deinit();
|
||||
|
||||
const payload = try new_decl_arena.allocator.create(Value.Payload.ErrorSet);
|
||||
payload.* = .{
|
||||
.base = .{ .tag = .error_set },
|
||||
.data = .{
|
||||
.fields = .{},
|
||||
.decl = undefined, // populated below
|
||||
},
|
||||
};
|
||||
try payload.data.fields.ensureCapacity(&new_decl_arena.allocator, @intCast(u32, switch (rhs_ty.tag()) {
|
||||
.error_set_single => 1,
|
||||
.error_set => rhs_ty.castTag(.error_set).?.data.typed_value.most_recent.typed_value.val.castTag(.error_set).?.data.fields.size,
|
||||
else => unreachable,
|
||||
} + switch (lhs_ty.tag()) {
|
||||
.error_set_single => 1,
|
||||
.error_set => lhs_ty.castTag(.error_set).?.data.typed_value.most_recent.typed_value.val.castTag(.error_set).?.data.fields.size,
|
||||
else => unreachable,
|
||||
}));
|
||||
|
||||
switch (lhs_ty.tag()) {
|
||||
.error_set_single => {
|
||||
const name = lhs_ty.castTag(.error_set_single).?.data;
|
||||
payload.data.fields.putAssumeCapacity(name, {});
|
||||
},
|
||||
.error_set => {
|
||||
var multiple = lhs_ty.castTag(.error_set).?.data.typed_value.most_recent.typed_value.val.castTag(.error_set).?.data.fields;
|
||||
var it = multiple.iterator();
|
||||
while (it.next()) |entry| {
|
||||
payload.data.fields.putAssumeCapacity(entry.key, entry.value);
|
||||
}
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
|
||||
switch (rhs_ty.tag()) {
|
||||
.error_set_single => {
|
||||
const name = rhs_ty.castTag(.error_set_single).?.data;
|
||||
payload.data.fields.putAssumeCapacity(name, {});
|
||||
},
|
||||
.error_set => {
|
||||
var multiple = rhs_ty.castTag(.error_set).?.data.typed_value.most_recent.typed_value.val.castTag(.error_set).?.data.fields;
|
||||
var it = multiple.iterator();
|
||||
while (it.next()) |entry| {
|
||||
payload.data.fields.putAssumeCapacity(entry.key, entry.value);
|
||||
}
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
// TODO create name in format "error:line:column"
|
||||
const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initPayload(&payload.base),
|
||||
});
|
||||
payload.data.decl = new_decl;
|
||||
|
||||
return mod.analyzeDeclVal(scope, inst.base.src, new_decl);
|
||||
}
|
||||
|
||||
fn 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!
|
||||
const ir_tag = switch (inst.base.tag) {
|
||||
.add => Inst.Tag.add,
|
||||
.sub => Inst.Tag.sub,
|
||||
.mul => Inst.Tag.mul,
|
||||
else => return mod.fail(scope, inst.base.src, "TODO implement arithmetic for operand '{s}''", .{@tagName(inst.base.tag)}),
|
||||
};
|
||||
|
||||
|
||||
@ -27,6 +27,8 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
|
||||
\\#define FOO =
|
||||
\\#define PtrToPtr64(p) ((void *POINTER_64) p)
|
||||
\\#define STRUC_ALIGNED_STACK_COPY(t,s) ((CONST t *)(s))
|
||||
\\#define bar = 0x
|
||||
\\#define baz = 0b
|
||||
\\int main(void) {}
|
||||
, "");
|
||||
|
||||
|
||||
@ -141,5 +141,5 @@ comptime {
|
||||
_ = @import("behavior/while.zig");
|
||||
_ = @import("behavior/widening.zig");
|
||||
_ = @import("behavior/src.zig");
|
||||
// _ = @import("behavior/translate_c_macros.zig");
|
||||
_ = @import("behavior/translate_c_macros.zig");
|
||||
}
|
||||
|
||||
@ -344,4 +344,38 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||
"",
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
var case = ctx.exe("integer multiplication", linux_arm);
|
||||
// Simple u32 integer multiplication
|
||||
case.addCompareOutput(
|
||||
\\export fn _start() noreturn {
|
||||
\\ assert(mul(1, 1) == 1);
|
||||
\\ assert(mul(42, 1) == 42);
|
||||
\\ assert(mul(1, 42) == 42);
|
||||
\\ assert(mul(123, 42) == 5166);
|
||||
\\ exit();
|
||||
\\}
|
||||
\\
|
||||
\\fn mul(x: u32, y: u32) u32 {
|
||||
\\ return x * y;
|
||||
\\}
|
||||
\\
|
||||
\\fn assert(ok: bool) void {
|
||||
\\ if (!ok) unreachable;
|
||||
\\}
|
||||
\\
|
||||
\\fn exit() noreturn {
|
||||
\\ asm volatile ("svc #0"
|
||||
\\ :
|
||||
\\ : [number] "{r7}" (1),
|
||||
\\ [arg1] "{r0}" (0)
|
||||
\\ : "memory"
|
||||
\\ );
|
||||
\\ unreachable;
|
||||
\\}
|
||||
,
|
||||
"",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,4 +132,72 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||
\\}
|
||||
, "");
|
||||
}
|
||||
|
||||
{
|
||||
var case = ctx.exeUsingLlvmBackend("optionals", linux_x64);
|
||||
|
||||
case.addCompareOutput(
|
||||
\\fn assert(ok: bool) void {
|
||||
\\ if (!ok) unreachable;
|
||||
\\}
|
||||
\\
|
||||
\\export fn main() c_int {
|
||||
\\ var opt_val: ?i32 = 10;
|
||||
\\ var null_val: ?i32 = null;
|
||||
\\
|
||||
\\ var val1: i32 = opt_val.?;
|
||||
\\ const val1_1: i32 = opt_val.?;
|
||||
\\ var ptr_val1 = &(opt_val.?);
|
||||
\\ const ptr_val1_1 = &(opt_val.?);
|
||||
\\
|
||||
\\ var val2: i32 = null_val orelse 20;
|
||||
\\ const val2_2: i32 = null_val orelse 20;
|
||||
\\
|
||||
\\ var value: i32 = 20;
|
||||
\\ var ptr_val2 = &(null_val orelse value);
|
||||
\\
|
||||
\\ const val3 = opt_val orelse 30;
|
||||
\\ var val3_var = opt_val orelse 30;
|
||||
\\
|
||||
\\ assert(val1 == 10);
|
||||
\\ assert(val1_1 == 10);
|
||||
\\ assert(ptr_val1.* == 10);
|
||||
\\ assert(ptr_val1_1.* == 10);
|
||||
\\
|
||||
\\ assert(val2 == 20);
|
||||
\\ assert(val2_2 == 20);
|
||||
\\ assert(ptr_val2.* == 20);
|
||||
\\
|
||||
\\ assert(val3 == 10);
|
||||
\\ assert(val3_var == 10);
|
||||
\\
|
||||
\\ (null_val orelse val2) = 1234;
|
||||
\\ assert(val2 == 1234);
|
||||
\\
|
||||
\\ (opt_val orelse val2) = 5678;
|
||||
\\ assert(opt_val.? == 5678);
|
||||
\\
|
||||
\\ return 0;
|
||||
\\}
|
||||
, "");
|
||||
}
|
||||
|
||||
{
|
||||
var case = ctx.exeUsingLlvmBackend("for loop", linux_x64);
|
||||
|
||||
case.addCompareOutput(
|
||||
\\fn assert(ok: bool) void {
|
||||
\\ if (!ok) unreachable;
|
||||
\\}
|
||||
\\
|
||||
\\export fn main() c_int {
|
||||
\\ var x: u32 = 0;
|
||||
\\ for ("hello") |_| {
|
||||
\\ x += 1;
|
||||
\\ }
|
||||
\\ assert("hello".len == x);
|
||||
\\ return 0;
|
||||
\\}
|
||||
, "");
|
||||
}
|
||||
}
|
||||
|
||||
@ -985,7 +985,7 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||
"Hello, World!\n",
|
||||
);
|
||||
try case.files.append(.{
|
||||
.src =
|
||||
.src =
|
||||
\\pub fn print() void {
|
||||
\\ asm volatile ("syscall"
|
||||
\\ :
|
||||
@ -1525,4 +1525,37 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||
\\}
|
||||
, "");
|
||||
}
|
||||
{
|
||||
var case = ctx.exe("merge error sets", linux_x64);
|
||||
|
||||
case.addCompareOutput(
|
||||
\\export fn _start() noreturn {
|
||||
\\ const E = error{ A, B, D } || error { A, B, C };
|
||||
\\ const a = E.A;
|
||||
\\ const b = E.B;
|
||||
\\ const c = E.C;
|
||||
\\ const d = E.D;
|
||||
\\ const E2 = error { X, Y } || @TypeOf(error.Z);
|
||||
\\ const x = E2.X;
|
||||
\\ const y = E2.Y;
|
||||
\\ const z = E2.Z;
|
||||
\\ assert(anyerror || error { Z } == anyerror);
|
||||
\\ exit();
|
||||
\\}
|
||||
\\fn assert(b: bool) void {
|
||||
\\ if (!b) unreachable;
|
||||
\\}
|
||||
\\fn exit() noreturn {
|
||||
\\ asm volatile ("syscall"
|
||||
\\ :
|
||||
\\ : [number] "{rax}" (231),
|
||||
\\ [arg1] "{rdi}" (0)
|
||||
\\ : "rcx", "r11", "memory"
|
||||
\\ );
|
||||
\\ unreachable;
|
||||
\\}
|
||||
,
|
||||
"",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -268,6 +268,10 @@ const known_options = [_]KnownOpt{
|
||||
.name = "MD",
|
||||
.ident = "dep_file",
|
||||
},
|
||||
.{
|
||||
.name = "write-dependencies",
|
||||
.ident = "dep_file",
|
||||
},
|
||||
.{
|
||||
.name = "MV",
|
||||
.ident = "dep_file",
|
||||
@ -284,18 +288,30 @@ const known_options = [_]KnownOpt{
|
||||
.name = "MG",
|
||||
.ident = "dep_file",
|
||||
},
|
||||
.{
|
||||
.name = "print-missing-file-dependencies",
|
||||
.ident = "dep_file",
|
||||
},
|
||||
.{
|
||||
.name = "MJ",
|
||||
.ident = "dep_file",
|
||||
},
|
||||
.{
|
||||
.name = "MM",
|
||||
.ident = "dep_file",
|
||||
.ident = "dep_file_mm",
|
||||
},
|
||||
.{
|
||||
.name = "user-dependencies",
|
||||
.ident = "dep_file_mm",
|
||||
},
|
||||
.{
|
||||
.name = "MMD",
|
||||
.ident = "dep_file",
|
||||
},
|
||||
.{
|
||||
.name = "write-user-dependencies",
|
||||
.ident = "dep_file",
|
||||
},
|
||||
.{
|
||||
.name = "MP",
|
||||
.ident = "dep_file",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user