mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-27 19:09:47 +03:00
Merge remote-tracking branch 'origin/master' into llvm7
This commit is contained in:
+13
-1
@@ -393,7 +393,7 @@ if(MSVC)
|
||||
)
|
||||
else()
|
||||
set_target_properties(embedded_softfloat PROPERTIES
|
||||
COMPILE_FLAGS "-std=c99"
|
||||
COMPILE_FLAGS "-std=c99 -O3"
|
||||
)
|
||||
endif()
|
||||
target_include_directories(embedded_softfloat PUBLIC
|
||||
@@ -412,7 +412,9 @@ set(ZIG_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/src/bigint.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/buffer.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/c_tokenizer.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/cache_hash.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/codegen.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/compiler.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/errmsg.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/error.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/ir.cpp"
|
||||
@@ -427,6 +429,9 @@ set(ZIG_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/src/util.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/translate_c.cpp"
|
||||
)
|
||||
set(BLAKE_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/src/blake2b.c"
|
||||
)
|
||||
set(ZIG_CPP_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp"
|
||||
@@ -793,6 +798,7 @@ else()
|
||||
set(EXE_CFLAGS "${EXE_CFLAGS} -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D_GNU_SOURCE -fno-exceptions -fno-rtti -Werror=strict-prototypes -Werror=old-style-definition -Werror=type-limits -Wno-missing-braces")
|
||||
endif()
|
||||
|
||||
set(BLAKE_CFLAGS "-std=c99")
|
||||
|
||||
set(EXE_LDFLAGS " ")
|
||||
if(MINGW)
|
||||
@@ -814,6 +820,11 @@ set_target_properties(zig_cpp PROPERTIES
|
||||
COMPILE_FLAGS ${EXE_CFLAGS}
|
||||
)
|
||||
|
||||
add_library(embedded_blake STATIC ${BLAKE_SOURCES})
|
||||
set_target_properties(embedded_blake PROPERTIES
|
||||
COMPILE_FLAGS "${BLAKE_CFLAGS} -O3"
|
||||
)
|
||||
|
||||
add_executable(zig ${ZIG_SOURCES})
|
||||
set_target_properties(zig PROPERTIES
|
||||
COMPILE_FLAGS ${EXE_CFLAGS}
|
||||
@@ -822,6 +833,7 @@ set_target_properties(zig PROPERTIES
|
||||
|
||||
target_link_libraries(zig LINK_PUBLIC
|
||||
zig_cpp
|
||||
embedded_blake
|
||||
${SOFTFLOAT_LIBRARIES}
|
||||
${CLANG_LIBRARIES}
|
||||
${LLD_LIBRARIES}
|
||||
|
||||
@@ -16,11 +16,12 @@ pub fn build(b: *Builder) !void {
|
||||
var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
|
||||
|
||||
const rel_zig_exe = try os.path.relative(b.allocator, b.build_root, b.zig_exe);
|
||||
const langref_out_path = os.path.join(b.allocator, b.cache_root, "langref.html") catch unreachable;
|
||||
var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8{
|
||||
docgen_exe.getOutputPath(),
|
||||
rel_zig_exe,
|
||||
"doc" ++ os.path.sep_str ++ "langref.html.in",
|
||||
os.path.join(b.allocator, b.cache_root, "langref.html") catch unreachable,
|
||||
langref_out_path,
|
||||
});
|
||||
docgen_cmd.step.dependOn(&docgen_exe.step);
|
||||
|
||||
@@ -61,6 +62,9 @@ pub fn build(b: *Builder) !void {
|
||||
b.default_step.dependOn(&exe.step);
|
||||
|
||||
const skip_release = b.option(bool, "skip-release", "Main test suite skips release builds") orelse false;
|
||||
const skip_release_small = b.option(bool, "skip-release-small", "Main test suite skips release-small builds") orelse skip_release;
|
||||
const skip_release_fast = b.option(bool, "skip-release-fast", "Main test suite skips release-fast builds") orelse skip_release;
|
||||
const skip_release_safe = b.option(bool, "skip-release-safe", "Main test suite skips release-safe builds") orelse skip_release;
|
||||
const skip_self_hosted = b.option(bool, "skip-self-hosted", "Main test suite skips building self hosted compiler") orelse false;
|
||||
if (!skip_self_hosted) {
|
||||
test_step.dependOn(&exe.step);
|
||||
@@ -76,15 +80,29 @@ pub fn build(b: *Builder) !void {
|
||||
|
||||
const test_stage2_step = b.step("test-stage2", "Run the stage2 compiler tests");
|
||||
test_stage2_step.dependOn(&test_stage2.step);
|
||||
test_step.dependOn(test_stage2_step);
|
||||
|
||||
const all_modes = []builtin.Mode{
|
||||
builtin.Mode.Debug,
|
||||
builtin.Mode.ReleaseSafe,
|
||||
builtin.Mode.ReleaseFast,
|
||||
builtin.Mode.ReleaseSmall,
|
||||
};
|
||||
const modes = if (skip_release) []builtin.Mode{builtin.Mode.Debug} else all_modes;
|
||||
// TODO see https://github.com/ziglang/zig/issues/1364
|
||||
if (false) {
|
||||
test_step.dependOn(test_stage2_step);
|
||||
}
|
||||
|
||||
var chosen_modes: [4]builtin.Mode = undefined;
|
||||
var chosen_mode_index: usize = 0;
|
||||
chosen_modes[chosen_mode_index] = builtin.Mode.Debug;
|
||||
chosen_mode_index += 1;
|
||||
if (!skip_release_safe) {
|
||||
chosen_modes[chosen_mode_index] = builtin.Mode.ReleaseSafe;
|
||||
chosen_mode_index += 1;
|
||||
}
|
||||
if (!skip_release_fast) {
|
||||
chosen_modes[chosen_mode_index] = builtin.Mode.ReleaseFast;
|
||||
chosen_mode_index += 1;
|
||||
}
|
||||
if (!skip_release_small) {
|
||||
chosen_modes[chosen_mode_index] = builtin.Mode.ReleaseSmall;
|
||||
chosen_mode_index += 1;
|
||||
}
|
||||
const modes = chosen_modes[0..chosen_mode_index];
|
||||
|
||||
test_step.dependOn(tests.addPkgTests(b, test_filter, "test/behavior.zig", "behavior", "Run the behavior tests", modes));
|
||||
|
||||
|
||||
@@ -23,4 +23,4 @@ cd %ZIGBUILDDIR%
|
||||
cmake.exe .. -Thost=x64 -G"Visual Studio 14 2015 Win64" "-DCMAKE_INSTALL_PREFIX=%ZIGBUILDDIR%" "-DCMAKE_PREFIX_PATH=%ZIGPREFIXPATH%" -DCMAKE_BUILD_TYPE=Release || exit /b
|
||||
msbuild /p:Configuration=Release INSTALL.vcxproj || exit /b
|
||||
|
||||
bin\zig.exe build --build-file ..\build.zig test || exit /b
|
||||
bin\zig.exe build --build-file ..\build.zig test -Dskip-release || exit /b
|
||||
|
||||
@@ -8,9 +8,9 @@ export CXX=clang++-7.0
|
||||
echo $PATH
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd)
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Release
|
||||
make -j2 install
|
||||
./zig build --build-file ../build.zig test
|
||||
./zig build --build-file ../build.zig test -Dskip-release-small
|
||||
|
||||
if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then
|
||||
mkdir $TRAVIS_BUILD_DIR/artifacts
|
||||
|
||||
@@ -5,8 +5,8 @@ set -e
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_PREFIX_PATH=/usr/local/opt/llvm@7/ -DCMAKE_INSTALL_PREFIX=$(pwd)
|
||||
cmake .. -DCMAKE_PREFIX_PATH=/usr/local/opt/llvm@7/ -DCMAKE_BUILD_TYPE=Release
|
||||
make VERBOSE=1
|
||||
make install
|
||||
|
||||
./zig build --build-file ../build.zig test
|
||||
./zig build --build-file ../build.zig test -Dskip-release-small
|
||||
|
||||
+254
-3
@@ -11,6 +11,7 @@ const max_doc_file_size = 10 * 1024 * 1024;
|
||||
const exe_ext = std.build.Target(std.build.Target.Native).exeFileExt();
|
||||
const obj_ext = std.build.Target(std.build.Target.Native).oFileExt();
|
||||
const tmp_dir_name = "docgen_tmp";
|
||||
const test_out_path = tmp_dir_name ++ os.path.sep_str ++ "test" ++ exe_ext;
|
||||
|
||||
pub fn main() !void {
|
||||
var direct_allocator = std.heap.DirectAllocator.init();
|
||||
@@ -299,6 +300,7 @@ const Node = union(enum) {
|
||||
SeeAlso: []const SeeAlsoItem,
|
||||
Code: Code,
|
||||
Link: Link,
|
||||
Syntax: Token,
|
||||
};
|
||||
|
||||
const Toc = struct {
|
||||
@@ -529,6 +531,17 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
|
||||
},
|
||||
});
|
||||
tokenizer.code_node_count += 1;
|
||||
} else if (mem.eql(u8, tag_name, "syntax")) {
|
||||
_ = try eatToken(tokenizer, Token.Id.BracketClose);
|
||||
const content_tok = try eatToken(tokenizer, Token.Id.Content);
|
||||
_ = try eatToken(tokenizer, Token.Id.BracketOpen);
|
||||
const end_syntax_tag = try eatToken(tokenizer, Token.Id.TagContent);
|
||||
const end_tag_name = tokenizer.buffer[end_syntax_tag.start..end_syntax_tag.end];
|
||||
if (!mem.eql(u8, end_tag_name, "endsyntax")) {
|
||||
return parseError(tokenizer, end_syntax_tag, "invalid token inside syntax: {}", end_tag_name);
|
||||
}
|
||||
_ = try eatToken(tokenizer, Token.Id.BracketClose);
|
||||
try nodes.append(Node{ .Syntax = content_tok });
|
||||
} else {
|
||||
return parseError(tokenizer, tag_token, "unrecognized tag name: {}", tag_name);
|
||||
}
|
||||
@@ -570,6 +583,11 @@ fn escapeHtml(allocator: *mem.Allocator, input: []const u8) ![]u8 {
|
||||
|
||||
var buf_adapter = io.BufferOutStream.init(&buf);
|
||||
var out = &buf_adapter.stream;
|
||||
try writeEscaped(out, input);
|
||||
return buf.toOwnedSlice();
|
||||
}
|
||||
|
||||
fn writeEscaped(out: var, input: []const u8) !void {
|
||||
for (input) |c| {
|
||||
try switch (c) {
|
||||
'&' => out.write("&"),
|
||||
@@ -579,7 +597,6 @@ fn escapeHtml(allocator: *mem.Allocator, input: []const u8) ![]u8 {
|
||||
else => out.writeByte(c),
|
||||
};
|
||||
}
|
||||
return buf.toOwnedSlice();
|
||||
}
|
||||
|
||||
//#define VT_RED "\x1b[31;1m"
|
||||
@@ -686,6 +703,230 @@ fn termColor(allocator: *mem.Allocator, input: []const u8) ![]u8 {
|
||||
return buf.toOwnedSlice();
|
||||
}
|
||||
|
||||
const builtin_types = [][]const u8{
|
||||
"f16", "f32", "f64", "f128", "c_longdouble", "c_short",
|
||||
"c_ushort", "c_int", "c_uint", "c_long", "c_ulong", "c_longlong",
|
||||
"c_ulonglong", "c_char", "c_void", "void", "bool", "isize",
|
||||
"usize", "noreturn", "type", "error", "comptime_int", "comptime_float",
|
||||
};
|
||||
|
||||
fn isType(name: []const u8) bool {
|
||||
for (builtin_types) |t| {
|
||||
if (mem.eql(u8, t, name))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn tokenizeAndPrint(allocator: *mem.Allocator, docgen_tokenizer: *Tokenizer, out: var, source_token: Token) !void {
|
||||
const raw_src = docgen_tokenizer.buffer[source_token.start..source_token.end];
|
||||
const src = mem.trim(u8, raw_src, " \n");
|
||||
try out.write("<code class=\"zig\">");
|
||||
var tokenizer = std.zig.Tokenizer.init(src);
|
||||
var index: usize = 0;
|
||||
var next_tok_is_fn = false;
|
||||
while (true) {
|
||||
const prev_tok_was_fn = next_tok_is_fn;
|
||||
next_tok_is_fn = false;
|
||||
|
||||
const token = tokenizer.next();
|
||||
try writeEscaped(out, src[index..token.start]);
|
||||
switch (token.id) {
|
||||
std.zig.Token.Id.Eof => break,
|
||||
|
||||
std.zig.Token.Id.Keyword_align,
|
||||
std.zig.Token.Id.Keyword_and,
|
||||
std.zig.Token.Id.Keyword_asm,
|
||||
std.zig.Token.Id.Keyword_async,
|
||||
std.zig.Token.Id.Keyword_await,
|
||||
std.zig.Token.Id.Keyword_break,
|
||||
std.zig.Token.Id.Keyword_cancel,
|
||||
std.zig.Token.Id.Keyword_catch,
|
||||
std.zig.Token.Id.Keyword_comptime,
|
||||
std.zig.Token.Id.Keyword_const,
|
||||
std.zig.Token.Id.Keyword_continue,
|
||||
std.zig.Token.Id.Keyword_defer,
|
||||
std.zig.Token.Id.Keyword_else,
|
||||
std.zig.Token.Id.Keyword_enum,
|
||||
std.zig.Token.Id.Keyword_errdefer,
|
||||
std.zig.Token.Id.Keyword_error,
|
||||
std.zig.Token.Id.Keyword_export,
|
||||
std.zig.Token.Id.Keyword_extern,
|
||||
std.zig.Token.Id.Keyword_for,
|
||||
std.zig.Token.Id.Keyword_if,
|
||||
std.zig.Token.Id.Keyword_inline,
|
||||
std.zig.Token.Id.Keyword_nakedcc,
|
||||
std.zig.Token.Id.Keyword_noalias,
|
||||
std.zig.Token.Id.Keyword_or,
|
||||
std.zig.Token.Id.Keyword_orelse,
|
||||
std.zig.Token.Id.Keyword_packed,
|
||||
std.zig.Token.Id.Keyword_promise,
|
||||
std.zig.Token.Id.Keyword_pub,
|
||||
std.zig.Token.Id.Keyword_resume,
|
||||
std.zig.Token.Id.Keyword_return,
|
||||
std.zig.Token.Id.Keyword_section,
|
||||
std.zig.Token.Id.Keyword_stdcallcc,
|
||||
std.zig.Token.Id.Keyword_struct,
|
||||
std.zig.Token.Id.Keyword_suspend,
|
||||
std.zig.Token.Id.Keyword_switch,
|
||||
std.zig.Token.Id.Keyword_test,
|
||||
std.zig.Token.Id.Keyword_try,
|
||||
std.zig.Token.Id.Keyword_union,
|
||||
std.zig.Token.Id.Keyword_unreachable,
|
||||
std.zig.Token.Id.Keyword_use,
|
||||
std.zig.Token.Id.Keyword_var,
|
||||
std.zig.Token.Id.Keyword_volatile,
|
||||
std.zig.Token.Id.Keyword_while,
|
||||
=> {
|
||||
try out.write("<span class=\"tok-kw\">");
|
||||
try writeEscaped(out, src[token.start..token.end]);
|
||||
try out.write("</span>");
|
||||
},
|
||||
|
||||
std.zig.Token.Id.Keyword_fn => {
|
||||
try out.write("<span class=\"tok-kw\">");
|
||||
try writeEscaped(out, src[token.start..token.end]);
|
||||
try out.write("</span>");
|
||||
next_tok_is_fn = true;
|
||||
},
|
||||
|
||||
std.zig.Token.Id.Keyword_undefined,
|
||||
std.zig.Token.Id.Keyword_null,
|
||||
std.zig.Token.Id.Keyword_true,
|
||||
std.zig.Token.Id.Keyword_false,
|
||||
std.zig.Token.Id.Keyword_this,
|
||||
=> {
|
||||
try out.write("<span class=\"tok-null\">");
|
||||
try writeEscaped(out, src[token.start..token.end]);
|
||||
try out.write("</span>");
|
||||
},
|
||||
|
||||
std.zig.Token.Id.StringLiteral,
|
||||
std.zig.Token.Id.MultilineStringLiteralLine,
|
||||
std.zig.Token.Id.CharLiteral,
|
||||
=> {
|
||||
try out.write("<span class=\"tok-str\">");
|
||||
try writeEscaped(out, src[token.start..token.end]);
|
||||
try out.write("</span>");
|
||||
},
|
||||
|
||||
std.zig.Token.Id.Builtin => {
|
||||
try out.write("<span class=\"tok-builtin\">");
|
||||
try writeEscaped(out, src[token.start..token.end]);
|
||||
try out.write("</span>");
|
||||
},
|
||||
|
||||
std.zig.Token.Id.LineComment,
|
||||
std.zig.Token.Id.DocComment,
|
||||
=> {
|
||||
try out.write("<span class=\"tok-comment\">");
|
||||
try writeEscaped(out, src[token.start..token.end]);
|
||||
try out.write("</span>");
|
||||
},
|
||||
|
||||
std.zig.Token.Id.Identifier => {
|
||||
if (prev_tok_was_fn) {
|
||||
try out.write("<span class=\"tok-fn\">");
|
||||
try writeEscaped(out, src[token.start..token.end]);
|
||||
try out.write("</span>");
|
||||
} else {
|
||||
const is_int = blk: {
|
||||
if (src[token.start] != 'i' and src[token.start] != 'u')
|
||||
break :blk false;
|
||||
var i = token.start + 1;
|
||||
if (i == token.end)
|
||||
break :blk false;
|
||||
while (i != token.end) : (i += 1) {
|
||||
if (src[i] < '0' or src[i] > '9')
|
||||
break :blk false;
|
||||
}
|
||||
break :blk true;
|
||||
};
|
||||
if (is_int or isType(src[token.start..token.end])) {
|
||||
try out.write("<span class=\"tok-type\">");
|
||||
try writeEscaped(out, src[token.start..token.end]);
|
||||
try out.write("</span>");
|
||||
} else {
|
||||
try writeEscaped(out, src[token.start..token.end]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
std.zig.Token.Id.IntegerLiteral,
|
||||
std.zig.Token.Id.FloatLiteral,
|
||||
=> {
|
||||
try out.write("<span class=\"tok-number\">");
|
||||
try writeEscaped(out, src[token.start..token.end]);
|
||||
try out.write("</span>");
|
||||
},
|
||||
|
||||
std.zig.Token.Id.Bang,
|
||||
std.zig.Token.Id.Pipe,
|
||||
std.zig.Token.Id.PipePipe,
|
||||
std.zig.Token.Id.PipeEqual,
|
||||
std.zig.Token.Id.Equal,
|
||||
std.zig.Token.Id.EqualEqual,
|
||||
std.zig.Token.Id.EqualAngleBracketRight,
|
||||
std.zig.Token.Id.BangEqual,
|
||||
std.zig.Token.Id.LParen,
|
||||
std.zig.Token.Id.RParen,
|
||||
std.zig.Token.Id.Semicolon,
|
||||
std.zig.Token.Id.Percent,
|
||||
std.zig.Token.Id.PercentEqual,
|
||||
std.zig.Token.Id.LBrace,
|
||||
std.zig.Token.Id.RBrace,
|
||||
std.zig.Token.Id.LBracket,
|
||||
std.zig.Token.Id.RBracket,
|
||||
std.zig.Token.Id.Period,
|
||||
std.zig.Token.Id.Ellipsis2,
|
||||
std.zig.Token.Id.Ellipsis3,
|
||||
std.zig.Token.Id.Caret,
|
||||
std.zig.Token.Id.CaretEqual,
|
||||
std.zig.Token.Id.Plus,
|
||||
std.zig.Token.Id.PlusPlus,
|
||||
std.zig.Token.Id.PlusEqual,
|
||||
std.zig.Token.Id.PlusPercent,
|
||||
std.zig.Token.Id.PlusPercentEqual,
|
||||
std.zig.Token.Id.Minus,
|
||||
std.zig.Token.Id.MinusEqual,
|
||||
std.zig.Token.Id.MinusPercent,
|
||||
std.zig.Token.Id.MinusPercentEqual,
|
||||
std.zig.Token.Id.Asterisk,
|
||||
std.zig.Token.Id.AsteriskEqual,
|
||||
std.zig.Token.Id.AsteriskAsterisk,
|
||||
std.zig.Token.Id.AsteriskPercent,
|
||||
std.zig.Token.Id.AsteriskPercentEqual,
|
||||
std.zig.Token.Id.Arrow,
|
||||
std.zig.Token.Id.Colon,
|
||||
std.zig.Token.Id.Slash,
|
||||
std.zig.Token.Id.SlashEqual,
|
||||
std.zig.Token.Id.Comma,
|
||||
std.zig.Token.Id.Ampersand,
|
||||
std.zig.Token.Id.AmpersandEqual,
|
||||
std.zig.Token.Id.QuestionMark,
|
||||
std.zig.Token.Id.AngleBracketLeft,
|
||||
std.zig.Token.Id.AngleBracketLeftEqual,
|
||||
std.zig.Token.Id.AngleBracketAngleBracketLeft,
|
||||
std.zig.Token.Id.AngleBracketAngleBracketLeftEqual,
|
||||
std.zig.Token.Id.AngleBracketRight,
|
||||
std.zig.Token.Id.AngleBracketRightEqual,
|
||||
std.zig.Token.Id.AngleBracketAngleBracketRight,
|
||||
std.zig.Token.Id.AngleBracketAngleBracketRightEqual,
|
||||
std.zig.Token.Id.Tilde,
|
||||
std.zig.Token.Id.BracketStarBracket,
|
||||
=> try writeEscaped(out, src[token.start..token.end]),
|
||||
|
||||
std.zig.Token.Id.Invalid => return parseError(
|
||||
docgen_tokenizer,
|
||||
source_token,
|
||||
"syntax error",
|
||||
),
|
||||
}
|
||||
index = token.end;
|
||||
}
|
||||
try out.write("</code>");
|
||||
}
|
||||
|
||||
fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var, zig_exe: []const u8) !void {
|
||||
var code_progress_index: usize = 0;
|
||||
|
||||
@@ -725,17 +966,21 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
||||
}
|
||||
try out.write("</ul>\n");
|
||||
},
|
||||
Node.Syntax => |content_tok| {
|
||||
try tokenizeAndPrint(allocator, tokenizer, out, content_tok);
|
||||
},
|
||||
Node.Code => |code| {
|
||||
code_progress_index += 1;
|
||||
warn("docgen example code {}/{}...", code_progress_index, tokenizer.code_node_count);
|
||||
|
||||
const raw_source = tokenizer.buffer[code.source_token.start..code.source_token.end];
|
||||
const trimmed_raw_source = mem.trim(u8, raw_source, " \n");
|
||||
const escaped_source = try escapeHtml(allocator, trimmed_raw_source);
|
||||
if (!code.is_inline) {
|
||||
try out.print("<p class=\"file\">{}.zig</p>", code.name);
|
||||
}
|
||||
try out.print("<pre><code class=\"zig\">{}</code></pre>", escaped_source);
|
||||
try out.write("<pre>");
|
||||
try tokenizeAndPrint(allocator, tokenizer, out, code.source_token);
|
||||
try out.write("</pre>");
|
||||
const name_plus_ext = try std.fmt.allocPrint(allocator, "{}.zig", code.name);
|
||||
const tmp_source_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_ext);
|
||||
try io.writeFile(tmp_source_file_name, trimmed_raw_source);
|
||||
@@ -821,6 +1066,8 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
||||
zig_exe,
|
||||
"test",
|
||||
tmp_source_file_name,
|
||||
"--output",
|
||||
test_out_path,
|
||||
});
|
||||
try out.print("<pre><code class=\"shell\">$ zig test {}.zig", code.name);
|
||||
switch (code.mode) {
|
||||
@@ -863,6 +1110,8 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
||||
"--color",
|
||||
"on",
|
||||
tmp_source_file_name,
|
||||
"--output",
|
||||
test_out_path,
|
||||
});
|
||||
try out.print("<pre><code class=\"shell\">$ zig test {}.zig", code.name);
|
||||
switch (code.mode) {
|
||||
@@ -918,6 +1167,8 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
||||
zig_exe,
|
||||
"test",
|
||||
tmp_source_file_name,
|
||||
"--output",
|
||||
test_out_path,
|
||||
});
|
||||
switch (code.mode) {
|
||||
builtin.Mode.Debug => {},
|
||||
|
||||
+742
-809
File diff suppressed because one or more lines are too long
@@ -737,7 +737,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8) FmtError!void {
|
||||
file_path,
|
||||
max_src_size,
|
||||
)) catch |err| switch (err) {
|
||||
error.IsDir => {
|
||||
error.IsDir, error.AccessDenied => {
|
||||
// TODO make event based (and dir.next())
|
||||
var dir = try std.os.Dir.open(fmt.loop.allocator, file_path);
|
||||
defer dir.close();
|
||||
|
||||
@@ -40,7 +40,6 @@ pub const Type = struct {
|
||||
Id.Enum => @fieldParentPtr(Enum, "base", base).destroy(comp),
|
||||
Id.Union => @fieldParentPtr(Union, "base", base).destroy(comp),
|
||||
Id.Namespace => @fieldParentPtr(Namespace, "base", base).destroy(comp),
|
||||
Id.Block => @fieldParentPtr(Block, "base", base).destroy(comp),
|
||||
Id.BoundFn => @fieldParentPtr(BoundFn, "base", base).destroy(comp),
|
||||
Id.ArgTuple => @fieldParentPtr(ArgTuple, "base", base).destroy(comp),
|
||||
Id.Opaque => @fieldParentPtr(Opaque, "base", base).destroy(comp),
|
||||
@@ -74,7 +73,6 @@ pub const Type = struct {
|
||||
Id.Enum => return @fieldParentPtr(Enum, "base", base).getLlvmType(allocator, llvm_context),
|
||||
Id.Union => return @fieldParentPtr(Union, "base", base).getLlvmType(allocator, llvm_context),
|
||||
Id.Namespace => unreachable,
|
||||
Id.Block => unreachable,
|
||||
Id.BoundFn => return @fieldParentPtr(BoundFn, "base", base).getLlvmType(allocator, llvm_context),
|
||||
Id.ArgTuple => unreachable,
|
||||
Id.Opaque => return @fieldParentPtr(Opaque, "base", base).getLlvmType(allocator, llvm_context),
|
||||
@@ -90,7 +88,6 @@ pub const Type = struct {
|
||||
Id.Undefined,
|
||||
Id.Null,
|
||||
Id.Namespace,
|
||||
Id.Block,
|
||||
Id.BoundFn,
|
||||
Id.ArgTuple,
|
||||
Id.Opaque,
|
||||
@@ -124,7 +121,6 @@ pub const Type = struct {
|
||||
Id.Undefined,
|
||||
Id.Null,
|
||||
Id.Namespace,
|
||||
Id.Block,
|
||||
Id.BoundFn,
|
||||
Id.ArgTuple,
|
||||
Id.Opaque,
|
||||
@@ -1012,14 +1008,6 @@ pub const Type = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const Block = struct {
|
||||
base: Type,
|
||||
|
||||
pub fn destroy(self: *Block, comp: *Compilation) void {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
};
|
||||
|
||||
pub const BoundFn = struct {
|
||||
base: Type,
|
||||
|
||||
|
||||
+175
-172
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "list.hpp"
|
||||
#include "buffer.hpp"
|
||||
#include "cache_hash.hpp"
|
||||
#include "zig_llvm.h"
|
||||
#include "hash_map.hpp"
|
||||
#include "errmsg.hpp"
|
||||
@@ -282,7 +283,6 @@ struct ConstExprValue {
|
||||
ConstArrayValue x_array;
|
||||
ConstPtrValue x_ptr;
|
||||
ImportTableEntry *x_import;
|
||||
Scope *x_block;
|
||||
ConstArgTuple x_arg_tuple;
|
||||
|
||||
// populated if special == ConstValSpecialRuntime
|
||||
@@ -412,7 +412,6 @@ enum NodeType {
|
||||
NodeTypeBoolLiteral,
|
||||
NodeTypeNullLiteral,
|
||||
NodeTypeUndefinedLiteral,
|
||||
NodeTypeThisLiteral,
|
||||
NodeTypeUnreachable,
|
||||
NodeTypeIfBoolExpr,
|
||||
NodeTypeWhileExpr,
|
||||
@@ -1013,13 +1012,13 @@ enum PtrLen {
|
||||
|
||||
struct ZigTypePointer {
|
||||
ZigType *child_type;
|
||||
ZigType *slice_parent;
|
||||
PtrLen ptr_len;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
uint32_t alignment;
|
||||
uint32_t explicit_alignment; // 0 means use ABI alignment
|
||||
uint32_t bit_offset;
|
||||
uint32_t unaligned_bit_count;
|
||||
ZigType *slice_parent;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
};
|
||||
|
||||
struct ZigTypeInt {
|
||||
@@ -1047,32 +1046,35 @@ struct TypeStructField {
|
||||
size_t unaligned_bit_count;
|
||||
AstNode *decl_node;
|
||||
};
|
||||
|
||||
enum ResolveStatus {
|
||||
ResolveStatusUnstarted,
|
||||
ResolveStatusInvalid,
|
||||
ResolveStatusZeroBitsKnown,
|
||||
ResolveStatusAlignmentKnown,
|
||||
ResolveStatusSizeKnown,
|
||||
};
|
||||
|
||||
struct ZigTypeStruct {
|
||||
AstNode *decl_node;
|
||||
ContainerLayout layout;
|
||||
TypeStructField *fields;
|
||||
ScopeDecls *decls_scope;
|
||||
uint64_t size_bytes;
|
||||
HashMap<Buf *, TypeStructField *, buf_hash, buf_eql_buf> fields_by_name;
|
||||
|
||||
uint32_t src_field_count;
|
||||
uint32_t gen_field_count;
|
||||
TypeStructField *fields;
|
||||
uint64_t size_bytes;
|
||||
bool is_invalid; // true if any fields are invalid
|
||||
|
||||
uint32_t abi_alignment; // known after ResolveStatusAlignmentKnown
|
||||
ContainerLayout layout;
|
||||
ResolveStatus resolve_status;
|
||||
|
||||
bool is_slice;
|
||||
ScopeDecls *decls_scope;
|
||||
|
||||
// set this flag temporarily to detect infinite loops
|
||||
bool embedded_in_current;
|
||||
bool resolve_loop_flag; // set this flag temporarily to detect infinite loops
|
||||
bool reported_infinite_err;
|
||||
// whether we've finished resolving it
|
||||
bool complete;
|
||||
|
||||
// whether any of the fields require comptime
|
||||
// the value is not valid until zero_bits_known == true
|
||||
// known after ResolveStatusZeroBitsKnown
|
||||
bool requires_comptime;
|
||||
|
||||
bool zero_bits_loop_flag;
|
||||
bool zero_bits_known;
|
||||
uint32_t abi_alignment; // also figured out with zero_bits pass
|
||||
|
||||
HashMap<Buf *, TypeStructField *, buf_hash, buf_eql_buf> fields_by_name;
|
||||
};
|
||||
|
||||
struct ZigTypeOptional {
|
||||
@@ -1204,7 +1206,6 @@ enum ZigTypeId {
|
||||
ZigTypeIdUnion,
|
||||
ZigTypeIdFn,
|
||||
ZigTypeIdNamespace,
|
||||
ZigTypeIdBlock,
|
||||
ZigTypeIdBoundFn,
|
||||
ZigTypeIdArgTuple,
|
||||
ZigTypeIdOpaque,
|
||||
@@ -1412,6 +1413,7 @@ enum BuiltinFnId {
|
||||
BuiltinFnIdSetEvalBranchQuota,
|
||||
BuiltinFnIdAlignCast,
|
||||
BuiltinFnIdOpaqueType,
|
||||
BuiltinFnIdThis,
|
||||
BuiltinFnIdSetAlignStack,
|
||||
BuiltinFnIdArgType,
|
||||
BuiltinFnIdExport,
|
||||
@@ -1550,22 +1552,50 @@ struct LinkLib {
|
||||
bool provided_explicitly;
|
||||
};
|
||||
|
||||
// When adding fields, check if they should be added to the hash computation in build_with_cache
|
||||
struct CodeGen {
|
||||
//////////////////////////// Runtime State
|
||||
LLVMModuleRef module;
|
||||
ZigList<ErrorMsg*> errors;
|
||||
LLVMBuilderRef builder;
|
||||
ZigLLVMDIBuilder *dbuilder;
|
||||
ZigLLVMDICompileUnit *compile_unit;
|
||||
ZigLLVMDIFile *compile_unit_file;
|
||||
|
||||
ZigList<LinkLib *> link_libs_list;
|
||||
LinkLib *libc_link_lib;
|
||||
|
||||
// add -framework [name] args to linker
|
||||
ZigList<Buf *> darwin_frameworks;
|
||||
// add -rpath [name] args to linker
|
||||
ZigList<Buf *> rpath_list;
|
||||
|
||||
LLVMTargetDataRef target_data_ref;
|
||||
LLVMTargetMachineRef target_machine;
|
||||
ZigLLVMDIFile *dummy_di_file;
|
||||
LLVMValueRef cur_ret_ptr;
|
||||
LLVMValueRef cur_fn_val;
|
||||
LLVMValueRef cur_err_ret_trace_val_arg;
|
||||
LLVMValueRef cur_err_ret_trace_val_stack;
|
||||
LLVMValueRef memcpy_fn_val;
|
||||
LLVMValueRef memset_fn_val;
|
||||
LLVMValueRef trap_fn_val;
|
||||
LLVMValueRef return_address_fn_val;
|
||||
LLVMValueRef frame_address_fn_val;
|
||||
LLVMValueRef coro_destroy_fn_val;
|
||||
LLVMValueRef coro_id_fn_val;
|
||||
LLVMValueRef coro_alloc_fn_val;
|
||||
LLVMValueRef coro_size_fn_val;
|
||||
LLVMValueRef coro_begin_fn_val;
|
||||
LLVMValueRef coro_suspend_fn_val;
|
||||
LLVMValueRef coro_end_fn_val;
|
||||
LLVMValueRef coro_free_fn_val;
|
||||
LLVMValueRef coro_resume_fn_val;
|
||||
LLVMValueRef coro_save_fn_val;
|
||||
LLVMValueRef coro_promise_fn_val;
|
||||
LLVMValueRef coro_alloc_helper_fn_val;
|
||||
LLVMValueRef coro_frame_fn_val;
|
||||
LLVMValueRef merge_err_ret_traces_fn_val;
|
||||
LLVMValueRef add_error_return_trace_addr_fn_val;
|
||||
LLVMValueRef stacksave_fn_val;
|
||||
LLVMValueRef stackrestore_fn_val;
|
||||
LLVMValueRef write_register_fn_val;
|
||||
LLVMValueRef sp_md_node;
|
||||
LLVMValueRef err_name_table;
|
||||
LLVMValueRef safety_crash_err_fn;
|
||||
LLVMValueRef return_err_fn;
|
||||
|
||||
// reminder: hash tables must be initialized before use
|
||||
HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table;
|
||||
@@ -1582,15 +1612,29 @@ struct CodeGen {
|
||||
HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table;
|
||||
HashMap<const ZigType *, ConstExprValue *, type_ptr_hash, type_ptr_eql> type_info_cache;
|
||||
|
||||
|
||||
ZigList<ImportTableEntry *> import_queue;
|
||||
size_t import_queue_index;
|
||||
ZigList<Tld *> resolve_queue;
|
||||
size_t resolve_queue_index;
|
||||
ZigList<AstNode *> use_queue;
|
||||
size_t use_queue_index;
|
||||
ZigList<TimeEvent> timing_events;
|
||||
ZigList<ZigLLVMDIType **> error_di_types;
|
||||
ZigList<AstNode *> tld_ref_source_node_stack;
|
||||
ZigList<ZigFn *> inline_fns;
|
||||
ZigList<ZigFn *> test_fns;
|
||||
ZigList<ZigLLVMDIEnumerator *> err_enumerators;
|
||||
ZigList<ErrorTableEntry *> errors_by_index;
|
||||
size_t largest_err_name_len;
|
||||
|
||||
uint32_t next_unresolved_index;
|
||||
PackageTableEntry *std_package;
|
||||
PackageTableEntry *panic_package;
|
||||
PackageTableEntry *test_runner_package;
|
||||
PackageTableEntry *compile_var_package;
|
||||
ImportTableEntry *compile_var_import;
|
||||
ImportTableEntry *root_import;
|
||||
ImportTableEntry *bootstrap_import;
|
||||
ImportTableEntry *test_runner_import;
|
||||
|
||||
struct {
|
||||
ZigType *entry_bool;
|
||||
@@ -1626,14 +1670,45 @@ struct CodeGen {
|
||||
ZigType *entry_arg_tuple;
|
||||
ZigType *entry_promise;
|
||||
} builtin_types;
|
||||
ZigType *align_amt_type;
|
||||
ZigType *stack_trace_type;
|
||||
ZigType *ptr_to_stack_trace_type;
|
||||
ZigType *err_tag_type;
|
||||
ZigType *test_fn_type;
|
||||
|
||||
EmitFileType emit_file_type;
|
||||
ZigTarget zig_target;
|
||||
LLVMTargetDataRef target_data_ref;
|
||||
Buf triple_str;
|
||||
Buf global_asm;
|
||||
Buf *out_h_path;
|
||||
Buf artifact_dir;
|
||||
Buf output_file_path;
|
||||
Buf o_file_output_path;
|
||||
Buf *wanted_output_file_path;
|
||||
Buf cache_dir;
|
||||
|
||||
IrInstruction *invalid_instruction;
|
||||
|
||||
ConstExprValue const_void_val;
|
||||
ConstExprValue panic_msg_vals[PanicMsgIdCount];
|
||||
|
||||
// The function definitions this module includes.
|
||||
ZigList<ZigFn *> fn_defs;
|
||||
size_t fn_defs_index;
|
||||
ZigList<TldVar *> global_vars;
|
||||
|
||||
ZigFn *cur_fn;
|
||||
ZigFn *main_fn;
|
||||
ZigFn *panic_fn;
|
||||
AstNode *root_export_decl;
|
||||
|
||||
CacheHash cache_hash;
|
||||
ErrColor err_color;
|
||||
uint32_t next_unresolved_index;
|
||||
unsigned pointer_size_bytes;
|
||||
uint32_t target_os_index;
|
||||
uint32_t target_arch_index;
|
||||
uint32_t target_environ_index;
|
||||
uint32_t target_oformat_index;
|
||||
bool is_big_endian;
|
||||
bool is_static;
|
||||
bool strip_debug_symbols;
|
||||
bool want_h_file;
|
||||
bool have_pub_main;
|
||||
bool have_c_main;
|
||||
@@ -1641,6 +1716,65 @@ struct CodeGen {
|
||||
bool have_winmain_crt_startup;
|
||||
bool have_dllmain_crt_startup;
|
||||
bool have_pub_panic;
|
||||
bool have_err_ret_tracing;
|
||||
bool c_want_stdint;
|
||||
bool c_want_stdbool;
|
||||
bool verbose_tokenize;
|
||||
bool verbose_ast;
|
||||
bool verbose_link;
|
||||
bool verbose_ir;
|
||||
bool verbose_llvm_ir;
|
||||
bool verbose_cimport;
|
||||
bool error_during_imports;
|
||||
bool generate_error_name_table;
|
||||
bool enable_cache;
|
||||
bool enable_time_report;
|
||||
|
||||
//////////////////////////// Participates in Input Parameter Cache Hash
|
||||
ZigList<LinkLib *> link_libs_list;
|
||||
// add -framework [name] args to linker
|
||||
ZigList<Buf *> darwin_frameworks;
|
||||
// add -rpath [name] args to linker
|
||||
ZigList<Buf *> rpath_list;
|
||||
ZigList<Buf *> forbidden_libs;
|
||||
ZigList<Buf *> link_objects;
|
||||
ZigList<Buf *> assembly_files;
|
||||
ZigList<const char *> lib_dirs;
|
||||
|
||||
size_t version_major;
|
||||
size_t version_minor;
|
||||
size_t version_patch;
|
||||
const char *linker_script;
|
||||
|
||||
EmitFileType emit_file_type;
|
||||
BuildMode build_mode;
|
||||
OutType out_type;
|
||||
ZigTarget zig_target;
|
||||
bool is_static;
|
||||
bool strip_debug_symbols;
|
||||
bool is_test_build;
|
||||
bool is_native_target;
|
||||
bool windows_subsystem_windows;
|
||||
bool windows_subsystem_console;
|
||||
bool linker_rdynamic;
|
||||
bool no_rosegment_workaround;
|
||||
bool each_lib_rpath;
|
||||
|
||||
Buf *mmacosx_version_min;
|
||||
Buf *mios_version_min;
|
||||
Buf *root_out_name;
|
||||
Buf *test_filter;
|
||||
Buf *test_name_prefix;
|
||||
PackageTableEntry *root_package;
|
||||
|
||||
const char **llvm_argv;
|
||||
size_t llvm_argv_len;
|
||||
|
||||
const char **clang_argv;
|
||||
size_t clang_argv_len;
|
||||
|
||||
//////////////////////////// Unsorted
|
||||
|
||||
Buf *libc_lib_dir;
|
||||
Buf *libc_static_lib_dir;
|
||||
Buf *libc_include_dir;
|
||||
@@ -1651,138 +1785,7 @@ struct CodeGen {
|
||||
Buf *zig_c_headers_dir;
|
||||
Buf *zig_std_special_dir;
|
||||
Buf *dynamic_linker;
|
||||
Buf *ar_path;
|
||||
ZigWindowsSDK *win_sdk;
|
||||
Buf triple_str;
|
||||
BuildMode build_mode;
|
||||
bool is_test_build;
|
||||
bool have_err_ret_tracing;
|
||||
uint32_t target_os_index;
|
||||
uint32_t target_arch_index;
|
||||
uint32_t target_environ_index;
|
||||
uint32_t target_oformat_index;
|
||||
LLVMTargetMachineRef target_machine;
|
||||
ZigLLVMDIFile *dummy_di_file;
|
||||
bool is_native_target;
|
||||
PackageTableEntry *root_package;
|
||||
PackageTableEntry *std_package;
|
||||
PackageTableEntry *panic_package;
|
||||
PackageTableEntry *test_runner_package;
|
||||
PackageTableEntry *compile_var_package;
|
||||
ImportTableEntry *compile_var_import;
|
||||
Buf *root_out_name;
|
||||
bool windows_subsystem_windows;
|
||||
bool windows_subsystem_console;
|
||||
Buf *mmacosx_version_min;
|
||||
Buf *mios_version_min;
|
||||
bool linker_rdynamic;
|
||||
const char *linker_script;
|
||||
|
||||
// The function definitions this module includes.
|
||||
ZigList<ZigFn *> fn_defs;
|
||||
size_t fn_defs_index;
|
||||
ZigList<TldVar *> global_vars;
|
||||
|
||||
OutType out_type;
|
||||
ZigFn *cur_fn;
|
||||
ZigFn *main_fn;
|
||||
ZigFn *panic_fn;
|
||||
LLVMValueRef cur_ret_ptr;
|
||||
LLVMValueRef cur_fn_val;
|
||||
LLVMValueRef cur_err_ret_trace_val_arg;
|
||||
LLVMValueRef cur_err_ret_trace_val_stack;
|
||||
bool c_want_stdint;
|
||||
bool c_want_stdbool;
|
||||
AstNode *root_export_decl;
|
||||
size_t version_major;
|
||||
size_t version_minor;
|
||||
size_t version_patch;
|
||||
bool verbose_tokenize;
|
||||
bool verbose_ast;
|
||||
bool verbose_link;
|
||||
bool verbose_ir;
|
||||
bool verbose_llvm_ir;
|
||||
bool verbose_cimport;
|
||||
ErrColor err_color;
|
||||
ImportTableEntry *root_import;
|
||||
ImportTableEntry *bootstrap_import;
|
||||
ImportTableEntry *test_runner_import;
|
||||
LLVMValueRef trap_fn_val;
|
||||
LLVMValueRef return_address_fn_val;
|
||||
LLVMValueRef frame_address_fn_val;
|
||||
LLVMValueRef coro_destroy_fn_val;
|
||||
LLVMValueRef coro_id_fn_val;
|
||||
LLVMValueRef coro_alloc_fn_val;
|
||||
LLVMValueRef coro_size_fn_val;
|
||||
LLVMValueRef coro_begin_fn_val;
|
||||
LLVMValueRef coro_suspend_fn_val;
|
||||
LLVMValueRef coro_end_fn_val;
|
||||
LLVMValueRef coro_free_fn_val;
|
||||
LLVMValueRef coro_resume_fn_val;
|
||||
LLVMValueRef coro_save_fn_val;
|
||||
LLVMValueRef coro_promise_fn_val;
|
||||
LLVMValueRef coro_alloc_helper_fn_val;
|
||||
LLVMValueRef coro_frame_fn_val;
|
||||
LLVMValueRef merge_err_ret_traces_fn_val;
|
||||
LLVMValueRef add_error_return_trace_addr_fn_val;
|
||||
LLVMValueRef stacksave_fn_val;
|
||||
LLVMValueRef stackrestore_fn_val;
|
||||
LLVMValueRef write_register_fn_val;
|
||||
bool error_during_imports;
|
||||
|
||||
LLVMValueRef sp_md_node;
|
||||
|
||||
const char **clang_argv;
|
||||
size_t clang_argv_len;
|
||||
ZigList<const char *> lib_dirs;
|
||||
|
||||
const char **llvm_argv;
|
||||
size_t llvm_argv_len;
|
||||
|
||||
ZigList<ZigFn *> test_fns;
|
||||
ZigType *test_fn_type;
|
||||
|
||||
bool each_lib_rpath;
|
||||
|
||||
ZigType *err_tag_type;
|
||||
ZigList<ZigLLVMDIEnumerator *> err_enumerators;
|
||||
ZigList<ErrorTableEntry *> errors_by_index;
|
||||
bool generate_error_name_table;
|
||||
LLVMValueRef err_name_table;
|
||||
size_t largest_err_name_len;
|
||||
LLVMValueRef safety_crash_err_fn;
|
||||
|
||||
LLVMValueRef return_err_fn;
|
||||
|
||||
IrInstruction *invalid_instruction;
|
||||
ConstExprValue const_void_val;
|
||||
|
||||
ConstExprValue panic_msg_vals[PanicMsgIdCount];
|
||||
|
||||
Buf global_asm;
|
||||
ZigList<Buf *> link_objects;
|
||||
ZigList<Buf *> assembly_files;
|
||||
|
||||
Buf *test_filter;
|
||||
Buf *test_name_prefix;
|
||||
|
||||
ZigList<TimeEvent> timing_events;
|
||||
|
||||
Buf cache_dir;
|
||||
Buf *out_h_path;
|
||||
|
||||
ZigList<ZigFn *> inline_fns;
|
||||
ZigList<AstNode *> tld_ref_source_node_stack;
|
||||
|
||||
ZigType *align_amt_type;
|
||||
ZigType *stack_trace_type;
|
||||
ZigType *ptr_to_stack_trace_type;
|
||||
|
||||
ZigList<ZigLLVMDIType **> error_di_types;
|
||||
|
||||
ZigList<Buf *> forbidden_libs;
|
||||
|
||||
bool no_rosegment_workaround;
|
||||
};
|
||||
|
||||
enum VarLinkage {
|
||||
@@ -3285,8 +3288,8 @@ static const size_t stack_trace_ptr_count = 30;
|
||||
|
||||
|
||||
enum FloatMode {
|
||||
FloatModeOptimized,
|
||||
FloatModeStrict,
|
||||
FloatModeOptimized,
|
||||
};
|
||||
|
||||
enum FnWalkId {
|
||||
|
||||
+296
-274
@@ -23,6 +23,7 @@ static Error resolve_enum_type(CodeGen *g, ZigType *enum_type);
|
||||
static Error resolve_struct_type(CodeGen *g, ZigType *struct_type);
|
||||
|
||||
static Error ATTRIBUTE_MUST_USE resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type);
|
||||
static Error ATTRIBUTE_MUST_USE resolve_struct_alignment(CodeGen *g, ZigType *struct_type);
|
||||
static Error ATTRIBUTE_MUST_USE resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type);
|
||||
static Error ATTRIBUTE_MUST_USE resolve_union_zero_bits(CodeGen *g, ZigType *union_type);
|
||||
static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry);
|
||||
@@ -246,7 +247,6 @@ AstNode *type_decl_node(ZigType *type_entry) {
|
||||
case ZigTypeIdErrorSet:
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdPromise:
|
||||
@@ -255,82 +255,71 @@ AstNode *type_decl_node(ZigType *type_entry) {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
bool type_is_resolved(ZigType *type_entry, ResolveStatus status) {
|
||||
switch (type_entry->id) {
|
||||
case ZigTypeIdInvalid:
|
||||
zig_unreachable();
|
||||
case ZigTypeIdStruct:
|
||||
return type_entry->data.structure.resolve_status >= status;
|
||||
case ZigTypeIdEnum:
|
||||
switch (status) {
|
||||
case ResolveStatusUnstarted:
|
||||
return true;
|
||||
case ResolveStatusInvalid:
|
||||
zig_unreachable();
|
||||
case ResolveStatusZeroBitsKnown:
|
||||
return type_entry->data.enumeration.zero_bits_known;
|
||||
case ResolveStatusAlignmentKnown:
|
||||
return type_entry->data.enumeration.zero_bits_known;
|
||||
case ResolveStatusSizeKnown:
|
||||
return type_entry->data.enumeration.complete;
|
||||
}
|
||||
zig_unreachable();
|
||||
case ZigTypeIdUnion:
|
||||
switch (status) {
|
||||
case ResolveStatusUnstarted:
|
||||
return true;
|
||||
case ResolveStatusInvalid:
|
||||
zig_unreachable();
|
||||
case ResolveStatusZeroBitsKnown:
|
||||
return type_entry->data.unionation.zero_bits_known;
|
||||
case ResolveStatusAlignmentKnown:
|
||||
return type_entry->data.unionation.zero_bits_known;
|
||||
case ResolveStatusSizeKnown:
|
||||
return type_entry->data.unionation.complete;
|
||||
}
|
||||
zig_unreachable();
|
||||
case ZigTypeIdOpaque:
|
||||
return status < ResolveStatusSizeKnown;
|
||||
case ZigTypeIdMetaType:
|
||||
case ZigTypeIdVoid:
|
||||
case ZigTypeIdBool:
|
||||
case ZigTypeIdUnreachable:
|
||||
case ZigTypeIdInt:
|
||||
case ZigTypeIdFloat:
|
||||
case ZigTypeIdPointer:
|
||||
case ZigTypeIdArray:
|
||||
case ZigTypeIdComptimeFloat:
|
||||
case ZigTypeIdComptimeInt:
|
||||
case ZigTypeIdUndefined:
|
||||
case ZigTypeIdNull:
|
||||
case ZigTypeIdOptional:
|
||||
case ZigTypeIdErrorUnion:
|
||||
case ZigTypeIdErrorSet:
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdPromise:
|
||||
return true;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
bool type_is_complete(ZigType *type_entry) {
|
||||
switch (type_entry->id) {
|
||||
case ZigTypeIdInvalid:
|
||||
zig_unreachable();
|
||||
case ZigTypeIdStruct:
|
||||
return type_entry->data.structure.complete;
|
||||
case ZigTypeIdEnum:
|
||||
return type_entry->data.enumeration.complete;
|
||||
case ZigTypeIdUnion:
|
||||
return type_entry->data.unionation.complete;
|
||||
case ZigTypeIdOpaque:
|
||||
return false;
|
||||
case ZigTypeIdMetaType:
|
||||
case ZigTypeIdVoid:
|
||||
case ZigTypeIdBool:
|
||||
case ZigTypeIdUnreachable:
|
||||
case ZigTypeIdInt:
|
||||
case ZigTypeIdFloat:
|
||||
case ZigTypeIdPointer:
|
||||
case ZigTypeIdArray:
|
||||
case ZigTypeIdComptimeFloat:
|
||||
case ZigTypeIdComptimeInt:
|
||||
case ZigTypeIdUndefined:
|
||||
case ZigTypeIdNull:
|
||||
case ZigTypeIdOptional:
|
||||
case ZigTypeIdErrorUnion:
|
||||
case ZigTypeIdErrorSet:
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdPromise:
|
||||
return true;
|
||||
}
|
||||
zig_unreachable();
|
||||
return type_is_resolved(type_entry, ResolveStatusSizeKnown);
|
||||
}
|
||||
|
||||
bool type_has_zero_bits_known(ZigType *type_entry) {
|
||||
switch (type_entry->id) {
|
||||
case ZigTypeIdInvalid:
|
||||
zig_unreachable();
|
||||
case ZigTypeIdStruct:
|
||||
return type_entry->data.structure.zero_bits_known;
|
||||
case ZigTypeIdEnum:
|
||||
return type_entry->data.enumeration.zero_bits_known;
|
||||
case ZigTypeIdUnion:
|
||||
return type_entry->data.unionation.zero_bits_known;
|
||||
case ZigTypeIdMetaType:
|
||||
case ZigTypeIdVoid:
|
||||
case ZigTypeIdBool:
|
||||
case ZigTypeIdUnreachable:
|
||||
case ZigTypeIdInt:
|
||||
case ZigTypeIdFloat:
|
||||
case ZigTypeIdPointer:
|
||||
case ZigTypeIdArray:
|
||||
case ZigTypeIdComptimeFloat:
|
||||
case ZigTypeIdComptimeInt:
|
||||
case ZigTypeIdUndefined:
|
||||
case ZigTypeIdNull:
|
||||
case ZigTypeIdOptional:
|
||||
case ZigTypeIdErrorUnion:
|
||||
case ZigTypeIdErrorSet:
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdOpaque:
|
||||
case ZigTypeIdPromise:
|
||||
return true;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
|
||||
uint64_t type_size(CodeGen *g, ZigType *type_entry) {
|
||||
assert(type_is_complete(type_entry));
|
||||
|
||||
@@ -379,7 +368,7 @@ uint64_t type_size_bits(CodeGen *g, ZigType *type_entry) {
|
||||
|
||||
Result<bool> type_is_copyable(CodeGen *g, ZigType *type_entry) {
|
||||
Error err;
|
||||
if ((err = type_ensure_zero_bits_known(g, type_entry)))
|
||||
if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
|
||||
return err;
|
||||
|
||||
if (!type_has_bits(type_entry))
|
||||
@@ -434,10 +423,15 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
|
||||
assert(!type_is_invalid(child_type));
|
||||
assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque);
|
||||
|
||||
if (byte_alignment != 0) {
|
||||
uint32_t abi_alignment = get_abi_alignment(g, child_type);
|
||||
if (byte_alignment == abi_alignment)
|
||||
byte_alignment = 0;
|
||||
}
|
||||
|
||||
TypeId type_id = {};
|
||||
ZigType **parent_pointer = nullptr;
|
||||
uint32_t abi_alignment = get_abi_alignment(g, child_type);
|
||||
if (unaligned_bit_count != 0 || is_volatile || byte_alignment != abi_alignment || ptr_len != PtrLenSingle) {
|
||||
if (unaligned_bit_count != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle) {
|
||||
type_id.id = ZigTypeIdPointer;
|
||||
type_id.data.pointer.child_type = child_type;
|
||||
type_id.data.pointer.is_const = is_const;
|
||||
@@ -454,12 +448,12 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
|
||||
assert(bit_offset == 0);
|
||||
parent_pointer = &child_type->pointer_parent[(is_const ? 1 : 0)];
|
||||
if (*parent_pointer) {
|
||||
assert((*parent_pointer)->data.pointer.alignment == byte_alignment);
|
||||
assert((*parent_pointer)->data.pointer.explicit_alignment == 0);
|
||||
return *parent_pointer;
|
||||
}
|
||||
}
|
||||
|
||||
assertNoError(type_ensure_zero_bits_known(g, child_type));
|
||||
assert(type_is_resolved(child_type, ResolveStatusZeroBitsKnown));
|
||||
|
||||
ZigType *entry = new_type_table_entry(ZigTypeIdPointer);
|
||||
entry->is_copyable = true;
|
||||
@@ -468,11 +462,14 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
|
||||
const char *const_str = is_const ? "const " : "";
|
||||
const char *volatile_str = is_volatile ? "volatile " : "";
|
||||
buf_resize(&entry->name, 0);
|
||||
if (unaligned_bit_count == 0 && byte_alignment == abi_alignment) {
|
||||
if (unaligned_bit_count == 0 && byte_alignment == 0) {
|
||||
buf_appendf(&entry->name, "%s%s%s%s", star_str, const_str, volatile_str, buf_ptr(&child_type->name));
|
||||
} else if (unaligned_bit_count == 0) {
|
||||
buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s", star_str, byte_alignment,
|
||||
const_str, volatile_str, buf_ptr(&child_type->name));
|
||||
} else if (byte_alignment == 0) {
|
||||
buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str,
|
||||
bit_offset, bit_offset + unaligned_bit_count, const_str, volatile_str, buf_ptr(&child_type->name));
|
||||
} else {
|
||||
buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str, byte_alignment,
|
||||
bit_offset, bit_offset + unaligned_bit_count, const_str, volatile_str, buf_ptr(&child_type->name));
|
||||
@@ -483,8 +480,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
|
||||
entry->zero_bits = !type_has_bits(child_type);
|
||||
|
||||
if (!entry->zero_bits) {
|
||||
assert(byte_alignment > 0);
|
||||
if (is_const || is_volatile || unaligned_bit_count != 0 || byte_alignment != abi_alignment ||
|
||||
if (is_const || is_volatile || unaligned_bit_count != 0 || byte_alignment != 0 ||
|
||||
ptr_len != PtrLenSingle)
|
||||
{
|
||||
ZigType *peer_type = get_pointer_to_type(g, child_type, false);
|
||||
@@ -508,7 +504,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
|
||||
entry->data.pointer.child_type = child_type;
|
||||
entry->data.pointer.is_const = is_const;
|
||||
entry->data.pointer.is_volatile = is_volatile;
|
||||
entry->data.pointer.alignment = byte_alignment;
|
||||
entry->data.pointer.explicit_alignment = byte_alignment;
|
||||
entry->data.pointer.bit_offset = bit_offset;
|
||||
entry->data.pointer.unaligned_bit_count = unaligned_bit_count;
|
||||
|
||||
@@ -521,8 +517,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
|
||||
}
|
||||
|
||||
ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const) {
|
||||
return get_pointer_to_type_extra(g, child_type, is_const, false, PtrLenSingle,
|
||||
get_abi_alignment(g, child_type), 0, 0);
|
||||
return get_pointer_to_type_extra(g, child_type, is_const, false, PtrLenSingle, 0, 0, 0);
|
||||
}
|
||||
|
||||
ZigType *get_promise_frame_type(CodeGen *g, ZigType *return_type) {
|
||||
@@ -803,8 +798,7 @@ static void slice_type_common_init(CodeGen *g, ZigType *pointer_type, ZigType *e
|
||||
entry->data.structure.fields_by_name.put(ptr_field_name, &entry->data.structure.fields[slice_ptr_index]);
|
||||
entry->data.structure.fields_by_name.put(len_field_name, &entry->data.structure.fields[slice_len_index]);
|
||||
|
||||
assert(type_has_zero_bits_known(pointer_type->data.pointer.child_type));
|
||||
if (pointer_type->data.pointer.child_type->zero_bits) {
|
||||
if (!type_has_bits(pointer_type->data.pointer.child_type)) {
|
||||
entry->data.structure.gen_field_count = 1;
|
||||
entry->data.structure.fields[slice_ptr_index].gen_index = SIZE_MAX;
|
||||
entry->data.structure.fields[slice_len_index].gen_index = 0;
|
||||
@@ -829,20 +823,18 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
|
||||
buf_appendf(&entry->name, "[]%s", buf_ptr(&ptr_type->name) + name_offset);
|
||||
|
||||
ZigType *child_type = ptr_type->data.pointer.child_type;
|
||||
uint32_t abi_alignment = get_abi_alignment(g, child_type);
|
||||
if (ptr_type->data.pointer.is_const || ptr_type->data.pointer.is_volatile ||
|
||||
ptr_type->data.pointer.alignment != abi_alignment)
|
||||
ptr_type->data.pointer.explicit_alignment != 0)
|
||||
{
|
||||
ZigType *peer_ptr_type = get_pointer_to_type_extra(g, child_type, false, false,
|
||||
PtrLenUnknown, abi_alignment, 0, 0);
|
||||
PtrLenUnknown, 0, 0, 0);
|
||||
ZigType *peer_slice_type = get_slice_type(g, peer_ptr_type);
|
||||
|
||||
slice_type_common_init(g, ptr_type, entry);
|
||||
|
||||
entry->type_ref = peer_slice_type->type_ref;
|
||||
entry->di_type = peer_slice_type->di_type;
|
||||
entry->data.structure.complete = true;
|
||||
entry->data.structure.zero_bits_known = true;
|
||||
entry->data.structure.resolve_status = ResolveStatusSizeKnown;
|
||||
entry->data.structure.abi_alignment = peer_slice_type->data.structure.abi_alignment;
|
||||
|
||||
*parent_pointer = entry;
|
||||
@@ -854,15 +846,15 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
|
||||
if (is_slice(child_type)) {
|
||||
ZigType *child_ptr_type = child_type->data.structure.fields[slice_ptr_index].type_entry;
|
||||
assert(child_ptr_type->id == ZigTypeIdPointer);
|
||||
ZigType *grand_child_type = child_ptr_type->data.pointer.child_type;
|
||||
if (child_ptr_type->data.pointer.is_const || child_ptr_type->data.pointer.is_volatile ||
|
||||
child_ptr_type->data.pointer.alignment != get_abi_alignment(g, grand_child_type))
|
||||
child_ptr_type->data.pointer.explicit_alignment != 0)
|
||||
{
|
||||
ZigType *grand_child_type = child_ptr_type->data.pointer.child_type;
|
||||
ZigType *bland_child_ptr_type = get_pointer_to_type_extra(g, grand_child_type, false, false,
|
||||
PtrLenUnknown, get_abi_alignment(g, grand_child_type), 0, 0);
|
||||
PtrLenUnknown, 0, 0, 0);
|
||||
ZigType *bland_child_slice = get_slice_type(g, bland_child_ptr_type);
|
||||
ZigType *peer_ptr_type = get_pointer_to_type_extra(g, bland_child_slice, false, false,
|
||||
PtrLenUnknown, get_abi_alignment(g, bland_child_slice), 0, 0);
|
||||
PtrLenUnknown, 0, 0, 0);
|
||||
ZigType *peer_slice_type = get_slice_type(g, peer_ptr_type);
|
||||
|
||||
entry->type_ref = peer_slice_type->type_ref;
|
||||
@@ -964,8 +956,7 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
|
||||
}
|
||||
|
||||
|
||||
entry->data.structure.complete = true;
|
||||
entry->data.structure.zero_bits_known = true;
|
||||
entry->data.structure.resolve_status = ResolveStatusSizeKnown;
|
||||
|
||||
*parent_pointer = entry;
|
||||
return entry;
|
||||
@@ -1370,7 +1361,7 @@ static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_
|
||||
|
||||
static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf **out_buffer) {
|
||||
ZigType *ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
|
||||
PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
|
||||
PtrLenUnknown, 0, 0, 0);
|
||||
ZigType *str_type = get_slice_type(g, ptr_type);
|
||||
IrInstruction *instr = analyze_const_value(g, scope, node, str_type, nullptr);
|
||||
if (type_is_invalid(instr->value.type))
|
||||
@@ -1414,7 +1405,6 @@ static bool type_allowed_in_packed_struct(ZigType *type_entry) {
|
||||
case ZigTypeIdErrorUnion:
|
||||
case ZigTypeIdErrorSet:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdOpaque:
|
||||
@@ -1455,7 +1445,6 @@ static bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) {
|
||||
case ZigTypeIdErrorUnion:
|
||||
case ZigTypeIdErrorSet:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdPromise:
|
||||
@@ -1581,7 +1570,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
|
||||
if ((err = type_ensure_zero_bits_known(g, type_entry)))
|
||||
if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
|
||||
return g->builtin_types.entry_invalid;
|
||||
if (!type_has_bits(type_entry)) {
|
||||
add_node_error(g, param_node->data.param_decl.type,
|
||||
@@ -1613,7 +1602,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
|
||||
case ZigTypeIdComptimeFloat:
|
||||
case ZigTypeIdComptimeInt:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdMetaType:
|
||||
case ZigTypeIdVoid:
|
||||
@@ -1630,7 +1618,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
|
||||
case ZigTypeIdUnion:
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdPromise:
|
||||
if ((err = type_ensure_zero_bits_known(g, type_entry)))
|
||||
if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
|
||||
return g->builtin_types.entry_invalid;
|
||||
if (type_requires_comptime(type_entry)) {
|
||||
add_node_error(g, param_node->data.param_decl.type,
|
||||
@@ -1703,7 +1691,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
|
||||
case ZigTypeIdComptimeFloat:
|
||||
case ZigTypeIdComptimeInt:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdMetaType:
|
||||
case ZigTypeIdUnreachable:
|
||||
@@ -1721,7 +1708,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
|
||||
case ZigTypeIdUnion:
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdPromise:
|
||||
if ((err = type_ensure_zero_bits_known(g, fn_type_id.return_type)))
|
||||
if ((err = type_resolve(g, fn_type_id.return_type, ResolveStatusZeroBitsKnown)))
|
||||
return g->builtin_types.entry_invalid;
|
||||
if (type_requires_comptime(fn_type_id.return_type)) {
|
||||
return get_generic_fn_type(g, &fn_type_id);
|
||||
@@ -1747,7 +1734,7 @@ bool type_is_invalid(ZigType *type_entry) {
|
||||
case ZigTypeIdInvalid:
|
||||
return true;
|
||||
case ZigTypeIdStruct:
|
||||
return type_entry->data.structure.is_invalid;
|
||||
return type_entry->data.structure.resolve_status == ResolveStatusInvalid;
|
||||
case ZigTypeIdEnum:
|
||||
return type_entry->data.enumeration.is_invalid;
|
||||
case ZigTypeIdUnion:
|
||||
@@ -1862,8 +1849,7 @@ ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_na
|
||||
|
||||
struct_type->data.structure.src_field_count = field_count;
|
||||
struct_type->data.structure.gen_field_count = 0;
|
||||
struct_type->data.structure.zero_bits_known = true;
|
||||
struct_type->data.structure.complete = true;
|
||||
struct_type->data.structure.resolve_status = ResolveStatusSizeKnown;
|
||||
struct_type->data.structure.fields = allocate<TypeStructField>(field_count);
|
||||
struct_type->data.structure.fields_by_name.init(field_count);
|
||||
|
||||
@@ -1935,26 +1921,29 @@ ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_na
|
||||
static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
|
||||
assert(struct_type->id == ZigTypeIdStruct);
|
||||
|
||||
if (struct_type->data.structure.complete)
|
||||
Error err;
|
||||
|
||||
if (struct_type->data.structure.resolve_status == ResolveStatusInvalid)
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
if (struct_type->data.structure.resolve_status >= ResolveStatusSizeKnown)
|
||||
return ErrorNone;
|
||||
|
||||
Error err;
|
||||
if ((err = resolve_struct_zero_bits(g, struct_type)))
|
||||
if ((err = resolve_struct_alignment(g, struct_type)))
|
||||
return err;
|
||||
|
||||
AstNode *decl_node = struct_type->data.structure.decl_node;
|
||||
|
||||
if (struct_type->data.structure.embedded_in_current) {
|
||||
struct_type->data.structure.is_invalid = true;
|
||||
if (!struct_type->data.structure.reported_infinite_err) {
|
||||
struct_type->data.structure.reported_infinite_err = true;
|
||||
if (struct_type->data.structure.resolve_loop_flag) {
|
||||
if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) {
|
||||
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
|
||||
add_node_error(g, decl_node,
|
||||
buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name)));
|
||||
buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name)));
|
||||
}
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
|
||||
assert(!struct_type->data.structure.zero_bits_loop_flag);
|
||||
struct_type->data.structure.resolve_loop_flag = true;
|
||||
|
||||
assert(struct_type->data.structure.fields || struct_type->data.structure.src_field_count == 0);
|
||||
assert(decl_node->type == NodeTypeContainerDecl);
|
||||
|
||||
@@ -1963,9 +1952,6 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
|
||||
size_t gen_field_count = struct_type->data.structure.gen_field_count;
|
||||
LLVMTypeRef *element_types = allocate<LLVMTypeRef>(gen_field_count);
|
||||
|
||||
// this field should be set to true only during the recursive calls to resolve_struct_type
|
||||
struct_type->data.structure.embedded_in_current = true;
|
||||
|
||||
Scope *scope = &struct_type->data.structure.decls_scope->base;
|
||||
|
||||
size_t gen_field_index = 0;
|
||||
@@ -1979,7 +1965,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
|
||||
ZigType *field_type = type_struct_field->type_entry;
|
||||
|
||||
if ((err = ensure_complete_type(g, field_type))) {
|
||||
struct_type->data.structure.is_invalid = true;
|
||||
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1989,7 +1975,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
|
||||
add_node_error(g, field_source_node,
|
||||
buf_sprintf("extern structs cannot contain fields of type '%s'",
|
||||
buf_ptr(&field_type->name)));
|
||||
struct_type->data.structure.is_invalid = true;
|
||||
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2005,7 +1991,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
|
||||
add_node_error(g, field_source_node,
|
||||
buf_sprintf("packed structs cannot contain fields of type '%s'",
|
||||
buf_ptr(&field_type->name)));
|
||||
struct_type->data.structure.is_invalid = true;
|
||||
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2056,12 +2042,13 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
|
||||
gen_field_index += 1;
|
||||
}
|
||||
|
||||
struct_type->data.structure.embedded_in_current = false;
|
||||
struct_type->data.structure.complete = true;
|
||||
struct_type->data.structure.resolve_loop_flag = false;
|
||||
|
||||
if (struct_type->data.structure.is_invalid)
|
||||
if (struct_type->data.structure.resolve_status == ResolveStatusInvalid)
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
|
||||
struct_type->data.structure.resolve_status = ResolveStatusSizeKnown;
|
||||
|
||||
if (struct_type->zero_bits) {
|
||||
struct_type->type_ref = LLVMVoidType();
|
||||
|
||||
@@ -2123,7 +2110,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
|
||||
|
||||
assert(field_type->type_ref);
|
||||
assert(struct_type->type_ref);
|
||||
assert(struct_type->data.structure.complete);
|
||||
assert(struct_type->data.structure.resolve_status == ResolveStatusSizeKnown);
|
||||
uint64_t debug_size_in_bits;
|
||||
uint64_t debug_align_in_bits;
|
||||
uint64_t debug_offset_in_bits;
|
||||
@@ -2450,6 +2437,8 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
|
||||
ZigType *tag_int_type;
|
||||
if (enum_type->data.enumeration.layout == ContainerLayoutExtern) {
|
||||
tag_int_type = get_c_int_type(g, CIntTypeInt);
|
||||
} else if (enum_type->data.enumeration.layout == ContainerLayoutAuto && field_count == 1) {
|
||||
tag_int_type = g->builtin_types.entry_num_lit_int;
|
||||
} else {
|
||||
tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
|
||||
}
|
||||
@@ -2513,7 +2502,8 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
|
||||
continue;
|
||||
}
|
||||
assert(result_inst->value.special != ConstValSpecialRuntime);
|
||||
assert(result_inst->value.type->id == ZigTypeIdInt);
|
||||
assert(result_inst->value.type->id == ZigTypeIdInt ||
|
||||
result_inst->value.type->id == ZigTypeIdComptimeInt);
|
||||
auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value);
|
||||
if (entry == nullptr) {
|
||||
bigint_init_bigint(&type_enum_field->value, &result_inst->value.data.x_bigint);
|
||||
@@ -2574,30 +2564,18 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
|
||||
|
||||
Error err;
|
||||
|
||||
if (struct_type->data.structure.is_invalid)
|
||||
if (struct_type->data.structure.resolve_status == ResolveStatusInvalid)
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
|
||||
if (struct_type->data.structure.zero_bits_known)
|
||||
if (struct_type->data.structure.resolve_status >= ResolveStatusZeroBitsKnown)
|
||||
return ErrorNone;
|
||||
|
||||
if (struct_type->data.structure.zero_bits_loop_flag) {
|
||||
// If we get here it's due to recursion. This is a design flaw in the compiler,
|
||||
// we should be able to still figure out alignment, but here we give up and say that
|
||||
// the alignment is pointer width, then assert that the first field is within that
|
||||
// alignment
|
||||
struct_type->data.structure.zero_bits_known = true;
|
||||
struct_type->data.structure.zero_bits_loop_flag = false;
|
||||
if (struct_type->data.structure.abi_alignment == 0) {
|
||||
if (struct_type->data.structure.layout == ContainerLayoutPacked) {
|
||||
struct_type->data.structure.abi_alignment = 1;
|
||||
} else {
|
||||
struct_type->data.structure.abi_alignment = LLVMABIAlignmentOfType(g->target_data_ref, LLVMPointerType(LLVMInt8Type(), 0));
|
||||
}
|
||||
}
|
||||
if (struct_type->data.structure.resolve_loop_flag) {
|
||||
struct_type->data.structure.resolve_status = ResolveStatusZeroBitsKnown;
|
||||
struct_type->data.structure.resolve_loop_flag = false;
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
struct_type->data.structure.zero_bits_loop_flag = true;
|
||||
struct_type->data.structure.resolve_loop_flag = true;
|
||||
|
||||
AstNode *decl_node = struct_type->data.structure.decl_node;
|
||||
assert(decl_node->type == NodeTypeContainerDecl);
|
||||
@@ -2620,7 +2598,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
|
||||
|
||||
if (field_node->data.struct_field.type == nullptr) {
|
||||
add_node_error(g, field_node, buf_sprintf("struct field missing type"));
|
||||
struct_type->data.structure.is_invalid = true;
|
||||
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2629,7 +2607,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
|
||||
ErrorMsg *msg = add_node_error(g, field_node,
|
||||
buf_sprintf("duplicate struct field: '%s'", buf_ptr(type_struct_field->name)));
|
||||
add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here"));
|
||||
struct_type->data.structure.is_invalid = true;
|
||||
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2643,8 +2621,8 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
|
||||
buf_sprintf("enums, not structs, support field assignment"));
|
||||
}
|
||||
|
||||
if ((err = type_ensure_zero_bits_known(g, field_type))) {
|
||||
struct_type->data.structure.is_invalid = true;
|
||||
if ((err = type_resolve(g, field_type, ResolveStatusZeroBitsKnown))) {
|
||||
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2655,36 +2633,87 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
|
||||
if (!type_has_bits(field_type))
|
||||
continue;
|
||||
|
||||
if (gen_field_index == 0) {
|
||||
if (struct_type->data.structure.layout == ContainerLayoutPacked) {
|
||||
struct_type->data.structure.abi_alignment = 1;
|
||||
} else if (struct_type->data.structure.abi_alignment == 0) {
|
||||
// Alignment of structs is the alignment of the first field, for now.
|
||||
// TODO change this when we re-order struct fields (issue #168)
|
||||
struct_type->data.structure.abi_alignment = get_abi_alignment(g, field_type);
|
||||
assert(struct_type->data.structure.abi_alignment != 0);
|
||||
} else {
|
||||
// due to a design flaw in the compiler we assumed that alignment was
|
||||
// pointer width, so we assert that this wasn't violated.
|
||||
if (get_abi_alignment(g, field_type) > struct_type->data.structure.abi_alignment) {
|
||||
zig_panic("compiler design flaw: incorrect alignment assumption");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type_struct_field->gen_index = gen_field_index;
|
||||
gen_field_index += 1;
|
||||
}
|
||||
|
||||
struct_type->data.structure.zero_bits_loop_flag = false;
|
||||
struct_type->data.structure.resolve_loop_flag = false;
|
||||
struct_type->data.structure.gen_field_count = (uint32_t)gen_field_index;
|
||||
struct_type->zero_bits = (gen_field_index == 0);
|
||||
struct_type->data.structure.zero_bits_known = true;
|
||||
|
||||
if (struct_type->data.structure.is_invalid) {
|
||||
if (struct_type->data.structure.resolve_status == ResolveStatusInvalid)
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
|
||||
struct_type->data.structure.resolve_status = ResolveStatusZeroBitsKnown;
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {
|
||||
assert(struct_type->id == ZigTypeIdStruct);
|
||||
|
||||
Error err;
|
||||
|
||||
if (struct_type->data.structure.resolve_status == ResolveStatusInvalid)
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
if (struct_type->data.structure.resolve_status >= ResolveStatusAlignmentKnown)
|
||||
return ErrorNone;
|
||||
|
||||
if ((err = resolve_struct_zero_bits(g, struct_type)))
|
||||
return err;
|
||||
|
||||
AstNode *decl_node = struct_type->data.structure.decl_node;
|
||||
|
||||
if (struct_type->data.structure.resolve_loop_flag) {
|
||||
if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) {
|
||||
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
|
||||
add_node_error(g, decl_node,
|
||||
buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name)));
|
||||
}
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
|
||||
struct_type->data.structure.resolve_loop_flag = true;
|
||||
assert(decl_node->type == NodeTypeContainerDecl);
|
||||
assert(struct_type->di_type);
|
||||
|
||||
if (struct_type->data.structure.layout == ContainerLayoutPacked) {
|
||||
struct_type->data.structure.abi_alignment = 1;
|
||||
}
|
||||
|
||||
size_t field_count = struct_type->data.structure.src_field_count;
|
||||
for (size_t i = 0; i < field_count; i += 1) {
|
||||
TypeStructField *field = &struct_type->data.structure.fields[i];
|
||||
|
||||
// If this assertion trips, look up the call stack. Probably something is
|
||||
// calling type_resolve with ResolveStatusAlignmentKnown when it should only
|
||||
// be resolving ResolveStatusZeroBitsKnown
|
||||
assert(field->type_entry != nullptr);
|
||||
|
||||
if (!type_has_bits(field->type_entry))
|
||||
continue;
|
||||
|
||||
// alignment of structs is the alignment of the most-aligned field
|
||||
if (struct_type->data.structure.layout != ContainerLayoutPacked) {
|
||||
if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) {
|
||||
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t this_field_align = get_abi_alignment(g, field->type_entry);
|
||||
assert(this_field_align != 0);
|
||||
if (this_field_align > struct_type->data.structure.abi_alignment) {
|
||||
struct_type->data.structure.abi_alignment = this_field_align;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct_type->data.structure.resolve_loop_flag = false;
|
||||
|
||||
if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) {
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
|
||||
struct_type->data.structure.resolve_status = ResolveStatusAlignmentKnown;
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
@@ -2776,6 +2805,8 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
|
||||
union_type->data.unionation.is_invalid = true;
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
} else if (auto_layout && field_count == 1) {
|
||||
tag_int_type = g->builtin_types.entry_num_lit_int;
|
||||
} else {
|
||||
tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
|
||||
}
|
||||
@@ -2809,6 +2840,10 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
|
||||
buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name)));
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
if ((err = type_resolve(g, enum_type, ResolveStatusAlignmentKnown))) {
|
||||
assert(g->errors.length != 0);
|
||||
return err;
|
||||
}
|
||||
tag_type = enum_type;
|
||||
abi_alignment_so_far = get_abi_alignment(g, enum_type); // this populates src_field_count
|
||||
covered_enum_fields = allocate<bool>(enum_type->data.enumeration.src_field_count);
|
||||
@@ -2846,7 +2881,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
|
||||
}
|
||||
} else {
|
||||
field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
|
||||
if ((err = type_ensure_zero_bits_known(g, field_type))) {
|
||||
if ((err = type_resolve(g, field_type, ResolveStatusAlignmentKnown))) {
|
||||
union_type->data.unionation.is_invalid = true;
|
||||
continue;
|
||||
}
|
||||
@@ -3109,7 +3144,7 @@ static void typecheck_panic_fn(CodeGen *g, ZigFn *panic_fn) {
|
||||
return wrong_panic_prototype(g, proto_node, fn_type);
|
||||
}
|
||||
ZigType *const_u8_ptr = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
|
||||
PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
|
||||
PtrLenUnknown, 0, 0, 0);
|
||||
ZigType *const_u8_slice = get_slice_type(g, const_u8_ptr);
|
||||
if (fn_type_id->param_info[0].type != const_u8_slice) {
|
||||
return wrong_panic_prototype(g, proto_node, fn_type);
|
||||
@@ -3428,7 +3463,6 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
|
||||
case NodeTypeBoolLiteral:
|
||||
case NodeTypeNullLiteral:
|
||||
case NodeTypeUndefinedLiteral:
|
||||
case NodeTypeThisLiteral:
|
||||
case NodeTypeSymbol:
|
||||
case NodeTypePrefixOpExpr:
|
||||
case NodeTypePointerType:
|
||||
@@ -3488,7 +3522,6 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry
|
||||
case ZigTypeIdUnreachable:
|
||||
case ZigTypeIdUndefined:
|
||||
case ZigTypeIdNull:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdOpaque:
|
||||
add_node_error(g, source_node, buf_sprintf("variable of type '%s' not allowed",
|
||||
@@ -3789,34 +3822,6 @@ ZigFn *scope_fn_entry(Scope *scope) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ZigFn *scope_get_fn_if_root(Scope *scope) {
|
||||
assert(scope);
|
||||
scope = scope->parent;
|
||||
while (scope) {
|
||||
switch (scope->id) {
|
||||
case ScopeIdBlock:
|
||||
return nullptr;
|
||||
case ScopeIdDecls:
|
||||
case ScopeIdDefer:
|
||||
case ScopeIdDeferExpr:
|
||||
case ScopeIdVarDecl:
|
||||
case ScopeIdCImport:
|
||||
case ScopeIdLoop:
|
||||
case ScopeIdSuspend:
|
||||
case ScopeIdCompTime:
|
||||
case ScopeIdCoroPrelude:
|
||||
case ScopeIdRuntime:
|
||||
scope = scope->parent;
|
||||
continue;
|
||||
case ScopeIdFnDef:
|
||||
ScopeFnDef *fn_scope = (ScopeFnDef *)scope;
|
||||
return fn_scope->fn_entry;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TypeEnumField *find_enum_type_field(ZigType *enum_type, Buf *name) {
|
||||
assert(enum_type->id == ZigTypeIdEnum);
|
||||
if (enum_type->data.enumeration.src_field_count == 0)
|
||||
@@ -3829,7 +3834,7 @@ TypeEnumField *find_enum_type_field(ZigType *enum_type, Buf *name) {
|
||||
|
||||
TypeStructField *find_struct_type_field(ZigType *type_entry, Buf *name) {
|
||||
assert(type_entry->id == ZigTypeIdStruct);
|
||||
assert(type_entry->data.structure.complete);
|
||||
assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown));
|
||||
if (type_entry->data.structure.src_field_count == 0)
|
||||
return nullptr;
|
||||
auto entry = type_entry->data.structure.fields_by_name.maybe_get(name);
|
||||
@@ -3898,7 +3903,6 @@ static bool is_container(ZigType *type_entry) {
|
||||
case ZigTypeIdErrorSet:
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdOpaque:
|
||||
@@ -3957,7 +3961,6 @@ void resolve_container_type(CodeGen *g, ZigType *type_entry) {
|
||||
case ZigTypeIdErrorSet:
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdInvalid:
|
||||
case ZigTypeIdArgTuple:
|
||||
@@ -3983,14 +3986,17 @@ bool type_is_codegen_pointer(ZigType *type) {
|
||||
return get_codegen_ptr_type(type) == type;
|
||||
}
|
||||
|
||||
uint32_t get_ptr_align(ZigType *type) {
|
||||
uint32_t get_ptr_align(CodeGen *g, ZigType *type) {
|
||||
ZigType *ptr_type = get_codegen_ptr_type(type);
|
||||
if (ptr_type->id == ZigTypeIdPointer) {
|
||||
return ptr_type->data.pointer.alignment;
|
||||
return (ptr_type->data.pointer.explicit_alignment == 0) ?
|
||||
get_abi_alignment(g, ptr_type->data.pointer.child_type) : ptr_type->data.pointer.explicit_alignment;
|
||||
} else if (ptr_type->id == ZigTypeIdFn) {
|
||||
return (ptr_type->data.fn.fn_type_id.alignment == 0) ? 1 : ptr_type->data.fn.fn_type_id.alignment;
|
||||
return (ptr_type->data.fn.fn_type_id.alignment == 0) ?
|
||||
LLVMABIAlignmentOfType(g->target_data_ref, ptr_type->data.fn.raw_type_ref) :
|
||||
ptr_type->data.fn.fn_type_id.alignment;
|
||||
} else if (ptr_type->id == ZigTypeIdPromise) {
|
||||
return 1;
|
||||
return get_coro_frame_align_bytes(g);
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
@@ -4060,6 +4066,7 @@ static void define_local_param_variables(CodeGen *g, ZigFn *fn_table_entry) {
|
||||
}
|
||||
|
||||
bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *source_node) {
|
||||
assert(err_set_type->id == ZigTypeIdErrorSet);
|
||||
ZigFn *infer_fn = err_set_type->data.error_set.infer_fn;
|
||||
if (infer_fn != nullptr) {
|
||||
if (infer_fn->anal_state == FnAnalStateInvalid) {
|
||||
@@ -4417,7 +4424,6 @@ bool handle_is_ptr(ZigType *type_entry) {
|
||||
case ZigTypeIdUndefined:
|
||||
case ZigTypeIdNull:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdOpaque:
|
||||
@@ -4832,8 +4838,6 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
|
||||
return const_val->data.x_err_set->value ^ 2630160122;
|
||||
case ZigTypeIdNamespace:
|
||||
return hash_ptr(const_val->data.x_import);
|
||||
case ZigTypeIdBlock:
|
||||
return hash_ptr(const_val->data.x_block);
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdInvalid:
|
||||
case ZigTypeIdUnreachable:
|
||||
@@ -4894,7 +4898,6 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) {
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdOpaque:
|
||||
case ZigTypeIdPromise:
|
||||
case ZigTypeIdErrorSet:
|
||||
@@ -4961,7 +4964,6 @@ static bool return_type_is_cacheable(ZigType *return_type) {
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdOpaque:
|
||||
case ZigTypeIdPromise:
|
||||
case ZigTypeIdErrorSet:
|
||||
@@ -5057,8 +5059,8 @@ bool fn_eval_eql(Scope *a, Scope *b) {
|
||||
|
||||
bool type_has_bits(ZigType *type_entry) {
|
||||
assert(type_entry);
|
||||
assert(type_entry->id != ZigTypeIdInvalid);
|
||||
assert(type_has_zero_bits_known(type_entry));
|
||||
assert(!type_is_invalid(type_entry));
|
||||
assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown));
|
||||
return !type_entry->zero_bits;
|
||||
}
|
||||
|
||||
@@ -5073,17 +5075,16 @@ bool type_requires_comptime(ZigType *type_entry) {
|
||||
case ZigTypeIdNull:
|
||||
case ZigTypeIdMetaType:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
return true;
|
||||
case ZigTypeIdArray:
|
||||
return type_requires_comptime(type_entry->data.array.child_type);
|
||||
case ZigTypeIdStruct:
|
||||
assert(type_has_zero_bits_known(type_entry));
|
||||
assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown));
|
||||
return type_entry->data.structure.requires_comptime;
|
||||
case ZigTypeIdUnion:
|
||||
assert(type_has_zero_bits_known(type_entry));
|
||||
assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown));
|
||||
return type_entry->data.unionation.requires_comptime;
|
||||
case ZigTypeIdOptional:
|
||||
return type_requires_comptime(type_entry->data.maybe.child_type);
|
||||
@@ -5159,7 +5160,7 @@ void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
|
||||
const_val->special = ConstValSpecialStatic;
|
||||
// TODO make this `[*]null u8` instead of `[*]u8`
|
||||
const_val->type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
|
||||
PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
|
||||
PtrLenUnknown, 0, 0, 0);
|
||||
const_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
|
||||
const_val->data.x_ptr.data.base_array.array_val = array_val;
|
||||
const_val->data.x_ptr.data.base_array.elem_index = 0;
|
||||
@@ -5304,8 +5305,7 @@ void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *arr
|
||||
assert(array_val->type->id == ZigTypeIdArray);
|
||||
|
||||
ZigType *ptr_type = get_pointer_to_type_extra(g, array_val->type->data.array.child_type,
|
||||
is_const, false, PtrLenUnknown, get_abi_alignment(g, array_val->type->data.array.child_type),
|
||||
0, 0);
|
||||
is_const, false, PtrLenUnknown, 0, 0, 0);
|
||||
|
||||
const_val->special = ConstValSpecialStatic;
|
||||
const_val->type = get_slice_type(g, ptr_type);
|
||||
@@ -5330,7 +5330,7 @@ void init_const_ptr_array(CodeGen *g, ConstExprValue *const_val, ConstExprValue
|
||||
|
||||
const_val->special = ConstValSpecialStatic;
|
||||
const_val->type = get_pointer_to_type_extra(g, child_type, is_const, false,
|
||||
ptr_len, get_abi_alignment(g, child_type), 0, 0);
|
||||
ptr_len, 0, 0, 0);
|
||||
const_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
|
||||
const_val->data.x_ptr.data.base_array.array_val = array_val;
|
||||
const_val->data.x_ptr.data.base_array.elem_index = elem_index;
|
||||
@@ -5429,32 +5429,46 @@ ConstExprValue *create_const_vals(size_t count) {
|
||||
}
|
||||
|
||||
Error ensure_complete_type(CodeGen *g, ZigType *type_entry) {
|
||||
if (type_is_invalid(type_entry))
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
if (type_entry->id == ZigTypeIdStruct) {
|
||||
if (!type_entry->data.structure.complete)
|
||||
return resolve_struct_type(g, type_entry);
|
||||
} else if (type_entry->id == ZigTypeIdEnum) {
|
||||
if (!type_entry->data.enumeration.complete)
|
||||
return resolve_enum_type(g, type_entry);
|
||||
} else if (type_entry->id == ZigTypeIdUnion) {
|
||||
if (!type_entry->data.unionation.complete)
|
||||
return resolve_union_type(g, type_entry);
|
||||
}
|
||||
return ErrorNone;
|
||||
return type_resolve(g, type_entry, ResolveStatusSizeKnown);
|
||||
}
|
||||
|
||||
Error type_ensure_zero_bits_known(CodeGen *g, ZigType *type_entry) {
|
||||
if (type_is_invalid(type_entry))
|
||||
Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {
|
||||
if (type_is_invalid(ty))
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
if (type_entry->id == ZigTypeIdStruct) {
|
||||
return resolve_struct_zero_bits(g, type_entry);
|
||||
} else if (type_entry->id == ZigTypeIdEnum) {
|
||||
return resolve_enum_zero_bits(g, type_entry);
|
||||
} else if (type_entry->id == ZigTypeIdUnion) {
|
||||
return resolve_union_zero_bits(g, type_entry);
|
||||
switch (status) {
|
||||
case ResolveStatusUnstarted:
|
||||
return ErrorNone;
|
||||
case ResolveStatusInvalid:
|
||||
zig_unreachable();
|
||||
case ResolveStatusZeroBitsKnown:
|
||||
if (ty->id == ZigTypeIdStruct) {
|
||||
return resolve_struct_zero_bits(g, ty);
|
||||
} else if (ty->id == ZigTypeIdEnum) {
|
||||
return resolve_enum_zero_bits(g, ty);
|
||||
} else if (ty->id == ZigTypeIdUnion) {
|
||||
return resolve_union_zero_bits(g, ty);
|
||||
}
|
||||
return ErrorNone;
|
||||
case ResolveStatusAlignmentKnown:
|
||||
if (ty->id == ZigTypeIdStruct) {
|
||||
return resolve_struct_alignment(g, ty);
|
||||
} else if (ty->id == ZigTypeIdEnum) {
|
||||
return resolve_enum_zero_bits(g, ty);
|
||||
} else if (ty->id == ZigTypeIdUnion) {
|
||||
return resolve_union_zero_bits(g, ty);
|
||||
}
|
||||
return ErrorNone;
|
||||
case ResolveStatusSizeKnown:
|
||||
if (ty->id == ZigTypeIdStruct) {
|
||||
return resolve_struct_type(g, ty);
|
||||
} else if (ty->id == ZigTypeIdEnum) {
|
||||
return resolve_enum_type(g, ty);
|
||||
} else if (ty->id == ZigTypeIdUnion) {
|
||||
return resolve_union_type(g, ty);
|
||||
}
|
||||
return ErrorNone;
|
||||
}
|
||||
return ErrorNone;
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
bool ir_get_var_is_comptime(ZigVar *var) {
|
||||
@@ -5605,8 +5619,6 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
|
||||
zig_panic("TODO");
|
||||
case ZigTypeIdNamespace:
|
||||
return a->data.x_import == b->data.x_import;
|
||||
case ZigTypeIdBlock:
|
||||
return a->data.x_block == b->data.x_block;
|
||||
case ZigTypeIdArgTuple:
|
||||
return a->data.x_arg_tuple.start_index == b->data.x_arg_tuple.start_index &&
|
||||
a->data.x_arg_tuple.end_index == b->data.x_arg_tuple.end_index;
|
||||
@@ -5785,12 +5797,6 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
|
||||
}
|
||||
case ZigTypeIdPointer:
|
||||
return render_const_val_ptr(g, buf, const_val, type_entry);
|
||||
case ZigTypeIdBlock:
|
||||
{
|
||||
AstNode *node = const_val->data.x_block->source_node;
|
||||
buf_appendf(buf, "(scope:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ")", node->line + 1, node->column + 1);
|
||||
return;
|
||||
}
|
||||
case ZigTypeIdArray:
|
||||
{
|
||||
ZigType *child_type = type_entry->data.array.child_type;
|
||||
@@ -5882,12 +5888,23 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
|
||||
}
|
||||
case ZigTypeIdErrorUnion:
|
||||
{
|
||||
buf_appendf(buf, "(error union %s constant)", buf_ptr(&type_entry->name));
|
||||
buf_appendf(buf, "%s(", buf_ptr(&type_entry->name));
|
||||
if (const_val->data.x_err_union.err == nullptr) {
|
||||
render_const_value(g, buf, const_val->data.x_err_union.payload);
|
||||
} else {
|
||||
buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->data.error_union.err_set_type->name),
|
||||
buf_ptr(&const_val->data.x_err_union.err->name));
|
||||
}
|
||||
buf_appendf(buf, ")");
|
||||
return;
|
||||
}
|
||||
case ZigTypeIdUnion:
|
||||
{
|
||||
buf_appendf(buf, "(union %s constant)", buf_ptr(&type_entry->name));
|
||||
uint64_t tag = bigint_as_unsigned(&const_val->data.x_union.tag);
|
||||
TypeUnionField *field = &type_entry->data.unionation.fields[tag];
|
||||
buf_appendf(buf, "%s { .%s = ", buf_ptr(&type_entry->name), buf_ptr(field->name));
|
||||
render_const_value(g, buf, const_val->data.x_union.payload);
|
||||
buf_append_str(buf, "}");
|
||||
return;
|
||||
}
|
||||
case ZigTypeIdErrorSet:
|
||||
@@ -5959,7 +5976,6 @@ uint32_t type_id_hash(TypeId x) {
|
||||
case ZigTypeIdUnion:
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdPromise:
|
||||
@@ -6006,7 +6022,6 @@ bool type_id_eql(TypeId a, TypeId b) {
|
||||
case ZigTypeIdUnion:
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdOpaque:
|
||||
@@ -6132,7 +6147,6 @@ static const ZigTypeId all_type_ids[] = {
|
||||
ZigTypeIdUnion,
|
||||
ZigTypeIdFn,
|
||||
ZigTypeIdNamespace,
|
||||
ZigTypeIdBlock,
|
||||
ZigTypeIdBoundFn,
|
||||
ZigTypeIdArgTuple,
|
||||
ZigTypeIdOpaque,
|
||||
@@ -6194,16 +6208,14 @@ size_t type_id_index(ZigType *entry) {
|
||||
return 18;
|
||||
case ZigTypeIdNamespace:
|
||||
return 19;
|
||||
case ZigTypeIdBlock:
|
||||
return 20;
|
||||
case ZigTypeIdBoundFn:
|
||||
return 21;
|
||||
return 20;
|
||||
case ZigTypeIdArgTuple:
|
||||
return 22;
|
||||
return 21;
|
||||
case ZigTypeIdOpaque:
|
||||
return 23;
|
||||
return 22;
|
||||
case ZigTypeIdPromise:
|
||||
return 24;
|
||||
return 23;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@@ -6252,8 +6264,6 @@ const char *type_id_name(ZigTypeId id) {
|
||||
return "Fn";
|
||||
case ZigTypeIdNamespace:
|
||||
return "Namespace";
|
||||
case ZigTypeIdBlock:
|
||||
return "Block";
|
||||
case ZigTypeIdBoundFn:
|
||||
return "BoundFn";
|
||||
case ZigTypeIdArgTuple:
|
||||
@@ -6278,6 +6288,12 @@ LinkLib *add_link_lib(CodeGen *g, Buf *name) {
|
||||
if (is_libc && g->libc_link_lib != nullptr)
|
||||
return g->libc_link_lib;
|
||||
|
||||
if (g->enable_cache && is_libc && g->zig_target.os != OsMacOSX && g->zig_target.os != OsIOS) {
|
||||
fprintf(stderr, "TODO linking against libc is currently incompatible with `--cache on`.\n"
|
||||
"Zig is not yet capable of determining whether the libc installation has changed on subsequent builds.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < g->link_libs_list.length; i += 1) {
|
||||
LinkLib *existing_lib = g->link_libs_list.at(i);
|
||||
if (buf_eql_buf(existing_lib->name, name)) {
|
||||
@@ -6295,7 +6311,7 @@ LinkLib *add_link_lib(CodeGen *g, Buf *name) {
|
||||
}
|
||||
|
||||
uint32_t get_abi_alignment(CodeGen *g, ZigType *type_entry) {
|
||||
assertNoError(type_ensure_zero_bits_known(g, type_entry));
|
||||
assert(type_is_resolved(type_entry, ResolveStatusAlignmentKnown));
|
||||
if (type_entry->zero_bits) return 0;
|
||||
|
||||
// We need to make this function work without requiring ensure_complete_type
|
||||
@@ -6310,10 +6326,6 @@ uint32_t get_abi_alignment(CodeGen *g, ZigType *type_entry) {
|
||||
return 1;
|
||||
} else {
|
||||
uint32_t llvm_alignment = LLVMABIAlignmentOfType(g->target_data_ref, type_entry->type_ref);
|
||||
// promises have at least alignment 8 so that we can have 3 extra bits when doing atomicrmw
|
||||
if (type_entry->id == ZigTypeIdPromise && llvm_alignment < 8) {
|
||||
return 8;
|
||||
}
|
||||
return llvm_alignment;
|
||||
}
|
||||
}
|
||||
@@ -6351,7 +6363,10 @@ bool type_is_global_error_set(ZigType *err_set_type) {
|
||||
}
|
||||
|
||||
uint32_t get_coro_frame_align_bytes(CodeGen *g) {
|
||||
return g->pointer_size_bytes * 2;
|
||||
uint32_t a = g->pointer_size_bytes * 2;
|
||||
// promises have at least alignment 8 so that we can have 3 extra bits when doing atomicrmw
|
||||
if (a < 8) a = 8;
|
||||
return a;
|
||||
}
|
||||
|
||||
bool type_can_fail(ZigType *type_entry) {
|
||||
@@ -6387,6 +6402,14 @@ not_integer:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Error file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents) {
|
||||
if (g->enable_cache) {
|
||||
return cache_add_file_fetch(&g->cache_hash, resolved_path, contents);
|
||||
} else {
|
||||
return os_fetch_file_path(resolved_path, contents, false);
|
||||
}
|
||||
}
|
||||
|
||||
X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty) {
|
||||
size_t ty_size = type_size(g, ty);
|
||||
if (get_codegen_ptr_type(ty) != nullptr)
|
||||
@@ -6467,4 +6490,3 @@ bool type_is_c_abi_int(CodeGen *g, ZigType *ty) {
|
||||
ty->id == ZigTypeIdUnreachable ||
|
||||
get_codegen_ptr_type(ty) != nullptr);
|
||||
}
|
||||
|
||||
|
||||
+5
-4
@@ -54,14 +54,14 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *so
|
||||
bool type_is_codegen_pointer(ZigType *type);
|
||||
|
||||
ZigType *get_codegen_ptr_type(ZigType *type);
|
||||
uint32_t get_ptr_align(ZigType *type);
|
||||
uint32_t get_ptr_align(CodeGen *g, ZigType *type);
|
||||
bool get_ptr_const(ZigType *type);
|
||||
ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry);
|
||||
ZigType *container_ref_type(ZigType *type_entry);
|
||||
bool type_is_complete(ZigType *type_entry);
|
||||
bool type_is_resolved(ZigType *type_entry, ResolveStatus status);
|
||||
bool type_is_invalid(ZigType *type_entry);
|
||||
bool type_is_global_error_set(ZigType *err_set_type);
|
||||
bool type_has_zero_bits_known(ZigType *type_entry);
|
||||
void resolve_container_type(CodeGen *g, ZigType *type_entry);
|
||||
ScopeDecls *get_container_scope(ZigType *type_entry);
|
||||
TypeStructField *find_struct_type_field(ZigType *type_entry, Buf *name);
|
||||
@@ -87,10 +87,9 @@ ZigFn *create_fn(AstNode *proto_node);
|
||||
ZigFn *create_fn_raw(FnInline inline_value, GlobalLinkageId linkage);
|
||||
void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_count_alloc);
|
||||
AstNode *get_param_decl_node(ZigFn *fn_entry, size_t index);
|
||||
ZigFn *scope_get_fn_if_root(Scope *scope);
|
||||
bool type_requires_comptime(ZigType *type_entry);
|
||||
Error ATTRIBUTE_MUST_USE ensure_complete_type(CodeGen *g, ZigType *type_entry);
|
||||
Error ATTRIBUTE_MUST_USE type_ensure_zero_bits_known(CodeGen *g, ZigType *type_entry);
|
||||
Error ATTRIBUTE_MUST_USE type_resolve(CodeGen *g, ZigType *type_entry, ResolveStatus status);
|
||||
void complete_enum(CodeGen *g, ZigType *enum_type);
|
||||
bool ir_get_var_is_comptime(ZigVar *var);
|
||||
bool const_values_equal(ConstExprValue *a, ConstExprValue *b);
|
||||
@@ -209,6 +208,8 @@ ZigType *get_primitive_type(CodeGen *g, Buf *name);
|
||||
bool calling_convention_allows_zig_types(CallingConvention cc);
|
||||
const char *calling_convention_name(CallingConvention cc);
|
||||
|
||||
Error ATTRIBUTE_MUST_USE file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents);
|
||||
|
||||
void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk);
|
||||
X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty);
|
||||
bool type_is_c_abi_int(CodeGen *g, ZigType *ty);
|
||||
|
||||
@@ -193,8 +193,6 @@ static const char *node_type_str(NodeType node_type) {
|
||||
return "NullLiteral";
|
||||
case NodeTypeUndefinedLiteral:
|
||||
return "UndefinedLiteral";
|
||||
case NodeTypeThisLiteral:
|
||||
return "ThisLiteral";
|
||||
case NodeTypeIfBoolExpr:
|
||||
return "IfBoolExpr";
|
||||
case NodeTypeWhileExpr:
|
||||
@@ -897,11 +895,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NodeTypeThisLiteral:
|
||||
{
|
||||
fprintf(ar->f, "this");
|
||||
break;
|
||||
}
|
||||
case NodeTypeBoolLiteral:
|
||||
{
|
||||
const char *bool_str = node->data.bool_literal.value ? "true" : "false";
|
||||
|
||||
+196
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
BLAKE2 reference source code package - reference C implementations
|
||||
|
||||
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
|
||||
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
|
||||
your option. The terms of these licenses can be found at:
|
||||
|
||||
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
- OpenSSL license : https://www.openssl.org/source/license.html
|
||||
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
More information about the BLAKE2 hash function can be found at
|
||||
https://blake2.net.
|
||||
*/
|
||||
#ifndef BLAKE2_H
|
||||
#define BLAKE2_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define BLAKE2_PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop))
|
||||
#else
|
||||
#define BLAKE2_PACKED(x) x __attribute__((packed))
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum blake2s_constant
|
||||
{
|
||||
BLAKE2S_BLOCKBYTES = 64,
|
||||
BLAKE2S_OUTBYTES = 32,
|
||||
BLAKE2S_KEYBYTES = 32,
|
||||
BLAKE2S_SALTBYTES = 8,
|
||||
BLAKE2S_PERSONALBYTES = 8
|
||||
};
|
||||
|
||||
enum blake2b_constant
|
||||
{
|
||||
BLAKE2B_BLOCKBYTES = 128,
|
||||
BLAKE2B_OUTBYTES = 64,
|
||||
BLAKE2B_KEYBYTES = 64,
|
||||
BLAKE2B_SALTBYTES = 16,
|
||||
BLAKE2B_PERSONALBYTES = 16
|
||||
};
|
||||
|
||||
typedef struct blake2s_state__
|
||||
{
|
||||
uint32_t h[8];
|
||||
uint32_t t[2];
|
||||
uint32_t f[2];
|
||||
uint8_t buf[BLAKE2S_BLOCKBYTES];
|
||||
size_t buflen;
|
||||
size_t outlen;
|
||||
uint8_t last_node;
|
||||
} blake2s_state;
|
||||
|
||||
typedef struct blake2b_state__
|
||||
{
|
||||
uint64_t h[8];
|
||||
uint64_t t[2];
|
||||
uint64_t f[2];
|
||||
uint8_t buf[BLAKE2B_BLOCKBYTES];
|
||||
size_t buflen;
|
||||
size_t outlen;
|
||||
uint8_t last_node;
|
||||
} blake2b_state;
|
||||
|
||||
typedef struct blake2sp_state__
|
||||
{
|
||||
blake2s_state S[8][1];
|
||||
blake2s_state R[1];
|
||||
uint8_t buf[8 * BLAKE2S_BLOCKBYTES];
|
||||
size_t buflen;
|
||||
size_t outlen;
|
||||
} blake2sp_state;
|
||||
|
||||
typedef struct blake2bp_state__
|
||||
{
|
||||
blake2b_state S[4][1];
|
||||
blake2b_state R[1];
|
||||
uint8_t buf[4 * BLAKE2B_BLOCKBYTES];
|
||||
size_t buflen;
|
||||
size_t outlen;
|
||||
} blake2bp_state;
|
||||
|
||||
|
||||
BLAKE2_PACKED(struct blake2s_param__
|
||||
{
|
||||
uint8_t digest_length; /* 1 */
|
||||
uint8_t key_length; /* 2 */
|
||||
uint8_t fanout; /* 3 */
|
||||
uint8_t depth; /* 4 */
|
||||
uint32_t leaf_length; /* 8 */
|
||||
uint32_t node_offset; /* 12 */
|
||||
uint16_t xof_length; /* 14 */
|
||||
uint8_t node_depth; /* 15 */
|
||||
uint8_t inner_length; /* 16 */
|
||||
/* uint8_t reserved[0]; */
|
||||
uint8_t salt[BLAKE2S_SALTBYTES]; /* 24 */
|
||||
uint8_t personal[BLAKE2S_PERSONALBYTES]; /* 32 */
|
||||
});
|
||||
|
||||
typedef struct blake2s_param__ blake2s_param;
|
||||
|
||||
BLAKE2_PACKED(struct blake2b_param__
|
||||
{
|
||||
uint8_t digest_length; /* 1 */
|
||||
uint8_t key_length; /* 2 */
|
||||
uint8_t fanout; /* 3 */
|
||||
uint8_t depth; /* 4 */
|
||||
uint32_t leaf_length; /* 8 */
|
||||
uint32_t node_offset; /* 12 */
|
||||
uint32_t xof_length; /* 16 */
|
||||
uint8_t node_depth; /* 17 */
|
||||
uint8_t inner_length; /* 18 */
|
||||
uint8_t reserved[14]; /* 32 */
|
||||
uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */
|
||||
uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */
|
||||
});
|
||||
|
||||
typedef struct blake2b_param__ blake2b_param;
|
||||
|
||||
typedef struct blake2xs_state__
|
||||
{
|
||||
blake2s_state S[1];
|
||||
blake2s_param P[1];
|
||||
} blake2xs_state;
|
||||
|
||||
typedef struct blake2xb_state__
|
||||
{
|
||||
blake2b_state S[1];
|
||||
blake2b_param P[1];
|
||||
} blake2xb_state;
|
||||
|
||||
/* Padded structs result in a compile-time error */
|
||||
enum {
|
||||
BLAKE2_DUMMY_1 = 1/(sizeof(blake2s_param) == BLAKE2S_OUTBYTES),
|
||||
BLAKE2_DUMMY_2 = 1/(sizeof(blake2b_param) == BLAKE2B_OUTBYTES)
|
||||
};
|
||||
|
||||
/* Streaming API */
|
||||
int blake2s_init( blake2s_state *S, size_t outlen );
|
||||
int blake2s_init_key( blake2s_state *S, size_t outlen, const void *key, size_t keylen );
|
||||
int blake2s_init_param( blake2s_state *S, const blake2s_param *P );
|
||||
int blake2s_update( blake2s_state *S, const void *in, size_t inlen );
|
||||
int blake2s_final( blake2s_state *S, void *out, size_t outlen );
|
||||
|
||||
int blake2b_init( blake2b_state *S, size_t outlen );
|
||||
int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen );
|
||||
int blake2b_init_param( blake2b_state *S, const blake2b_param *P );
|
||||
int blake2b_update( blake2b_state *S, const void *in, size_t inlen );
|
||||
int blake2b_final( blake2b_state *S, void *out, size_t outlen );
|
||||
|
||||
int blake2sp_init( blake2sp_state *S, size_t outlen );
|
||||
int blake2sp_init_key( blake2sp_state *S, size_t outlen, const void *key, size_t keylen );
|
||||
int blake2sp_update( blake2sp_state *S, const void *in, size_t inlen );
|
||||
int blake2sp_final( blake2sp_state *S, void *out, size_t outlen );
|
||||
|
||||
int blake2bp_init( blake2bp_state *S, size_t outlen );
|
||||
int blake2bp_init_key( blake2bp_state *S, size_t outlen, const void *key, size_t keylen );
|
||||
int blake2bp_update( blake2bp_state *S, const void *in, size_t inlen );
|
||||
int blake2bp_final( blake2bp_state *S, void *out, size_t outlen );
|
||||
|
||||
/* Variable output length API */
|
||||
int blake2xs_init( blake2xs_state *S, const size_t outlen );
|
||||
int blake2xs_init_key( blake2xs_state *S, const size_t outlen, const void *key, size_t keylen );
|
||||
int blake2xs_update( blake2xs_state *S, const void *in, size_t inlen );
|
||||
int blake2xs_final(blake2xs_state *S, void *out, size_t outlen);
|
||||
|
||||
int blake2xb_init( blake2xb_state *S, const size_t outlen );
|
||||
int blake2xb_init_key( blake2xb_state *S, const size_t outlen, const void *key, size_t keylen );
|
||||
int blake2xb_update( blake2xb_state *S, const void *in, size_t inlen );
|
||||
int blake2xb_final(blake2xb_state *S, void *out, size_t outlen);
|
||||
|
||||
/* Simple API */
|
||||
int blake2s( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
|
||||
int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
|
||||
|
||||
int blake2sp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
|
||||
int blake2bp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
|
||||
|
||||
int blake2xs( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
|
||||
int blake2xb( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
|
||||
|
||||
/* This is simply an alias for blake2b */
|
||||
int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
+539
@@ -0,0 +1,539 @@
|
||||
/*
|
||||
BLAKE2 reference source code package - reference C implementations
|
||||
|
||||
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
|
||||
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
|
||||
your option. The terms of these licenses can be found at:
|
||||
|
||||
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
- OpenSSL license : https://www.openssl.org/source/license.html
|
||||
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
More information about the BLAKE2 hash function can be found at
|
||||
https://blake2.net.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "blake2.h"
|
||||
/*
|
||||
BLAKE2 reference source code package - reference C implementations
|
||||
|
||||
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
|
||||
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
|
||||
your option. The terms of these licenses can be found at:
|
||||
|
||||
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
|
||||
- OpenSSL license : https://www.openssl.org/source/license.html
|
||||
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
More information about the BLAKE2 hash function can be found at
|
||||
https://blake2.net.
|
||||
*/
|
||||
#ifndef BLAKE2_IMPL_H
|
||||
#define BLAKE2_IMPL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#if !defined(__cplusplus) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L)
|
||||
#if defined(_MSC_VER)
|
||||
#define BLAKE2_INLINE __inline
|
||||
#elif defined(__GNUC__)
|
||||
#define BLAKE2_INLINE __inline__
|
||||
#else
|
||||
#define BLAKE2_INLINE
|
||||
#endif
|
||||
#else
|
||||
#define BLAKE2_INLINE inline
|
||||
#endif
|
||||
|
||||
static BLAKE2_INLINE uint32_t load32( const void *src )
|
||||
{
|
||||
#if defined(NATIVE_LITTLE_ENDIAN)
|
||||
uint32_t w;
|
||||
memcpy(&w, src, sizeof w);
|
||||
return w;
|
||||
#else
|
||||
const uint8_t *p = ( const uint8_t * )src;
|
||||
return (( uint32_t )( p[0] ) << 0) |
|
||||
(( uint32_t )( p[1] ) << 8) |
|
||||
(( uint32_t )( p[2] ) << 16) |
|
||||
(( uint32_t )( p[3] ) << 24) ;
|
||||
#endif
|
||||
}
|
||||
|
||||
static BLAKE2_INLINE uint64_t load64( const void *src )
|
||||
{
|
||||
#if defined(NATIVE_LITTLE_ENDIAN)
|
||||
uint64_t w;
|
||||
memcpy(&w, src, sizeof w);
|
||||
return w;
|
||||
#else
|
||||
const uint8_t *p = ( const uint8_t * )src;
|
||||
return (( uint64_t )( p[0] ) << 0) |
|
||||
(( uint64_t )( p[1] ) << 8) |
|
||||
(( uint64_t )( p[2] ) << 16) |
|
||||
(( uint64_t )( p[3] ) << 24) |
|
||||
(( uint64_t )( p[4] ) << 32) |
|
||||
(( uint64_t )( p[5] ) << 40) |
|
||||
(( uint64_t )( p[6] ) << 48) |
|
||||
(( uint64_t )( p[7] ) << 56) ;
|
||||
#endif
|
||||
}
|
||||
|
||||
static BLAKE2_INLINE uint16_t load16( const void *src )
|
||||
{
|
||||
#if defined(NATIVE_LITTLE_ENDIAN)
|
||||
uint16_t w;
|
||||
memcpy(&w, src, sizeof w);
|
||||
return w;
|
||||
#else
|
||||
const uint8_t *p = ( const uint8_t * )src;
|
||||
return ( uint16_t )((( uint32_t )( p[0] ) << 0) |
|
||||
(( uint32_t )( p[1] ) << 8));
|
||||
#endif
|
||||
}
|
||||
|
||||
static BLAKE2_INLINE void store16( void *dst, uint16_t w )
|
||||
{
|
||||
#if defined(NATIVE_LITTLE_ENDIAN)
|
||||
memcpy(dst, &w, sizeof w);
|
||||
#else
|
||||
uint8_t *p = ( uint8_t * )dst;
|
||||
*p++ = ( uint8_t )w; w >>= 8;
|
||||
*p++ = ( uint8_t )w;
|
||||
#endif
|
||||
}
|
||||
|
||||
static BLAKE2_INLINE void store32( void *dst, uint32_t w )
|
||||
{
|
||||
#if defined(NATIVE_LITTLE_ENDIAN)
|
||||
memcpy(dst, &w, sizeof w);
|
||||
#else
|
||||
uint8_t *p = ( uint8_t * )dst;
|
||||
p[0] = (uint8_t)(w >> 0);
|
||||
p[1] = (uint8_t)(w >> 8);
|
||||
p[2] = (uint8_t)(w >> 16);
|
||||
p[3] = (uint8_t)(w >> 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
static BLAKE2_INLINE void store64( void *dst, uint64_t w )
|
||||
{
|
||||
#if defined(NATIVE_LITTLE_ENDIAN)
|
||||
memcpy(dst, &w, sizeof w);
|
||||
#else
|
||||
uint8_t *p = ( uint8_t * )dst;
|
||||
p[0] = (uint8_t)(w >> 0);
|
||||
p[1] = (uint8_t)(w >> 8);
|
||||
p[2] = (uint8_t)(w >> 16);
|
||||
p[3] = (uint8_t)(w >> 24);
|
||||
p[4] = (uint8_t)(w >> 32);
|
||||
p[5] = (uint8_t)(w >> 40);
|
||||
p[6] = (uint8_t)(w >> 48);
|
||||
p[7] = (uint8_t)(w >> 56);
|
||||
#endif
|
||||
}
|
||||
|
||||
static BLAKE2_INLINE uint64_t load48( const void *src )
|
||||
{
|
||||
const uint8_t *p = ( const uint8_t * )src;
|
||||
return (( uint64_t )( p[0] ) << 0) |
|
||||
(( uint64_t )( p[1] ) << 8) |
|
||||
(( uint64_t )( p[2] ) << 16) |
|
||||
(( uint64_t )( p[3] ) << 24) |
|
||||
(( uint64_t )( p[4] ) << 32) |
|
||||
(( uint64_t )( p[5] ) << 40) ;
|
||||
}
|
||||
|
||||
static BLAKE2_INLINE void store48( void *dst, uint64_t w )
|
||||
{
|
||||
uint8_t *p = ( uint8_t * )dst;
|
||||
p[0] = (uint8_t)(w >> 0);
|
||||
p[1] = (uint8_t)(w >> 8);
|
||||
p[2] = (uint8_t)(w >> 16);
|
||||
p[3] = (uint8_t)(w >> 24);
|
||||
p[4] = (uint8_t)(w >> 32);
|
||||
p[5] = (uint8_t)(w >> 40);
|
||||
}
|
||||
|
||||
static BLAKE2_INLINE uint32_t rotr32( const uint32_t w, const unsigned c )
|
||||
{
|
||||
return ( w >> c ) | ( w << ( 32 - c ) );
|
||||
}
|
||||
|
||||
static BLAKE2_INLINE uint64_t rotr64( const uint64_t w, const unsigned c )
|
||||
{
|
||||
return ( w >> c ) | ( w << ( 64 - c ) );
|
||||
}
|
||||
|
||||
/* prevents compiler optimizing out memset() */
|
||||
static BLAKE2_INLINE void secure_zero_memory(void *v, size_t n)
|
||||
{
|
||||
static void *(*const volatile memset_v)(void *, int, size_t) = &memset;
|
||||
memset_v(v, 0, n);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static const uint64_t blake2b_IV[8] =
|
||||
{
|
||||
0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
|
||||
0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
|
||||
0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
|
||||
0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
|
||||
};
|
||||
|
||||
static const uint8_t blake2b_sigma[12][16] =
|
||||
{
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
|
||||
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
|
||||
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
|
||||
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
|
||||
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
|
||||
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
|
||||
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
|
||||
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
|
||||
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
|
||||
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
|
||||
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }
|
||||
};
|
||||
|
||||
|
||||
static void blake2b_set_lastnode( blake2b_state *S )
|
||||
{
|
||||
S->f[1] = (uint64_t)-1;
|
||||
}
|
||||
|
||||
/* Some helper functions, not necessarily useful */
|
||||
static int blake2b_is_lastblock( const blake2b_state *S )
|
||||
{
|
||||
return S->f[0] != 0;
|
||||
}
|
||||
|
||||
static void blake2b_set_lastblock( blake2b_state *S )
|
||||
{
|
||||
if( S->last_node ) blake2b_set_lastnode( S );
|
||||
|
||||
S->f[0] = (uint64_t)-1;
|
||||
}
|
||||
|
||||
static void blake2b_increment_counter( blake2b_state *S, const uint64_t inc )
|
||||
{
|
||||
S->t[0] += inc;
|
||||
S->t[1] += ( S->t[0] < inc );
|
||||
}
|
||||
|
||||
static void blake2b_init0( blake2b_state *S )
|
||||
{
|
||||
size_t i;
|
||||
memset( S, 0, sizeof( blake2b_state ) );
|
||||
|
||||
for( i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i];
|
||||
}
|
||||
|
||||
/* init xors IV with input parameter block */
|
||||
int blake2b_init_param( blake2b_state *S, const blake2b_param *P )
|
||||
{
|
||||
const uint8_t *p = ( const uint8_t * )( P );
|
||||
size_t i;
|
||||
|
||||
blake2b_init0( S );
|
||||
|
||||
/* IV XOR ParamBlock */
|
||||
for( i = 0; i < 8; ++i )
|
||||
S->h[i] ^= load64( p + sizeof( S->h[i] ) * i );
|
||||
|
||||
S->outlen = P->digest_length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int blake2b_init( blake2b_state *S, size_t outlen )
|
||||
{
|
||||
blake2b_param P[1];
|
||||
|
||||
if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
|
||||
|
||||
P->digest_length = (uint8_t)outlen;
|
||||
P->key_length = 0;
|
||||
P->fanout = 1;
|
||||
P->depth = 1;
|
||||
store32( &P->leaf_length, 0 );
|
||||
store32( &P->node_offset, 0 );
|
||||
store32( &P->xof_length, 0 );
|
||||
P->node_depth = 0;
|
||||
P->inner_length = 0;
|
||||
memset( P->reserved, 0, sizeof( P->reserved ) );
|
||||
memset( P->salt, 0, sizeof( P->salt ) );
|
||||
memset( P->personal, 0, sizeof( P->personal ) );
|
||||
return blake2b_init_param( S, P );
|
||||
}
|
||||
|
||||
|
||||
int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen )
|
||||
{
|
||||
blake2b_param P[1];
|
||||
|
||||
if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
|
||||
|
||||
if ( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1;
|
||||
|
||||
P->digest_length = (uint8_t)outlen;
|
||||
P->key_length = (uint8_t)keylen;
|
||||
P->fanout = 1;
|
||||
P->depth = 1;
|
||||
store32( &P->leaf_length, 0 );
|
||||
store32( &P->node_offset, 0 );
|
||||
store32( &P->xof_length, 0 );
|
||||
P->node_depth = 0;
|
||||
P->inner_length = 0;
|
||||
memset( P->reserved, 0, sizeof( P->reserved ) );
|
||||
memset( P->salt, 0, sizeof( P->salt ) );
|
||||
memset( P->personal, 0, sizeof( P->personal ) );
|
||||
|
||||
if( blake2b_init_param( S, P ) < 0 ) return -1;
|
||||
|
||||
{
|
||||
uint8_t block[BLAKE2B_BLOCKBYTES];
|
||||
memset( block, 0, BLAKE2B_BLOCKBYTES );
|
||||
memcpy( block, key, keylen );
|
||||
blake2b_update( S, block, BLAKE2B_BLOCKBYTES );
|
||||
secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define G(r,i,a,b,c,d) \
|
||||
do { \
|
||||
a = a + b + m[blake2b_sigma[r][2*i+0]]; \
|
||||
d = rotr64(d ^ a, 32); \
|
||||
c = c + d; \
|
||||
b = rotr64(b ^ c, 24); \
|
||||
a = a + b + m[blake2b_sigma[r][2*i+1]]; \
|
||||
d = rotr64(d ^ a, 16); \
|
||||
c = c + d; \
|
||||
b = rotr64(b ^ c, 63); \
|
||||
} while(0)
|
||||
|
||||
#define ROUND(r) \
|
||||
do { \
|
||||
G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
|
||||
G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
|
||||
G(r,2,v[ 2],v[ 6],v[10],v[14]); \
|
||||
G(r,3,v[ 3],v[ 7],v[11],v[15]); \
|
||||
G(r,4,v[ 0],v[ 5],v[10],v[15]); \
|
||||
G(r,5,v[ 1],v[ 6],v[11],v[12]); \
|
||||
G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
|
||||
G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
|
||||
} while(0)
|
||||
|
||||
static void blake2b_compress( blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES] )
|
||||
{
|
||||
uint64_t m[16];
|
||||
uint64_t v[16];
|
||||
size_t i;
|
||||
|
||||
for( i = 0; i < 16; ++i ) {
|
||||
m[i] = load64( block + i * sizeof( m[i] ) );
|
||||
}
|
||||
|
||||
for( i = 0; i < 8; ++i ) {
|
||||
v[i] = S->h[i];
|
||||
}
|
||||
|
||||
v[ 8] = blake2b_IV[0];
|
||||
v[ 9] = blake2b_IV[1];
|
||||
v[10] = blake2b_IV[2];
|
||||
v[11] = blake2b_IV[3];
|
||||
v[12] = blake2b_IV[4] ^ S->t[0];
|
||||
v[13] = blake2b_IV[5] ^ S->t[1];
|
||||
v[14] = blake2b_IV[6] ^ S->f[0];
|
||||
v[15] = blake2b_IV[7] ^ S->f[1];
|
||||
|
||||
ROUND( 0 );
|
||||
ROUND( 1 );
|
||||
ROUND( 2 );
|
||||
ROUND( 3 );
|
||||
ROUND( 4 );
|
||||
ROUND( 5 );
|
||||
ROUND( 6 );
|
||||
ROUND( 7 );
|
||||
ROUND( 8 );
|
||||
ROUND( 9 );
|
||||
ROUND( 10 );
|
||||
ROUND( 11 );
|
||||
|
||||
for( i = 0; i < 8; ++i ) {
|
||||
S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
|
||||
}
|
||||
}
|
||||
|
||||
#undef G
|
||||
#undef ROUND
|
||||
|
||||
int blake2b_update( blake2b_state *S, const void *pin, size_t inlen )
|
||||
{
|
||||
const unsigned char * in = (const unsigned char *)pin;
|
||||
if( inlen > 0 )
|
||||
{
|
||||
size_t left = S->buflen;
|
||||
size_t fill = BLAKE2B_BLOCKBYTES - left;
|
||||
if( inlen > fill )
|
||||
{
|
||||
S->buflen = 0;
|
||||
memcpy( S->buf + left, in, fill ); /* Fill buffer */
|
||||
blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
|
||||
blake2b_compress( S, S->buf ); /* Compress */
|
||||
in += fill; inlen -= fill;
|
||||
while(inlen > BLAKE2B_BLOCKBYTES) {
|
||||
blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);
|
||||
blake2b_compress( S, in );
|
||||
in += BLAKE2B_BLOCKBYTES;
|
||||
inlen -= BLAKE2B_BLOCKBYTES;
|
||||
}
|
||||
}
|
||||
memcpy( S->buf + S->buflen, in, inlen );
|
||||
S->buflen += inlen;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blake2b_final( blake2b_state *S, void *out, size_t outlen )
|
||||
{
|
||||
uint8_t buffer[BLAKE2B_OUTBYTES] = {0};
|
||||
size_t i;
|
||||
|
||||
if( out == NULL || outlen < S->outlen )
|
||||
return -1;
|
||||
|
||||
if( blake2b_is_lastblock( S ) )
|
||||
return -1;
|
||||
|
||||
blake2b_increment_counter( S, S->buflen );
|
||||
blake2b_set_lastblock( S );
|
||||
memset( S->buf + S->buflen, 0, BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */
|
||||
blake2b_compress( S, S->buf );
|
||||
|
||||
for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */
|
||||
store64( buffer + sizeof( S->h[i] ) * i, S->h[i] );
|
||||
|
||||
memcpy( out, buffer, S->outlen );
|
||||
secure_zero_memory(buffer, sizeof(buffer));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* inlen, at least, should be uint64_t. Others can be size_t. */
|
||||
int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen )
|
||||
{
|
||||
blake2b_state S[1];
|
||||
|
||||
/* Verify parameters */
|
||||
if ( NULL == in && inlen > 0 ) return -1;
|
||||
|
||||
if ( NULL == out ) return -1;
|
||||
|
||||
if( NULL == key && keylen > 0 ) return -1;
|
||||
|
||||
if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1;
|
||||
|
||||
if( keylen > BLAKE2B_KEYBYTES ) return -1;
|
||||
|
||||
if( keylen > 0 )
|
||||
{
|
||||
if( blake2b_init_key( S, outlen, key, keylen ) < 0 ) return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( blake2b_init( S, outlen ) < 0 ) return -1;
|
||||
}
|
||||
|
||||
blake2b_update( S, ( const uint8_t * )in, inlen );
|
||||
blake2b_final( S, out, outlen );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) {
|
||||
return blake2b(out, outlen, in, inlen, key, keylen);
|
||||
}
|
||||
|
||||
#if defined(SUPERCOP)
|
||||
int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen )
|
||||
{
|
||||
return blake2b( out, BLAKE2B_OUTBYTES, in, inlen, NULL, 0 );
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(BLAKE2B_SELFTEST)
|
||||
#include <string.h>
|
||||
#include "blake2-kat.h"
|
||||
int main( void )
|
||||
{
|
||||
uint8_t key[BLAKE2B_KEYBYTES];
|
||||
uint8_t buf[BLAKE2_KAT_LENGTH];
|
||||
size_t i, step;
|
||||
|
||||
for( i = 0; i < BLAKE2B_KEYBYTES; ++i )
|
||||
key[i] = ( uint8_t )i;
|
||||
|
||||
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
|
||||
buf[i] = ( uint8_t )i;
|
||||
|
||||
/* Test simple API */
|
||||
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
|
||||
{
|
||||
uint8_t hash[BLAKE2B_OUTBYTES];
|
||||
blake2b( hash, BLAKE2B_OUTBYTES, buf, i, key, BLAKE2B_KEYBYTES );
|
||||
|
||||
if( 0 != memcmp( hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES ) )
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Test streaming API */
|
||||
for(step = 1; step < BLAKE2B_BLOCKBYTES; ++step) {
|
||||
for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) {
|
||||
uint8_t hash[BLAKE2B_OUTBYTES];
|
||||
blake2b_state S;
|
||||
uint8_t * p = buf;
|
||||
size_t mlen = i;
|
||||
int err = 0;
|
||||
|
||||
if( (err = blake2b_init_key(&S, BLAKE2B_OUTBYTES, key, BLAKE2B_KEYBYTES)) < 0 ) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
while (mlen >= step) {
|
||||
if ( (err = blake2b_update(&S, p, step)) < 0 ) {
|
||||
goto fail;
|
||||
}
|
||||
mlen -= step;
|
||||
p += step;
|
||||
}
|
||||
if ( (err = blake2b_update(&S, p, mlen)) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
if ( (err = blake2b_final(&S, hash, BLAKE2B_OUTBYTES)) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (0 != memcmp(hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES)) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
puts( "ok" );
|
||||
return 0;
|
||||
fail:
|
||||
puts("error");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -78,6 +78,10 @@ static inline Buf *buf_create_from_mem(const char *ptr, size_t len) {
|
||||
return buf;
|
||||
}
|
||||
|
||||
static inline Buf *buf_create_from_slice(Slice<uint8_t> slice) {
|
||||
return buf_create_from_mem((const char *)slice.ptr, slice.len);
|
||||
}
|
||||
|
||||
static inline Buf *buf_create_from_str(const char *str) {
|
||||
return buf_create_from_mem(str, strlen(str));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,469 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Andrew Kelley
|
||||
*
|
||||
* This file is part of zig, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "cache_hash.hpp"
|
||||
#include "all_types.hpp"
|
||||
#include "buffer.hpp"
|
||||
#include "os.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void cache_init(CacheHash *ch, Buf *manifest_dir) {
|
||||
int rc = blake2b_init(&ch->blake, 48);
|
||||
assert(rc == 0);
|
||||
ch->files = {};
|
||||
ch->manifest_dir = manifest_dir;
|
||||
ch->manifest_file_path = nullptr;
|
||||
ch->manifest_dirty = false;
|
||||
}
|
||||
|
||||
void cache_str(CacheHash *ch, const char *ptr) {
|
||||
assert(ch->manifest_file_path == nullptr);
|
||||
assert(ptr != nullptr);
|
||||
// + 1 to include the null byte
|
||||
blake2b_update(&ch->blake, ptr, strlen(ptr) + 1);
|
||||
}
|
||||
|
||||
void cache_int(CacheHash *ch, int x) {
|
||||
assert(ch->manifest_file_path == nullptr);
|
||||
// + 1 to include the null byte
|
||||
uint8_t buf[sizeof(int) + 1];
|
||||
memcpy(buf, &x, sizeof(int));
|
||||
buf[sizeof(int)] = 0;
|
||||
blake2b_update(&ch->blake, buf, sizeof(int) + 1);
|
||||
}
|
||||
|
||||
void cache_usize(CacheHash *ch, size_t x) {
|
||||
assert(ch->manifest_file_path == nullptr);
|
||||
// + 1 to include the null byte
|
||||
uint8_t buf[sizeof(size_t) + 1];
|
||||
memcpy(buf, &x, sizeof(size_t));
|
||||
buf[sizeof(size_t)] = 0;
|
||||
blake2b_update(&ch->blake, buf, sizeof(size_t) + 1);
|
||||
}
|
||||
|
||||
void cache_bool(CacheHash *ch, bool x) {
|
||||
assert(ch->manifest_file_path == nullptr);
|
||||
blake2b_update(&ch->blake, &x, 1);
|
||||
}
|
||||
|
||||
void cache_buf(CacheHash *ch, Buf *buf) {
|
||||
assert(ch->manifest_file_path == nullptr);
|
||||
assert(buf != nullptr);
|
||||
// + 1 to include the null byte
|
||||
blake2b_update(&ch->blake, buf_ptr(buf), buf_len(buf) + 1);
|
||||
}
|
||||
|
||||
void cache_buf_opt(CacheHash *ch, Buf *buf) {
|
||||
assert(ch->manifest_file_path == nullptr);
|
||||
if (buf == nullptr) {
|
||||
cache_str(ch, "");
|
||||
cache_str(ch, "");
|
||||
} else {
|
||||
cache_buf(ch, buf);
|
||||
}
|
||||
}
|
||||
|
||||
void cache_list_of_link_lib(CacheHash *ch, LinkLib **ptr, size_t len) {
|
||||
assert(ch->manifest_file_path == nullptr);
|
||||
for (size_t i = 0; i < len; i += 1) {
|
||||
LinkLib *lib = ptr[i];
|
||||
if (lib->provided_explicitly) {
|
||||
cache_buf(ch, lib->name);
|
||||
}
|
||||
}
|
||||
cache_str(ch, "");
|
||||
}
|
||||
|
||||
void cache_list_of_buf(CacheHash *ch, Buf **ptr, size_t len) {
|
||||
assert(ch->manifest_file_path == nullptr);
|
||||
for (size_t i = 0; i < len; i += 1) {
|
||||
Buf *buf = ptr[i];
|
||||
cache_buf(ch, buf);
|
||||
}
|
||||
cache_str(ch, "");
|
||||
}
|
||||
|
||||
void cache_list_of_file(CacheHash *ch, Buf **ptr, size_t len) {
|
||||
assert(ch->manifest_file_path == nullptr);
|
||||
|
||||
for (size_t i = 0; i < len; i += 1) {
|
||||
Buf *buf = ptr[i];
|
||||
cache_file(ch, buf);
|
||||
}
|
||||
cache_str(ch, "");
|
||||
}
|
||||
|
||||
void cache_list_of_str(CacheHash *ch, const char **ptr, size_t len) {
|
||||
assert(ch->manifest_file_path == nullptr);
|
||||
|
||||
for (size_t i = 0; i < len; i += 1) {
|
||||
const char *s = ptr[i];
|
||||
cache_str(ch, s);
|
||||
}
|
||||
cache_str(ch, "");
|
||||
}
|
||||
|
||||
void cache_file(CacheHash *ch, Buf *file_path) {
|
||||
assert(ch->manifest_file_path == nullptr);
|
||||
assert(file_path != nullptr);
|
||||
Buf *resolved_path = buf_alloc();
|
||||
*resolved_path = os_path_resolve(&file_path, 1);
|
||||
CacheHashFile *chf = ch->files.add_one();
|
||||
chf->path = resolved_path;
|
||||
cache_buf(ch, resolved_path);
|
||||
}
|
||||
|
||||
void cache_file_opt(CacheHash *ch, Buf *file_path) {
|
||||
assert(ch->manifest_file_path == nullptr);
|
||||
if (file_path == nullptr) {
|
||||
cache_str(ch, "");
|
||||
cache_str(ch, "");
|
||||
} else {
|
||||
cache_file(ch, file_path);
|
||||
}
|
||||
}
|
||||
|
||||
// Ported from std/base64.zig
|
||||
static uint8_t base64_fs_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||
static void base64_encode(Slice<uint8_t> dest, Slice<uint8_t> source) {
|
||||
size_t dest_len = ((source.len + 2) / 3) * 4;
|
||||
assert(dest.len == dest_len);
|
||||
|
||||
size_t i = 0;
|
||||
size_t out_index = 0;
|
||||
for (; i + 2 < source.len; i += 3) {
|
||||
dest.ptr[out_index] = base64_fs_alphabet[(source.ptr[i] >> 2) & 0x3f];
|
||||
out_index += 1;
|
||||
|
||||
dest.ptr[out_index] = base64_fs_alphabet[((source.ptr[i] & 0x3) << 4) | ((source.ptr[i + 1] & 0xf0) >> 4)];
|
||||
out_index += 1;
|
||||
|
||||
dest.ptr[out_index] = base64_fs_alphabet[((source.ptr[i + 1] & 0xf) << 2) | ((source.ptr[i + 2] & 0xc0) >> 6)];
|
||||
out_index += 1;
|
||||
|
||||
dest.ptr[out_index] = base64_fs_alphabet[source.ptr[i + 2] & 0x3f];
|
||||
out_index += 1;
|
||||
}
|
||||
|
||||
// Assert that we never need pad characters.
|
||||
assert(i == source.len);
|
||||
}
|
||||
|
||||
// Ported from std/base64.zig
|
||||
static Error base64_decode(Slice<uint8_t> dest, Slice<uint8_t> source) {
|
||||
assert(source.len % 4 == 0);
|
||||
assert(dest.len == (source.len / 4) * 3);
|
||||
|
||||
// In Zig this is comptime computed. In C++ it's not worth it to do that.
|
||||
uint8_t char_to_index[256];
|
||||
bool char_in_alphabet[256] = {0};
|
||||
for (size_t i = 0; i < 64; i += 1) {
|
||||
uint8_t c = base64_fs_alphabet[i];
|
||||
assert(!char_in_alphabet[c]);
|
||||
char_in_alphabet[c] = true;
|
||||
char_to_index[c] = i;
|
||||
}
|
||||
|
||||
size_t src_cursor = 0;
|
||||
size_t dest_cursor = 0;
|
||||
|
||||
for (;src_cursor < source.len; src_cursor += 4) {
|
||||
if (!char_in_alphabet[source.ptr[src_cursor + 0]]) return ErrorInvalidFormat;
|
||||
if (!char_in_alphabet[source.ptr[src_cursor + 1]]) return ErrorInvalidFormat;
|
||||
if (!char_in_alphabet[source.ptr[src_cursor + 2]]) return ErrorInvalidFormat;
|
||||
if (!char_in_alphabet[source.ptr[src_cursor + 3]]) return ErrorInvalidFormat;
|
||||
dest.ptr[dest_cursor + 0] = (char_to_index[source.ptr[src_cursor + 0]] << 2) | (char_to_index[source.ptr[src_cursor + 1]] >> 4);
|
||||
dest.ptr[dest_cursor + 1] = (char_to_index[source.ptr[src_cursor + 1]] << 4) | (char_to_index[source.ptr[src_cursor + 2]] >> 2);
|
||||
dest.ptr[dest_cursor + 2] = (char_to_index[source.ptr[src_cursor + 2]] << 6) | (char_to_index[source.ptr[src_cursor + 3]]);
|
||||
dest_cursor += 3;
|
||||
}
|
||||
|
||||
assert(src_cursor == source.len);
|
||||
assert(dest_cursor == dest.len);
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
static Error hash_file(uint8_t *digest, OsFile handle, Buf *contents) {
|
||||
Error err;
|
||||
|
||||
if (contents) {
|
||||
buf_resize(contents, 0);
|
||||
}
|
||||
|
||||
blake2b_state blake;
|
||||
int rc = blake2b_init(&blake, 48);
|
||||
assert(rc == 0);
|
||||
|
||||
for (;;) {
|
||||
uint8_t buf[4096];
|
||||
size_t amt = 4096;
|
||||
if ((err = os_file_read(handle, buf, &amt)))
|
||||
return err;
|
||||
if (amt == 0) {
|
||||
rc = blake2b_final(&blake, digest, 48);
|
||||
assert(rc == 0);
|
||||
return ErrorNone;
|
||||
}
|
||||
blake2b_update(&blake, buf, amt);
|
||||
if (contents) {
|
||||
buf_append_mem(contents, (char*)buf, amt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Error populate_file_hash(CacheHash *ch, CacheHashFile *chf, Buf *contents) {
|
||||
Error err;
|
||||
|
||||
assert(chf->path != nullptr);
|
||||
|
||||
OsFile this_file;
|
||||
if ((err = os_file_open_r(chf->path, &this_file)))
|
||||
return err;
|
||||
|
||||
if ((err = os_file_mtime(this_file, &chf->mtime))) {
|
||||
os_file_close(this_file);
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = hash_file(chf->bin_digest, this_file, contents))) {
|
||||
os_file_close(this_file);
|
||||
return err;
|
||||
}
|
||||
os_file_close(this_file);
|
||||
|
||||
blake2b_update(&ch->blake, chf->bin_digest, 48);
|
||||
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
Error cache_hit(CacheHash *ch, Buf *out_digest) {
|
||||
Error err;
|
||||
|
||||
uint8_t bin_digest[48];
|
||||
int rc = blake2b_final(&ch->blake, bin_digest, 48);
|
||||
assert(rc == 0);
|
||||
|
||||
if (ch->files.length == 0) {
|
||||
buf_resize(out_digest, 64);
|
||||
base64_encode(buf_to_slice(out_digest), {bin_digest, 48});
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
Buf b64_digest = BUF_INIT;
|
||||
buf_resize(&b64_digest, 64);
|
||||
base64_encode(buf_to_slice(&b64_digest), {bin_digest, 48});
|
||||
|
||||
rc = blake2b_init(&ch->blake, 48);
|
||||
assert(rc == 0);
|
||||
blake2b_update(&ch->blake, bin_digest, 48);
|
||||
|
||||
ch->manifest_file_path = buf_alloc();
|
||||
os_path_join(ch->manifest_dir, &b64_digest, ch->manifest_file_path);
|
||||
|
||||
buf_append_str(ch->manifest_file_path, ".txt");
|
||||
|
||||
if ((err = os_make_path(ch->manifest_dir)))
|
||||
return err;
|
||||
|
||||
if ((err = os_file_open_lock_rw(ch->manifest_file_path, &ch->manifest_file)))
|
||||
return err;
|
||||
|
||||
Buf line_buf = BUF_INIT;
|
||||
buf_resize(&line_buf, 512);
|
||||
if ((err = os_file_read_all(ch->manifest_file, &line_buf))) {
|
||||
os_file_close(ch->manifest_file);
|
||||
return err;
|
||||
}
|
||||
|
||||
size_t input_file_count = ch->files.length;
|
||||
bool any_file_changed = false;
|
||||
size_t file_i = 0;
|
||||
SplitIterator line_it = memSplit(buf_to_slice(&line_buf), str("\n"));
|
||||
for (;; file_i += 1) {
|
||||
Optional<Slice<uint8_t>> opt_line = SplitIterator_next(&line_it);
|
||||
if (!opt_line.is_some)
|
||||
break;
|
||||
|
||||
CacheHashFile *chf;
|
||||
if (file_i < input_file_count) {
|
||||
chf = &ch->files.at(file_i);
|
||||
} else if (any_file_changed) {
|
||||
// cache miss.
|
||||
// keep the the manifest file open with the rw lock
|
||||
// reset the hash
|
||||
rc = blake2b_init(&ch->blake, 48);
|
||||
assert(rc == 0);
|
||||
blake2b_update(&ch->blake, bin_digest, 48);
|
||||
ch->files.resize(input_file_count);
|
||||
// bring the hash up to the input file hashes
|
||||
for (file_i = 0; file_i < input_file_count; file_i += 1) {
|
||||
blake2b_update(&ch->blake, ch->files.at(file_i).bin_digest, 48);
|
||||
}
|
||||
// caller can notice that out_digest is unmodified.
|
||||
return ErrorNone;
|
||||
} else {
|
||||
chf = ch->files.add_one();
|
||||
chf->path = nullptr;
|
||||
}
|
||||
|
||||
SplitIterator it = memSplit(opt_line.value, str(" "));
|
||||
|
||||
Optional<Slice<uint8_t>> opt_mtime_sec = SplitIterator_next(&it);
|
||||
if (!opt_mtime_sec.is_some) {
|
||||
os_file_close(ch->manifest_file);
|
||||
return ErrorInvalidFormat;
|
||||
}
|
||||
chf->mtime.sec = strtoull((const char *)opt_mtime_sec.value.ptr, nullptr, 10);
|
||||
|
||||
Optional<Slice<uint8_t>> opt_mtime_nsec = SplitIterator_next(&it);
|
||||
if (!opt_mtime_nsec.is_some) {
|
||||
os_file_close(ch->manifest_file);
|
||||
return ErrorInvalidFormat;
|
||||
}
|
||||
chf->mtime.nsec = strtoull((const char *)opt_mtime_nsec.value.ptr, nullptr, 10);
|
||||
|
||||
Optional<Slice<uint8_t>> opt_digest = SplitIterator_next(&it);
|
||||
if (!opt_digest.is_some) {
|
||||
os_file_close(ch->manifest_file);
|
||||
return ErrorInvalidFormat;
|
||||
}
|
||||
if ((err = base64_decode({chf->bin_digest, 48}, opt_digest.value))) {
|
||||
os_file_close(ch->manifest_file);
|
||||
return ErrorInvalidFormat;
|
||||
}
|
||||
|
||||
Slice<uint8_t> file_path = SplitIterator_rest(&it);
|
||||
if (file_path.len == 0) {
|
||||
os_file_close(ch->manifest_file);
|
||||
return ErrorInvalidFormat;
|
||||
}
|
||||
Buf *this_path = buf_create_from_slice(file_path);
|
||||
if (chf->path != nullptr && !buf_eql_buf(this_path, chf->path)) {
|
||||
os_file_close(ch->manifest_file);
|
||||
return ErrorInvalidFormat;
|
||||
}
|
||||
chf->path = this_path;
|
||||
|
||||
// if the mtime matches we can trust the digest
|
||||
OsFile this_file;
|
||||
if ((err = os_file_open_r(chf->path, &this_file))) {
|
||||
os_file_close(ch->manifest_file);
|
||||
return err;
|
||||
}
|
||||
OsTimeStamp actual_mtime;
|
||||
if ((err = os_file_mtime(this_file, &actual_mtime))) {
|
||||
os_file_close(this_file);
|
||||
os_file_close(ch->manifest_file);
|
||||
return err;
|
||||
}
|
||||
if (chf->mtime.sec == actual_mtime.sec && chf->mtime.nsec == actual_mtime.nsec) {
|
||||
os_file_close(this_file);
|
||||
} else {
|
||||
// we have to recompute the digest.
|
||||
// later we'll rewrite the manifest with the new mtime/digest values
|
||||
ch->manifest_dirty = true;
|
||||
chf->mtime = actual_mtime;
|
||||
|
||||
uint8_t actual_digest[48];
|
||||
if ((err = hash_file(actual_digest, this_file, nullptr))) {
|
||||
os_file_close(this_file);
|
||||
os_file_close(ch->manifest_file);
|
||||
return err;
|
||||
}
|
||||
os_file_close(this_file);
|
||||
if (memcmp(chf->bin_digest, actual_digest, 48) != 0) {
|
||||
memcpy(chf->bin_digest, actual_digest, 48);
|
||||
// keep going until we have the input file digests
|
||||
any_file_changed = true;
|
||||
}
|
||||
}
|
||||
if (!any_file_changed) {
|
||||
blake2b_update(&ch->blake, chf->bin_digest, 48);
|
||||
}
|
||||
}
|
||||
if (file_i < input_file_count) {
|
||||
// manifest file is empty or missing entries, so this is a cache miss
|
||||
ch->manifest_dirty = true;
|
||||
for (; file_i < input_file_count; file_i += 1) {
|
||||
CacheHashFile *chf = &ch->files.at(file_i);
|
||||
if ((err = populate_file_hash(ch, chf, nullptr))) {
|
||||
os_file_close(ch->manifest_file);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return ErrorNone;
|
||||
}
|
||||
// Cache Hit
|
||||
return cache_final(ch, out_digest);
|
||||
}
|
||||
|
||||
Error cache_add_file_fetch(CacheHash *ch, Buf *resolved_path, Buf *contents) {
|
||||
Error err;
|
||||
|
||||
assert(ch->manifest_file_path != nullptr);
|
||||
CacheHashFile *chf = ch->files.add_one();
|
||||
chf->path = resolved_path;
|
||||
if ((err = populate_file_hash(ch, chf, contents))) {
|
||||
os_file_close(ch->manifest_file);
|
||||
return err;
|
||||
}
|
||||
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
Error cache_add_file(CacheHash *ch, Buf *path) {
|
||||
Buf *resolved_path = buf_alloc();
|
||||
*resolved_path = os_path_resolve(&path, 1);
|
||||
return cache_add_file_fetch(ch, resolved_path, nullptr);
|
||||
}
|
||||
|
||||
static Error write_manifest_file(CacheHash *ch) {
|
||||
Error err;
|
||||
Buf contents = BUF_INIT;
|
||||
buf_resize(&contents, 0);
|
||||
uint8_t encoded_digest[65];
|
||||
encoded_digest[64] = 0;
|
||||
for (size_t i = 0; i < ch->files.length; i += 1) {
|
||||
CacheHashFile *chf = &ch->files.at(i);
|
||||
base64_encode({encoded_digest, 64}, {chf->bin_digest, 48});
|
||||
buf_appendf(&contents, "%" ZIG_PRI_u64 " %" ZIG_PRI_u64 " %s %s\n",
|
||||
chf->mtime.sec, chf->mtime.nsec, encoded_digest, buf_ptr(chf->path));
|
||||
}
|
||||
if ((err = os_file_overwrite(ch->manifest_file, &contents)))
|
||||
return err;
|
||||
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
Error cache_final(CacheHash *ch, Buf *out_digest) {
|
||||
Error err;
|
||||
|
||||
assert(ch->manifest_file_path != nullptr);
|
||||
|
||||
if (ch->manifest_dirty) {
|
||||
if ((err = write_manifest_file(ch))) {
|
||||
fprintf(stderr, "Warning: Unable to write cache file '%s': %s\n",
|
||||
buf_ptr(ch->manifest_file_path), err_str(err));
|
||||
}
|
||||
}
|
||||
// We don't close the manifest file yet, because we want to
|
||||
// keep it locked until the API user is done using it.
|
||||
|
||||
uint8_t bin_digest[48];
|
||||
int rc = blake2b_final(&ch->blake, bin_digest, 48);
|
||||
assert(rc == 0);
|
||||
buf_resize(out_digest, 64);
|
||||
base64_encode(buf_to_slice(out_digest), {bin_digest, 48});
|
||||
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
void cache_release(CacheHash *ch) {
|
||||
assert(ch->manifest_file_path != nullptr);
|
||||
os_file_close(ch->manifest_file);
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Andrew Kelley
|
||||
*
|
||||
* This file is part of zig, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#ifndef ZIG_CACHE_HASH_HPP
|
||||
#define ZIG_CACHE_HASH_HPP
|
||||
|
||||
#include "blake2.h"
|
||||
#include "os.hpp"
|
||||
|
||||
struct LinkLib;
|
||||
|
||||
struct CacheHashFile {
|
||||
Buf *path;
|
||||
OsTimeStamp mtime;
|
||||
uint8_t bin_digest[48];
|
||||
Buf *contents;
|
||||
};
|
||||
|
||||
struct CacheHash {
|
||||
blake2b_state blake;
|
||||
ZigList<CacheHashFile> files;
|
||||
Buf *manifest_dir;
|
||||
Buf *manifest_file_path;
|
||||
OsFile manifest_file;
|
||||
bool manifest_dirty;
|
||||
};
|
||||
|
||||
// Always call this first to set up.
|
||||
void cache_init(CacheHash *ch, Buf *manifest_dir);
|
||||
|
||||
// Next, use the hash population functions to add the initial parameters.
|
||||
void cache_str(CacheHash *ch, const char *ptr);
|
||||
void cache_int(CacheHash *ch, int x);
|
||||
void cache_bool(CacheHash *ch, bool x);
|
||||
void cache_usize(CacheHash *ch, size_t x);
|
||||
void cache_buf(CacheHash *ch, Buf *buf);
|
||||
void cache_buf_opt(CacheHash *ch, Buf *buf);
|
||||
void cache_list_of_link_lib(CacheHash *ch, LinkLib **ptr, size_t len);
|
||||
void cache_list_of_buf(CacheHash *ch, Buf **ptr, size_t len);
|
||||
void cache_list_of_file(CacheHash *ch, Buf **ptr, size_t len);
|
||||
void cache_list_of_str(CacheHash *ch, const char **ptr, size_t len);
|
||||
void cache_file(CacheHash *ch, Buf *path);
|
||||
void cache_file_opt(CacheHash *ch, Buf *path);
|
||||
|
||||
// Then call cache_hit when you're ready to see if you can skip the next step.
|
||||
// out_b64_digest will be left unchanged if it was a cache miss.
|
||||
// If you got a cache hit, the next step is cache_release.
|
||||
// From this point on, there is a lock on the input params. Release
|
||||
// the lock with cache_release.
|
||||
Error ATTRIBUTE_MUST_USE cache_hit(CacheHash *ch, Buf *out_b64_digest);
|
||||
|
||||
// If you did not get a cache hit, call this function for every file
|
||||
// that is depended on, and then finish with cache_final.
|
||||
Error ATTRIBUTE_MUST_USE cache_add_file(CacheHash *ch, Buf *path);
|
||||
|
||||
// This variant of cache_add_file returns the file contents.
|
||||
// Also the file path argument must be already resolved.
|
||||
Error ATTRIBUTE_MUST_USE cache_add_file_fetch(CacheHash *ch, Buf *resolved_path, Buf *contents);
|
||||
|
||||
// out_b64_digest will be the same thing that cache_hit returns if you got a cache hit
|
||||
Error ATTRIBUTE_MUST_USE cache_final(CacheHash *ch, Buf *out_b64_digest);
|
||||
|
||||
// Until this function is called, no one will be able to get a lock on your input params.
|
||||
void cache_release(CacheHash *ch);
|
||||
|
||||
|
||||
#endif
|
||||
+394
-136
@@ -8,12 +8,12 @@
|
||||
#include "analyze.hpp"
|
||||
#include "ast_render.hpp"
|
||||
#include "codegen.hpp"
|
||||
#include "compiler.hpp"
|
||||
#include "config.h"
|
||||
#include "errmsg.hpp"
|
||||
#include "error.hpp"
|
||||
#include "hash_map.hpp"
|
||||
#include "ir.hpp"
|
||||
#include "link.hpp"
|
||||
#include "os.hpp"
|
||||
#include "translate_c.hpp"
|
||||
#include "target.hpp"
|
||||
@@ -183,14 +183,14 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
|
||||
return g;
|
||||
}
|
||||
|
||||
void codegen_destroy(CodeGen *codegen) {
|
||||
LLVMDisposeTargetMachine(codegen->target_machine);
|
||||
}
|
||||
|
||||
void codegen_set_output_h_path(CodeGen *g, Buf *h_path) {
|
||||
g->out_h_path = h_path;
|
||||
}
|
||||
|
||||
void codegen_set_output_path(CodeGen *g, Buf *path) {
|
||||
g->wanted_output_file_path = path;
|
||||
}
|
||||
|
||||
void codegen_set_clang_argv(CodeGen *g, const char **args, size_t len) {
|
||||
g->clang_argv = args;
|
||||
g->clang_argv_len = len;
|
||||
@@ -243,10 +243,6 @@ void codegen_set_out_name(CodeGen *g, Buf *out_name) {
|
||||
g->root_out_name = out_name;
|
||||
}
|
||||
|
||||
void codegen_set_cache_dir(CodeGen *g, Buf cache_dir) {
|
||||
g->cache_dir = cache_dir;
|
||||
}
|
||||
|
||||
void codegen_set_libc_lib_dir(CodeGen *g, Buf *libc_lib_dir) {
|
||||
g->libc_lib_dir = libc_lib_dir;
|
||||
}
|
||||
@@ -779,7 +775,8 @@ static LLVMValueRef gen_store_untyped(CodeGen *g, LLVMValueRef value, LLVMValueR
|
||||
|
||||
static LLVMValueRef gen_store(CodeGen *g, LLVMValueRef value, LLVMValueRef ptr, ZigType *ptr_type) {
|
||||
assert(ptr_type->id == ZigTypeIdPointer);
|
||||
return gen_store_untyped(g, value, ptr, ptr_type->data.pointer.alignment, ptr_type->data.pointer.is_volatile);
|
||||
uint32_t alignment = get_ptr_align(g, ptr_type);
|
||||
return gen_store_untyped(g, value, ptr, alignment, ptr_type->data.pointer.is_volatile);
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_load_untyped(CodeGen *g, LLVMValueRef ptr, uint32_t alignment, bool is_volatile,
|
||||
@@ -797,7 +794,8 @@ static LLVMValueRef gen_load_untyped(CodeGen *g, LLVMValueRef ptr, uint32_t alig
|
||||
|
||||
static LLVMValueRef gen_load(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_type, const char *name) {
|
||||
assert(ptr_type->id == ZigTypeIdPointer);
|
||||
return gen_load_untyped(g, ptr, ptr_type->data.pointer.alignment, ptr_type->data.pointer.is_volatile, name);
|
||||
uint32_t alignment = get_ptr_align(g, ptr_type);
|
||||
return gen_load_untyped(g, ptr, alignment, ptr_type->data.pointer.is_volatile, name);
|
||||
}
|
||||
|
||||
static LLVMValueRef get_handle_value(CodeGen *g, LLVMValueRef ptr, ZigType *type, ZigType *ptr_type) {
|
||||
@@ -1772,7 +1770,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty
|
||||
|
||||
ZigType *usize = g->builtin_types.entry_usize;
|
||||
uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, child_type->type_ref);
|
||||
uint64_t align_bytes = ptr_type->data.pointer.alignment;
|
||||
uint64_t align_bytes = get_ptr_align(g, ptr_type);
|
||||
assert(size_bytes > 0);
|
||||
assert(align_bytes > 0);
|
||||
|
||||
@@ -3162,7 +3160,8 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
|
||||
assert(var->value->type == init_value->value.type);
|
||||
ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->value->type, false, false,
|
||||
PtrLenSingle, var->align_bytes, 0, 0);
|
||||
gen_assign_raw(g, var->value_ref, var_ptr_type, ir_llvm_value(g, init_value));
|
||||
LLVMValueRef llvm_init_val = ir_llvm_value(g, init_value);
|
||||
gen_assign_raw(g, var->value_ref, var_ptr_type, llvm_init_val);
|
||||
} else {
|
||||
bool want_safe = ir_want_runtime_safety(g, &decl_var_instruction->base);
|
||||
if (want_safe) {
|
||||
@@ -4022,7 +4021,7 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
|
||||
LLVMValueRef ptr_val;
|
||||
|
||||
if (target_type->id == ZigTypeIdPointer) {
|
||||
align_bytes = target_type->data.pointer.alignment;
|
||||
align_bytes = get_ptr_align(g, target_type);
|
||||
ptr_val = target_val;
|
||||
} else if (target_type->id == ZigTypeIdFn) {
|
||||
align_bytes = target_type->data.fn.fn_type_id.alignment;
|
||||
@@ -4030,7 +4029,7 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
|
||||
} else if (target_type->id == ZigTypeIdOptional &&
|
||||
target_type->data.maybe.child_type->id == ZigTypeIdPointer)
|
||||
{
|
||||
align_bytes = target_type->data.maybe.child_type->data.pointer.alignment;
|
||||
align_bytes = get_ptr_align(g, target_type->data.maybe.child_type);
|
||||
ptr_val = target_val;
|
||||
} else if (target_type->id == ZigTypeIdOptional &&
|
||||
target_type->data.maybe.child_type->id == ZigTypeIdFn)
|
||||
@@ -4043,7 +4042,7 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
|
||||
zig_panic("TODO audit this function");
|
||||
} else if (target_type->id == ZigTypeIdStruct && target_type->data.structure.is_slice) {
|
||||
ZigType *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index].type_entry;
|
||||
align_bytes = slice_ptr_type->data.pointer.alignment;
|
||||
align_bytes = get_ptr_align(g, slice_ptr_type);
|
||||
|
||||
size_t ptr_index = target_type->data.structure.fields[slice_ptr_index].gen_index;
|
||||
LLVMValueRef ptr_val_ptr = LLVMBuildStructGEP(g->builder, target_val, (unsigned)ptr_index, "");
|
||||
@@ -4195,7 +4194,7 @@ static LLVMValueRef ir_render_memset(CodeGen *g, IrExecutable *executable, IrIns
|
||||
ZigType *ptr_type = instruction->dest_ptr->value.type;
|
||||
assert(ptr_type->id == ZigTypeIdPointer);
|
||||
|
||||
ZigLLVMBuildMemSet(g->builder, dest_ptr_casted, char_val, len_val, ptr_type->data.pointer.alignment, ptr_type->data.pointer.is_volatile);
|
||||
ZigLLVMBuildMemSet(g->builder, dest_ptr_casted, char_val, len_val, get_ptr_align(g, ptr_type), ptr_type->data.pointer.is_volatile);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -4216,9 +4215,8 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutable *executable, IrIns
|
||||
assert(src_ptr_type->id == ZigTypeIdPointer);
|
||||
|
||||
bool is_volatile = (dest_ptr_type->data.pointer.is_volatile || src_ptr_type->data.pointer.is_volatile);
|
||||
|
||||
ZigLLVMBuildMemCpy(g->builder, dest_ptr_casted, dest_ptr_type->data.pointer.alignment,
|
||||
src_ptr_casted, src_ptr_type->data.pointer.alignment, len_val, is_volatile);
|
||||
ZigLLVMBuildMemCpy(g->builder, dest_ptr_casted, get_ptr_align(g, dest_ptr_type),
|
||||
src_ptr_casted, get_ptr_align(g, src_ptr_type), len_val, is_volatile);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -4629,7 +4627,6 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa
|
||||
|
||||
static LLVMValueRef ir_render_union_tag(CodeGen *g, IrExecutable *executable, IrInstructionUnionTag *instruction) {
|
||||
ZigType *union_type = instruction->value->value.type;
|
||||
assert(union_type->data.unionation.gen_tag_index != SIZE_MAX);
|
||||
|
||||
ZigType *tag_type = union_type->data.unionation.tag_type;
|
||||
if (!type_has_bits(tag_type))
|
||||
@@ -4639,6 +4636,7 @@ static LLVMValueRef ir_render_union_tag(CodeGen *g, IrExecutable *executable, Ir
|
||||
if (union_type->data.unionation.gen_field_count == 0)
|
||||
return union_val;
|
||||
|
||||
assert(union_type->data.unionation.gen_tag_index != SIZE_MAX);
|
||||
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_val,
|
||||
union_type->data.unionation.gen_tag_index, "");
|
||||
ZigType *ptr_type = get_pointer_to_type(g, tag_type, false);
|
||||
@@ -5393,7 +5391,6 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
|
||||
case ZigTypeIdErrorUnion:
|
||||
case ZigTypeIdErrorSet:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdVoid:
|
||||
@@ -5774,12 +5771,24 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
|
||||
LLVMValueRef tag_value = bigint_to_llvm_const(type_entry->data.unionation.tag_type->type_ref,
|
||||
&const_val->data.x_union.tag);
|
||||
|
||||
LLVMValueRef fields[2];
|
||||
LLVMValueRef fields[3];
|
||||
fields[type_entry->data.unionation.gen_union_index] = union_value_ref;
|
||||
fields[type_entry->data.unionation.gen_tag_index] = tag_value;
|
||||
|
||||
if (make_unnamed_struct) {
|
||||
return LLVMConstStruct(fields, 2, false);
|
||||
LLVMValueRef result = LLVMConstStruct(fields, 2, false);
|
||||
uint64_t last_field_offset = LLVMOffsetOfElement(g->target_data_ref, LLVMTypeOf(result), 1);
|
||||
uint64_t end_offset = last_field_offset +
|
||||
LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(fields[1]));
|
||||
uint64_t expected_sz = LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref);
|
||||
unsigned pad_sz = expected_sz - end_offset;
|
||||
if (pad_sz != 0) {
|
||||
fields[2] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), pad_sz));
|
||||
result = LLVMConstStruct(fields, 3, false);
|
||||
}
|
||||
uint64_t actual_sz = LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(result));
|
||||
assert(actual_sz == expected_sz);
|
||||
return result;
|
||||
} else {
|
||||
return LLVMConstNamedStruct(type_entry->type_ref, fields, 2);
|
||||
}
|
||||
@@ -5789,9 +5798,16 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
|
||||
case ZigTypeIdEnum:
|
||||
return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_enum_tag);
|
||||
case ZigTypeIdFn:
|
||||
assert(const_val->data.x_ptr.special == ConstPtrSpecialFunction);
|
||||
assert(const_val->data.x_ptr.mut == ConstPtrMutComptimeConst);
|
||||
return fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry);
|
||||
if (const_val->data.x_ptr.special == ConstPtrSpecialFunction) {
|
||||
assert(const_val->data.x_ptr.mut == ConstPtrMutComptimeConst);
|
||||
return fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry);
|
||||
} else if (const_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
|
||||
LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref;
|
||||
uint64_t addr = const_val->data.x_ptr.data.hard_coded_addr.addr;
|
||||
return LLVMConstIntToPtr(LLVMConstInt(usize_type_ref, addr, false), type_entry->type_ref);
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
case ZigTypeIdPointer:
|
||||
return gen_const_val_ptr(g, const_val, name);
|
||||
case ZigTypeIdErrorUnion:
|
||||
@@ -5819,13 +5835,29 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
|
||||
err_payload_value = gen_const_val(g, payload_val, "");
|
||||
make_unnamed_struct = is_llvm_value_unnamed_type(payload_val->type, err_payload_value);
|
||||
}
|
||||
LLVMValueRef fields[] = {
|
||||
err_tag_value,
|
||||
err_payload_value,
|
||||
};
|
||||
if (make_unnamed_struct) {
|
||||
return LLVMConstStruct(fields, 2, false);
|
||||
uint64_t payload_off = LLVMOffsetOfElement(g->target_data_ref, type_entry->type_ref, 1);
|
||||
uint64_t err_sz = LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(err_tag_value));
|
||||
unsigned pad_sz = payload_off - err_sz;
|
||||
if (pad_sz == 0) {
|
||||
LLVMValueRef fields[] = {
|
||||
err_tag_value,
|
||||
err_payload_value,
|
||||
};
|
||||
return LLVMConstStruct(fields, 2, false);
|
||||
} else {
|
||||
LLVMValueRef fields[] = {
|
||||
err_tag_value,
|
||||
LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), pad_sz)),
|
||||
err_payload_value,
|
||||
};
|
||||
return LLVMConstStruct(fields, 3, false);
|
||||
}
|
||||
} else {
|
||||
LLVMValueRef fields[] = {
|
||||
err_tag_value,
|
||||
err_payload_value,
|
||||
};
|
||||
return LLVMConstNamedStruct(type_entry->type_ref, fields, 2);
|
||||
}
|
||||
}
|
||||
@@ -5840,7 +5872,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
|
||||
case ZigTypeIdUndefined:
|
||||
case ZigTypeIdNull:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdOpaque:
|
||||
@@ -5958,13 +5989,6 @@ static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val,
|
||||
// TODO ^^ make an actual global variable
|
||||
}
|
||||
|
||||
static void ensure_cache_dir(CodeGen *g) {
|
||||
int err;
|
||||
if ((err = os_make_path(&g->cache_dir))) {
|
||||
zig_panic("unable to make cache dir: %s", err_str(err));
|
||||
}
|
||||
}
|
||||
|
||||
static void validate_inline_fns(CodeGen *g) {
|
||||
for (size_t i = 0; i < g->inline_fns.length; i += 1) {
|
||||
ZigFn *fn_entry = g->inline_fns.at(i);
|
||||
@@ -5979,8 +6003,6 @@ static void validate_inline_fns(CodeGen *g) {
|
||||
static void do_code_gen(CodeGen *g) {
|
||||
assert(!g->errors.length);
|
||||
|
||||
codegen_add_time_event(g, "Code Generation");
|
||||
|
||||
{
|
||||
// create debug type for error sets
|
||||
assert(g->err_enumerators.length == g->errors_by_index.length);
|
||||
@@ -6283,45 +6305,18 @@ static void do_code_gen(CodeGen *g) {
|
||||
char *error = nullptr;
|
||||
LLVMVerifyModule(g->module, LLVMAbortProcessAction, &error);
|
||||
#endif
|
||||
}
|
||||
|
||||
codegen_add_time_event(g, "LLVM Emit Output");
|
||||
|
||||
char *err_msg = nullptr;
|
||||
Buf *o_basename = buf_create_from_buf(g->root_out_name);
|
||||
|
||||
switch (g->emit_file_type) {
|
||||
case EmitFileTypeBinary:
|
||||
{
|
||||
const char *o_ext = target_o_file_ext(&g->zig_target);
|
||||
buf_append_str(o_basename, o_ext);
|
||||
break;
|
||||
}
|
||||
case EmitFileTypeAssembly:
|
||||
{
|
||||
const char *asm_ext = target_asm_file_ext(&g->zig_target);
|
||||
buf_append_str(o_basename, asm_ext);
|
||||
break;
|
||||
}
|
||||
case EmitFileTypeLLVMIr:
|
||||
{
|
||||
const char *llvm_ir_ext = target_llvm_ir_file_ext(&g->zig_target);
|
||||
buf_append_str(o_basename, llvm_ir_ext);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
Buf *output_path = buf_alloc();
|
||||
os_path_join(&g->cache_dir, o_basename, output_path);
|
||||
ensure_cache_dir(g);
|
||||
|
||||
static void zig_llvm_emit_output(CodeGen *g) {
|
||||
bool is_small = g->build_mode == BuildModeSmallRelease;
|
||||
|
||||
Buf *output_path = &g->o_file_output_path;
|
||||
char *err_msg = nullptr;
|
||||
switch (g->emit_file_type) {
|
||||
case EmitFileTypeBinary:
|
||||
if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
|
||||
ZigLLVM_EmitBinary, &err_msg, g->build_mode == BuildModeDebug, is_small))
|
||||
ZigLLVM_EmitBinary, &err_msg, g->build_mode == BuildModeDebug, is_small,
|
||||
g->enable_time_report))
|
||||
{
|
||||
zig_panic("unable to write object file %s: %s", buf_ptr(output_path), err_msg);
|
||||
}
|
||||
@@ -6331,22 +6326,22 @@ static void do_code_gen(CodeGen *g) {
|
||||
|
||||
case EmitFileTypeAssembly:
|
||||
if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
|
||||
ZigLLVM_EmitAssembly, &err_msg, g->build_mode == BuildModeDebug, is_small))
|
||||
ZigLLVM_EmitAssembly, &err_msg, g->build_mode == BuildModeDebug, is_small,
|
||||
g->enable_time_report))
|
||||
{
|
||||
zig_panic("unable to write assembly file %s: %s", buf_ptr(output_path), err_msg);
|
||||
}
|
||||
validate_inline_fns(g);
|
||||
g->link_objects.append(output_path);
|
||||
break;
|
||||
|
||||
case EmitFileTypeLLVMIr:
|
||||
if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
|
||||
ZigLLVM_EmitLLVMIr, &err_msg, g->build_mode == BuildModeDebug, is_small))
|
||||
ZigLLVM_EmitLLVMIr, &err_msg, g->build_mode == BuildModeDebug, is_small,
|
||||
g->enable_time_report))
|
||||
{
|
||||
zig_panic("unable to write llvm-ir file %s: %s", buf_ptr(output_path), err_msg);
|
||||
}
|
||||
validate_inline_fns(g);
|
||||
g->link_objects.append(output_path);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -6399,12 +6394,6 @@ static void define_builtin_types(CodeGen *g) {
|
||||
entry->zero_bits = true;
|
||||
g->builtin_types.entry_namespace = entry;
|
||||
}
|
||||
{
|
||||
ZigType *entry = new_type_table_entry(ZigTypeIdBlock);
|
||||
buf_init_from_str(&entry->name, "(block)");
|
||||
entry->zero_bits = true;
|
||||
g->builtin_types.entry_block = entry;
|
||||
}
|
||||
{
|
||||
ZigType *entry = new_type_table_entry(ZigTypeIdComptimeFloat);
|
||||
buf_init_from_str(&entry->name, "comptime_float");
|
||||
@@ -6651,7 +6640,7 @@ static void define_builtin_fns(CodeGen *g) {
|
||||
create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int
|
||||
create_builtin_fn(g, BuiltinFnIdSetCold, "setCold", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdSetRuntimeSafety, "setRuntimeSafety", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdPanic, "panic", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdPtrCast, "ptrCast", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdBitCast, "bitCast", 2);
|
||||
@@ -6685,6 +6674,7 @@ static void define_builtin_fns(CodeGen *g) {
|
||||
create_builtin_fn(g, BuiltinFnIdErrSetCast, "errSetCast", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdToBytes, "sliceToBytes", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdThis, "This", 0);
|
||||
}
|
||||
|
||||
static const char *bool_to_str(bool b) {
|
||||
@@ -6866,7 +6856,6 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
|
||||
" Union: Union,\n"
|
||||
" Fn: Fn,\n"
|
||||
" Namespace: void,\n"
|
||||
" Block: void,\n"
|
||||
" BoundFn: Fn,\n"
|
||||
" ArgTuple: void,\n"
|
||||
" Opaque: void,\n"
|
||||
@@ -7037,11 +7026,11 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
|
||||
{
|
||||
buf_appendf(contents,
|
||||
"pub const FloatMode = enum {\n"
|
||||
" Optimized,\n"
|
||||
" Strict,\n"
|
||||
" Optimized,\n"
|
||||
"};\n\n");
|
||||
assert(FloatModeOptimized == 0);
|
||||
assert(FloatModeStrict == 1);
|
||||
assert(FloatModeStrict == 0);
|
||||
assert(FloatModeOptimized == 1);
|
||||
}
|
||||
{
|
||||
buf_appendf(contents,
|
||||
@@ -7049,8 +7038,8 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
|
||||
" Big,\n"
|
||||
" Little,\n"
|
||||
"};\n\n");
|
||||
assert(FloatModeOptimized == 0);
|
||||
assert(FloatModeStrict == 1);
|
||||
//assert(EndianBig == 0);
|
||||
//assert(EndianLittle == 1);
|
||||
}
|
||||
{
|
||||
const char *endian_str = g->is_big_endian ? "Endian.Big" : "Endian.Little";
|
||||
@@ -7071,36 +7060,84 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
|
||||
return contents;
|
||||
}
|
||||
|
||||
static void define_builtin_compile_vars(CodeGen *g) {
|
||||
static Error define_builtin_compile_vars(CodeGen *g) {
|
||||
if (g->std_package == nullptr)
|
||||
return;
|
||||
return ErrorNone;
|
||||
|
||||
Error err;
|
||||
|
||||
Buf *manifest_dir = buf_alloc();
|
||||
os_path_join(get_stage1_cache_path(), buf_create_from_str("builtin"), manifest_dir);
|
||||
|
||||
CacheHash cache_hash;
|
||||
cache_init(&cache_hash, manifest_dir);
|
||||
|
||||
Buf *compiler_id;
|
||||
if ((err = get_compiler_id(&compiler_id)))
|
||||
return err;
|
||||
|
||||
// Only a few things affect builtin.zig
|
||||
cache_buf(&cache_hash, compiler_id);
|
||||
cache_int(&cache_hash, g->build_mode);
|
||||
cache_bool(&cache_hash, g->is_test_build);
|
||||
cache_int(&cache_hash, g->zig_target.arch.arch);
|
||||
cache_int(&cache_hash, g->zig_target.arch.sub_arch);
|
||||
cache_int(&cache_hash, g->zig_target.vendor);
|
||||
cache_int(&cache_hash, g->zig_target.os);
|
||||
cache_int(&cache_hash, g->zig_target.env_type);
|
||||
cache_int(&cache_hash, g->zig_target.oformat);
|
||||
cache_bool(&cache_hash, g->have_err_ret_tracing);
|
||||
cache_bool(&cache_hash, g->libc_link_lib != nullptr);
|
||||
|
||||
Buf digest = BUF_INIT;
|
||||
buf_resize(&digest, 0);
|
||||
if ((err = cache_hit(&cache_hash, &digest)))
|
||||
return err;
|
||||
|
||||
// We should always get a cache hit because there are no
|
||||
// files in the input hash.
|
||||
assert(buf_len(&digest) != 0);
|
||||
|
||||
Buf *this_dir = buf_alloc();
|
||||
os_path_join(manifest_dir, &digest, this_dir);
|
||||
|
||||
if ((err = os_make_path(this_dir)))
|
||||
return err;
|
||||
|
||||
const char *builtin_zig_basename = "builtin.zig";
|
||||
Buf *builtin_zig_path = buf_alloc();
|
||||
os_path_join(&g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
|
||||
os_path_join(this_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
|
||||
|
||||
Buf *contents = codegen_generate_builtin_source(g);
|
||||
ensure_cache_dir(g);
|
||||
os_write_file(builtin_zig_path, contents);
|
||||
|
||||
Buf *resolved_path = buf_alloc();
|
||||
Buf *resolve_paths[] = {builtin_zig_path};
|
||||
*resolved_path = os_path_resolve(resolve_paths, 1);
|
||||
bool hit;
|
||||
if ((err = os_file_exists(builtin_zig_path, &hit)))
|
||||
return err;
|
||||
Buf *contents;
|
||||
if (hit) {
|
||||
contents = buf_alloc();
|
||||
if ((err = os_fetch_file_path(builtin_zig_path, contents, false))) {
|
||||
fprintf(stderr, "Unable to open '%s': %s\n", buf_ptr(builtin_zig_path), err_str(err));
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
contents = codegen_generate_builtin_source(g);
|
||||
os_write_file(builtin_zig_path, contents);
|
||||
}
|
||||
|
||||
assert(g->root_package);
|
||||
assert(g->std_package);
|
||||
g->compile_var_package = new_package(buf_ptr(&g->cache_dir), builtin_zig_basename);
|
||||
g->compile_var_package = new_package(buf_ptr(this_dir), builtin_zig_basename);
|
||||
g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
|
||||
g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
|
||||
g->compile_var_import = add_source_file(g, g->compile_var_package, resolved_path, contents);
|
||||
g->compile_var_import = add_source_file(g, g->compile_var_package, builtin_zig_path, contents);
|
||||
scan_import(g, g->compile_var_import);
|
||||
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
static void init(CodeGen *g) {
|
||||
if (g->module)
|
||||
return;
|
||||
|
||||
|
||||
if (g->llvm_argv_len > 0) {
|
||||
const char **args = allocate_nonzero<const char *>(g->llvm_argv_len + 2);
|
||||
args[0] = "zig (LLVM option parsing)";
|
||||
@@ -7207,7 +7244,11 @@ static void init(CodeGen *g) {
|
||||
g->have_err_ret_tracing = g->build_mode != BuildModeFastRelease && g->build_mode != BuildModeSmallRelease;
|
||||
|
||||
define_builtin_fns(g);
|
||||
define_builtin_compile_vars(g);
|
||||
Error err;
|
||||
if ((err = define_builtin_compile_vars(g))) {
|
||||
fprintf(stderr, "Unable to create builtin.zig: %s\n", err_str(err));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void codegen_translate_c(CodeGen *g, Buf *full_path) {
|
||||
@@ -7253,8 +7294,8 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package
|
||||
Buf *resolved_path = buf_alloc();
|
||||
*resolved_path = os_path_resolve(resolve_paths, 1);
|
||||
Buf *import_code = buf_alloc();
|
||||
int err;
|
||||
if ((err = os_fetch_file_path(resolved_path, import_code, false))) {
|
||||
Error err;
|
||||
if ((err = file_fetch(g, resolved_path, import_code))) {
|
||||
zig_panic("unable to open '%s': %s\n", buf_ptr(&path_to_code_src), err_str(err));
|
||||
}
|
||||
|
||||
@@ -7327,23 +7368,32 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
|
||||
g->test_runner_import = add_special_code(g, g->test_runner_package, "test_runner.zig");
|
||||
}
|
||||
|
||||
static void gen_root_source(CodeGen *g) {
|
||||
static Buf *get_resolved_root_src_path(CodeGen *g) {
|
||||
// TODO memoize
|
||||
if (buf_len(&g->root_package->root_src_path) == 0)
|
||||
return;
|
||||
return nullptr;
|
||||
|
||||
codegen_add_time_event(g, "Semantic Analysis");
|
||||
|
||||
Buf *rel_full_path = buf_alloc();
|
||||
os_path_join(&g->root_package->root_src_dir, &g->root_package->root_src_path, rel_full_path);
|
||||
Buf rel_full_path = BUF_INIT;
|
||||
os_path_join(&g->root_package->root_src_dir, &g->root_package->root_src_path, &rel_full_path);
|
||||
|
||||
Buf *resolved_path = buf_alloc();
|
||||
Buf *resolve_paths[] = {rel_full_path};
|
||||
Buf *resolve_paths[] = {&rel_full_path};
|
||||
*resolved_path = os_path_resolve(resolve_paths, 1);
|
||||
|
||||
return resolved_path;
|
||||
}
|
||||
|
||||
static void gen_root_source(CodeGen *g) {
|
||||
Buf *resolved_path = get_resolved_root_src_path(g);
|
||||
if (resolved_path == nullptr)
|
||||
return;
|
||||
|
||||
Buf *source_code = buf_alloc();
|
||||
int err;
|
||||
if ((err = os_fetch_file_path(rel_full_path, source_code, true))) {
|
||||
fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(rel_full_path), err_str(err));
|
||||
// No need for using the caching system for this file fetch because it is handled
|
||||
// separately.
|
||||
if ((err = os_fetch_file_path(resolved_path, source_code, true))) {
|
||||
fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(resolved_path), err_str(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -7408,6 +7458,8 @@ static void gen_global_asm(CodeGen *g) {
|
||||
int err;
|
||||
for (size_t i = 0; i < g->assembly_files.length; i += 1) {
|
||||
Buf *asm_file = g->assembly_files.at(i);
|
||||
// No need to use the caching system for these fetches because they
|
||||
// are handled separately.
|
||||
if ((err = os_fetch_file_path(asm_file, &contents, false))) {
|
||||
zig_panic("Unable to read %s: %s", buf_ptr(asm_file), err_str(err));
|
||||
}
|
||||
@@ -7448,7 +7500,6 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, ZigType *type_e
|
||||
case ZigTypeIdUndefined:
|
||||
case ZigTypeIdNull:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdErrorUnion:
|
||||
@@ -7627,7 +7678,6 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu
|
||||
case ZigTypeIdMetaType:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdComptimeFloat:
|
||||
case ZigTypeIdComptimeInt:
|
||||
case ZigTypeIdUndefined:
|
||||
@@ -7671,19 +7721,11 @@ static Buf *preprocessor_mangle(Buf *src) {
|
||||
}
|
||||
|
||||
static void gen_h_file(CodeGen *g) {
|
||||
if (!g->want_h_file)
|
||||
return;
|
||||
|
||||
GenH gen_h_data = {0};
|
||||
GenH *gen_h = &gen_h_data;
|
||||
|
||||
codegen_add_time_event(g, "Generate .h");
|
||||
|
||||
assert(!g->is_test_build);
|
||||
|
||||
if (!g->out_h_path) {
|
||||
g->out_h_path = buf_sprintf("%s.h", buf_ptr(g->root_out_name));
|
||||
}
|
||||
assert(g->out_h_path != nullptr);
|
||||
|
||||
FILE *out_h = fopen(buf_ptr(g->out_h_path), "wb");
|
||||
if (!out_h)
|
||||
@@ -7788,7 +7830,6 @@ static void gen_h_file(CodeGen *g) {
|
||||
case ZigTypeIdErrorUnion:
|
||||
case ZigTypeIdErrorSet:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdOptional:
|
||||
@@ -7886,14 +7927,231 @@ void codegen_add_time_event(CodeGen *g, const char *name) {
|
||||
g->timing_events.append({os_get_time(), name});
|
||||
}
|
||||
|
||||
void codegen_build(CodeGen *g) {
|
||||
assert(g->out_type != OutTypeUnknown);
|
||||
init(g);
|
||||
static void add_cache_pkg(CodeGen *g, CacheHash *ch, PackageTableEntry *pkg) {
|
||||
if (buf_len(&pkg->root_src_path) == 0)
|
||||
return;
|
||||
|
||||
gen_global_asm(g);
|
||||
gen_root_source(g);
|
||||
do_code_gen(g);
|
||||
gen_h_file(g);
|
||||
Buf *rel_full_path = buf_alloc();
|
||||
os_path_join(&pkg->root_src_dir, &pkg->root_src_path, rel_full_path);
|
||||
cache_file(ch, rel_full_path);
|
||||
|
||||
auto it = pkg->package_table.entry_iterator();
|
||||
for (;;) {
|
||||
auto *entry = it.next();
|
||||
if (!entry)
|
||||
break;
|
||||
|
||||
cache_buf(ch, entry->key);
|
||||
add_cache_pkg(g, ch, entry->value);
|
||||
}
|
||||
}
|
||||
|
||||
// Called before init()
|
||||
static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
|
||||
Error err;
|
||||
|
||||
Buf *compiler_id;
|
||||
if ((err = get_compiler_id(&compiler_id)))
|
||||
return err;
|
||||
|
||||
CacheHash *ch = &g->cache_hash;
|
||||
cache_init(ch, manifest_dir);
|
||||
|
||||
add_cache_pkg(g, ch, g->root_package);
|
||||
if (g->linker_script != nullptr) {
|
||||
cache_file(ch, buf_create_from_str(g->linker_script));
|
||||
}
|
||||
cache_buf(ch, compiler_id);
|
||||
cache_buf(ch, g->root_out_name);
|
||||
cache_list_of_link_lib(ch, g->link_libs_list.items, g->link_libs_list.length);
|
||||
cache_list_of_buf(ch, g->darwin_frameworks.items, g->darwin_frameworks.length);
|
||||
cache_list_of_buf(ch, g->rpath_list.items, g->rpath_list.length);
|
||||
cache_list_of_buf(ch, g->forbidden_libs.items, g->forbidden_libs.length);
|
||||
cache_list_of_file(ch, g->link_objects.items, g->link_objects.length);
|
||||
cache_list_of_file(ch, g->assembly_files.items, g->assembly_files.length);
|
||||
cache_int(ch, g->emit_file_type);
|
||||
cache_int(ch, g->build_mode);
|
||||
cache_int(ch, g->out_type);
|
||||
cache_int(ch, g->zig_target.arch.arch);
|
||||
cache_int(ch, g->zig_target.arch.sub_arch);
|
||||
cache_int(ch, g->zig_target.vendor);
|
||||
cache_int(ch, g->zig_target.os);
|
||||
cache_int(ch, g->zig_target.env_type);
|
||||
cache_int(ch, g->zig_target.oformat);
|
||||
cache_bool(ch, g->is_static);
|
||||
cache_bool(ch, g->strip_debug_symbols);
|
||||
cache_bool(ch, g->is_test_build);
|
||||
cache_bool(ch, g->is_native_target);
|
||||
cache_bool(ch, g->windows_subsystem_windows);
|
||||
cache_bool(ch, g->windows_subsystem_console);
|
||||
cache_bool(ch, g->linker_rdynamic);
|
||||
cache_bool(ch, g->no_rosegment_workaround);
|
||||
cache_bool(ch, g->each_lib_rpath);
|
||||
cache_buf_opt(ch, g->mmacosx_version_min);
|
||||
cache_buf_opt(ch, g->mios_version_min);
|
||||
cache_usize(ch, g->version_major);
|
||||
cache_usize(ch, g->version_minor);
|
||||
cache_usize(ch, g->version_patch);
|
||||
cache_buf_opt(ch, g->test_filter);
|
||||
cache_buf_opt(ch, g->test_name_prefix);
|
||||
cache_list_of_str(ch, g->llvm_argv, g->llvm_argv_len);
|
||||
cache_list_of_str(ch, g->clang_argv, g->clang_argv_len);
|
||||
cache_list_of_str(ch, g->lib_dirs.items, g->lib_dirs.length);
|
||||
|
||||
buf_resize(digest, 0);
|
||||
if ((err = cache_hit(ch, digest)))
|
||||
return err;
|
||||
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
static void resolve_out_paths(CodeGen *g) {
|
||||
Buf *o_basename = buf_create_from_buf(g->root_out_name);
|
||||
|
||||
switch (g->emit_file_type) {
|
||||
case EmitFileTypeBinary:
|
||||
{
|
||||
const char *o_ext = target_o_file_ext(&g->zig_target);
|
||||
buf_append_str(o_basename, o_ext);
|
||||
break;
|
||||
}
|
||||
case EmitFileTypeAssembly:
|
||||
{
|
||||
const char *asm_ext = target_asm_file_ext(&g->zig_target);
|
||||
buf_append_str(o_basename, asm_ext);
|
||||
break;
|
||||
}
|
||||
case EmitFileTypeLLVMIr:
|
||||
{
|
||||
const char *llvm_ir_ext = target_llvm_ir_file_ext(&g->zig_target);
|
||||
buf_append_str(o_basename, llvm_ir_ext);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
if (g->enable_cache || g->out_type != OutTypeObj) {
|
||||
os_path_join(&g->artifact_dir, o_basename, &g->o_file_output_path);
|
||||
} else if (g->wanted_output_file_path != nullptr && g->out_type == OutTypeObj) {
|
||||
buf_init_from_buf(&g->o_file_output_path, g->wanted_output_file_path);
|
||||
} else {
|
||||
buf_init_from_buf(&g->o_file_output_path, o_basename);
|
||||
}
|
||||
|
||||
if (g->out_type == OutTypeObj) {
|
||||
buf_init_from_buf(&g->output_file_path, &g->o_file_output_path);
|
||||
} else if (g->out_type == OutTypeExe) {
|
||||
if (!g->enable_cache && g->wanted_output_file_path != nullptr) {
|
||||
buf_init_from_buf(&g->output_file_path, g->wanted_output_file_path);
|
||||
} else {
|
||||
assert(g->root_out_name);
|
||||
|
||||
Buf basename = BUF_INIT;
|
||||
buf_init_from_buf(&basename, g->root_out_name);
|
||||
buf_append_str(&basename, target_exe_file_ext(&g->zig_target));
|
||||
if (g->enable_cache || g->is_test_build) {
|
||||
os_path_join(&g->artifact_dir, &basename, &g->output_file_path);
|
||||
} else {
|
||||
buf_init_from_buf(&g->output_file_path, &basename);
|
||||
}
|
||||
}
|
||||
} else if (g->out_type == OutTypeLib) {
|
||||
if (!g->enable_cache && g->wanted_output_file_path != nullptr) {
|
||||
buf_init_from_buf(&g->output_file_path, g->wanted_output_file_path);
|
||||
} else {
|
||||
Buf basename = BUF_INIT;
|
||||
buf_init_from_buf(&basename, g->root_out_name);
|
||||
buf_append_str(&basename, target_lib_file_ext(&g->zig_target, g->is_static,
|
||||
g->version_major, g->version_minor, g->version_patch));
|
||||
if (g->enable_cache) {
|
||||
os_path_join(&g->artifact_dir, &basename, &g->output_file_path);
|
||||
} else {
|
||||
buf_init_from_buf(&g->output_file_path, &basename);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
if (g->want_h_file && !g->out_h_path) {
|
||||
assert(g->root_out_name);
|
||||
Buf *h_basename = buf_sprintf("%s.h", buf_ptr(g->root_out_name));
|
||||
if (g->enable_cache) {
|
||||
g->out_h_path = buf_alloc();
|
||||
os_path_join(&g->artifact_dir, h_basename, g->out_h_path);
|
||||
} else {
|
||||
g->out_h_path = h_basename;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void codegen_build_and_link(CodeGen *g) {
|
||||
Error err;
|
||||
assert(g->out_type != OutTypeUnknown);
|
||||
|
||||
Buf *stage1_dir = get_stage1_cache_path();
|
||||
Buf *artifact_dir = buf_alloc();
|
||||
Buf digest = BUF_INIT;
|
||||
if (g->enable_cache) {
|
||||
codegen_add_time_event(g, "Check Cache");
|
||||
|
||||
Buf *manifest_dir = buf_alloc();
|
||||
os_path_join(stage1_dir, buf_create_from_str("build"), manifest_dir);
|
||||
|
||||
if ((err = check_cache(g, manifest_dir, &digest))) {
|
||||
fprintf(stderr, "Unable to check cache: %s\n", err_str(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
os_path_join(stage1_dir, buf_create_from_str("artifact"), artifact_dir);
|
||||
}
|
||||
|
||||
if (g->enable_cache && buf_len(&digest) != 0) {
|
||||
os_path_join(artifact_dir, &digest, &g->artifact_dir);
|
||||
resolve_out_paths(g);
|
||||
} else {
|
||||
init(g);
|
||||
|
||||
codegen_add_time_event(g, "Semantic Analysis");
|
||||
|
||||
gen_global_asm(g);
|
||||
gen_root_source(g);
|
||||
|
||||
if (g->enable_cache) {
|
||||
if ((err = cache_final(&g->cache_hash, &digest))) {
|
||||
fprintf(stderr, "Unable to finalize cache hash: %s\n", err_str(err));
|
||||
exit(1);
|
||||
}
|
||||
os_path_join(artifact_dir, &digest, &g->artifact_dir);
|
||||
} else {
|
||||
buf_init_from_buf(&g->artifact_dir, &g->cache_dir);
|
||||
}
|
||||
if ((err = os_make_path(&g->artifact_dir))) {
|
||||
fprintf(stderr, "Unable to create artifact directory: %s\n", err_str(err));
|
||||
exit(1);
|
||||
}
|
||||
resolve_out_paths(g);
|
||||
|
||||
codegen_add_time_event(g, "Code Generation");
|
||||
do_code_gen(g);
|
||||
codegen_add_time_event(g, "LLVM Emit Output");
|
||||
zig_llvm_emit_output(g);
|
||||
|
||||
if (g->want_h_file) {
|
||||
codegen_add_time_event(g, "Generate .h");
|
||||
gen_h_file(g);
|
||||
}
|
||||
if (g->out_type != OutTypeObj) {
|
||||
codegen_link(g);
|
||||
}
|
||||
}
|
||||
|
||||
if (g->enable_cache) {
|
||||
cache_release(&g->cache_hash);
|
||||
}
|
||||
codegen_add_time_event(g, "Done");
|
||||
}
|
||||
|
||||
PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path) {
|
||||
|
||||
+3
-3
@@ -16,7 +16,6 @@
|
||||
|
||||
CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode,
|
||||
Buf *zig_lib_dir);
|
||||
void codegen_destroy(CodeGen *codegen);
|
||||
|
||||
void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len);
|
||||
void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len);
|
||||
@@ -47,11 +46,12 @@ void codegen_set_linker_script(CodeGen *g, const char *linker_script);
|
||||
void codegen_set_test_filter(CodeGen *g, Buf *filter);
|
||||
void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix);
|
||||
void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch);
|
||||
void codegen_set_cache_dir(CodeGen *g, Buf cache_dir);
|
||||
void codegen_set_output_h_path(CodeGen *g, Buf *h_path);
|
||||
void codegen_set_output_path(CodeGen *g, Buf *path);
|
||||
void codegen_add_time_event(CodeGen *g, const char *name);
|
||||
void codegen_print_timing_report(CodeGen *g, FILE *f);
|
||||
void codegen_build(CodeGen *g);
|
||||
void codegen_link(CodeGen *g);
|
||||
void codegen_build_and_link(CodeGen *g);
|
||||
|
||||
PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path);
|
||||
void codegen_add_assembly(CodeGen *g, Buf *path);
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
#include "cache_hash.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static Buf saved_compiler_id = BUF_INIT;
|
||||
static Buf saved_app_data_dir = BUF_INIT;
|
||||
static Buf saved_stage1_path = BUF_INIT;
|
||||
|
||||
Buf *get_stage1_cache_path() {
|
||||
if (saved_stage1_path.list.length != 0) {
|
||||
return &saved_stage1_path;
|
||||
}
|
||||
Error err;
|
||||
if ((err = os_get_app_data_dir(&saved_app_data_dir, "zig"))) {
|
||||
fprintf(stderr, "Unable to get app data dir: %s\n", err_str(err));
|
||||
exit(1);
|
||||
}
|
||||
os_path_join(&saved_app_data_dir, buf_create_from_str("stage1"), &saved_stage1_path);
|
||||
return &saved_stage1_path;
|
||||
}
|
||||
|
||||
Error get_compiler_id(Buf **result) {
|
||||
if (saved_compiler_id.list.length != 0) {
|
||||
*result = &saved_compiler_id;
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
Error err;
|
||||
Buf *stage1_dir = get_stage1_cache_path();
|
||||
Buf *manifest_dir = buf_alloc();
|
||||
os_path_join(stage1_dir, buf_create_from_str("exe"), manifest_dir);
|
||||
|
||||
CacheHash cache_hash;
|
||||
CacheHash *ch = &cache_hash;
|
||||
cache_init(ch, manifest_dir);
|
||||
Buf self_exe_path = BUF_INIT;
|
||||
if ((err = os_self_exe_path(&self_exe_path)))
|
||||
return err;
|
||||
|
||||
cache_file(ch, &self_exe_path);
|
||||
|
||||
buf_resize(&saved_compiler_id, 0);
|
||||
if ((err = cache_hit(ch, &saved_compiler_id)))
|
||||
return err;
|
||||
if (buf_len(&saved_compiler_id) != 0) {
|
||||
cache_release(ch);
|
||||
*result = &saved_compiler_id;
|
||||
return ErrorNone;
|
||||
}
|
||||
ZigList<Buf *> lib_paths = {};
|
||||
if ((err = os_self_exe_shared_libs(lib_paths)))
|
||||
return err;
|
||||
for (size_t i = 0; i < lib_paths.length; i += 1) {
|
||||
Buf *lib_path = lib_paths.at(i);
|
||||
if ((err = cache_add_file(ch, lib_path)))
|
||||
return err;
|
||||
}
|
||||
if ((err = cache_final(ch, &saved_compiler_id)))
|
||||
return err;
|
||||
|
||||
cache_release(ch);
|
||||
|
||||
*result = &saved_compiler_id;
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Andrew Kelley
|
||||
*
|
||||
* This file is part of zig, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#ifndef ZIG_COMPILER_HPP
|
||||
#define ZIG_COMPILER_HPP
|
||||
|
||||
#include "buffer.hpp"
|
||||
#include "error.hpp"
|
||||
|
||||
Buf *get_stage1_cache_path();
|
||||
Error get_compiler_id(Buf **result);
|
||||
|
||||
#endif
|
||||
@@ -27,6 +27,11 @@ const char *err_str(int err) {
|
||||
case ErrorNegativeDenominator: return "negative denominator";
|
||||
case ErrorShiftedOutOneBits: return "exact shift shifted out one bits";
|
||||
case ErrorCCompileErrors: return "C compile errors";
|
||||
case ErrorEndOfFile: return "end of file";
|
||||
case ErrorIsDir: return "is directory";
|
||||
case ErrorUnsupportedOperatingSystem: return "unsupported operating system";
|
||||
case ErrorSharingViolation: return "sharing violation";
|
||||
case ErrorPipeBusy: return "pipe busy";
|
||||
}
|
||||
return "(invalid error)";
|
||||
}
|
||||
|
||||
@@ -27,6 +27,11 @@ enum Error {
|
||||
ErrorNegativeDenominator,
|
||||
ErrorShiftedOutOneBits,
|
||||
ErrorCCompileErrors,
|
||||
ErrorEndOfFile,
|
||||
ErrorIsDir,
|
||||
ErrorUnsupportedOperatingSystem,
|
||||
ErrorSharingViolation,
|
||||
ErrorPipeBusy,
|
||||
};
|
||||
|
||||
const char *err_str(int err);
|
||||
|
||||
+353
-234
@@ -40,6 +40,7 @@ struct IrAnalyze {
|
||||
|
||||
enum ConstCastResultId {
|
||||
ConstCastResultIdOk,
|
||||
ConstCastResultIdInvalid,
|
||||
ConstCastResultIdErrSet,
|
||||
ConstCastResultIdErrSetGlobal,
|
||||
ConstCastResultIdPointerChild,
|
||||
@@ -1029,12 +1030,6 @@ static IrInstruction *ir_create_const_fn(IrBuilder *irb, Scope *scope, AstNode *
|
||||
return &const_instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_const_fn(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigFn *fn_entry) {
|
||||
IrInstruction *instruction = ir_create_const_fn(irb, scope, source_node, fn_entry);
|
||||
ir_instruction_append(irb->current_basic_block, instruction);
|
||||
return instruction;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_const_import(IrBuilder *irb, Scope *scope, AstNode *source_node, ImportTableEntry *import) {
|
||||
IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
|
||||
const_instruction->base.value.type = irb->codegen->builtin_types.entry_namespace;
|
||||
@@ -1043,16 +1038,6 @@ static IrInstruction *ir_build_const_import(IrBuilder *irb, Scope *scope, AstNod
|
||||
return &const_instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_const_scope(IrBuilder *irb, Scope *parent_scope, AstNode *source_node,
|
||||
Scope *target_scope)
|
||||
{
|
||||
IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, parent_scope, source_node);
|
||||
const_instruction->base.value.type = irb->codegen->builtin_types.entry_block;
|
||||
const_instruction->base.value.special = ConstValSpecialStatic;
|
||||
const_instruction->base.value.data.x_block = target_scope;
|
||||
return &const_instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_const_bool(IrBuilder *irb, Scope *scope, AstNode *source_node, bool value) {
|
||||
IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
|
||||
const_instruction->base.value.type = irb->codegen->builtin_types.entry_bool;
|
||||
@@ -1577,13 +1562,11 @@ static IrInstruction *ir_build_set_runtime_safety(IrBuilder *irb, Scope *scope,
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_set_float_mode(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
IrInstruction *scope_value, IrInstruction *mode_value)
|
||||
IrInstruction *mode_value)
|
||||
{
|
||||
IrInstructionSetFloatMode *instruction = ir_build_instruction<IrInstructionSetFloatMode>(irb, scope, source_node);
|
||||
instruction->scope_value = scope_value;
|
||||
instruction->mode_value = mode_value;
|
||||
|
||||
ir_ref_instruction(scope_value, irb->current_basic_block);
|
||||
ir_ref_instruction(mode_value, irb->current_basic_block);
|
||||
|
||||
return &instruction->base;
|
||||
@@ -3894,6 +3877,21 @@ static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode *
|
||||
return ir_build_overflow_op(irb, scope, node, op, type_value, op1, op2, result_ptr, nullptr);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_this(IrBuilder *irb, Scope *orig_scope, AstNode *node) {
|
||||
for (Scope *it_scope = orig_scope; it_scope != nullptr; it_scope = it_scope->parent) {
|
||||
if (it_scope->id == ScopeIdDecls) {
|
||||
ScopeDecls *decls_scope = (ScopeDecls *)it_scope;
|
||||
ZigType *container_type = decls_scope->container_type;
|
||||
if (container_type != nullptr) {
|
||||
return ir_build_const_type(irb, orig_scope, node, container_type);
|
||||
} else {
|
||||
return ir_build_const_import(irb, orig_scope, node, decls_scope->import);
|
||||
}
|
||||
}
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
|
||||
assert(node->type == NodeTypeFnCallExpr);
|
||||
|
||||
@@ -3959,12 +3957,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
|
||||
if (arg0_value == irb->codegen->invalid_instruction)
|
||||
return arg0_value;
|
||||
|
||||
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
|
||||
IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
|
||||
if (arg1_value == irb->codegen->invalid_instruction)
|
||||
return arg1_value;
|
||||
|
||||
IrInstruction *set_float_mode = ir_build_set_float_mode(irb, scope, node, arg0_value, arg1_value);
|
||||
IrInstruction *set_float_mode = ir_build_set_float_mode(irb, scope, node, arg0_value);
|
||||
return ir_lval_wrap(irb, scope, set_float_mode, lval);
|
||||
}
|
||||
case BuiltinFnIdSizeof:
|
||||
@@ -4837,6 +4830,11 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
|
||||
IrInstruction *opaque_type = ir_build_opaque_type(irb, scope, node);
|
||||
return ir_lval_wrap(irb, scope, opaque_type, lval);
|
||||
}
|
||||
case BuiltinFnIdThis:
|
||||
{
|
||||
IrInstruction *this_inst = ir_gen_this(irb, scope, node);
|
||||
return ir_lval_wrap(irb, scope, this_inst, lval);
|
||||
}
|
||||
case BuiltinFnIdSetAlignStack:
|
||||
{
|
||||
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
||||
@@ -5688,33 +5686,6 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
|
||||
return ir_build_phi(irb, parent_scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_this_literal(IrBuilder *irb, Scope *scope, AstNode *node) {
|
||||
assert(node->type == NodeTypeThisLiteral);
|
||||
|
||||
if (!scope->parent)
|
||||
return ir_build_const_import(irb, scope, node, node->owner);
|
||||
|
||||
ZigFn *fn_entry = scope_get_fn_if_root(scope);
|
||||
if (fn_entry)
|
||||
return ir_build_const_fn(irb, scope, node, fn_entry);
|
||||
|
||||
while (scope->id != ScopeIdBlock && scope->id != ScopeIdDecls) {
|
||||
scope = scope->parent;
|
||||
}
|
||||
|
||||
if (scope->id == ScopeIdDecls) {
|
||||
ScopeDecls *decls_scope = (ScopeDecls *)scope;
|
||||
ZigType *container_type = decls_scope->container_type;
|
||||
assert(container_type);
|
||||
return ir_build_const_type(irb, scope, node, container_type);
|
||||
}
|
||||
|
||||
if (scope->id == ScopeIdBlock)
|
||||
return ir_build_const_scope(irb, scope, node, scope);
|
||||
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_bool_literal(IrBuilder *irb, Scope *scope, AstNode *node) {
|
||||
assert(node->type == NodeTypeBoolLiteral);
|
||||
return ir_build_const_bool(irb, scope, node, node->data.bool_literal.value);
|
||||
@@ -7292,8 +7263,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
|
||||
|
||||
return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
|
||||
}
|
||||
case NodeTypeThisLiteral:
|
||||
return ir_lval_wrap(irb, scope, ir_gen_this_literal(irb, scope, node), lval);
|
||||
case NodeTypeBoolLiteral:
|
||||
return ir_lval_wrap(irb, scope, ir_gen_bool_literal(irb, scope, node), lval);
|
||||
case NodeTypeArrayType:
|
||||
@@ -7522,8 +7491,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
|
||||
if (type_has_bits(return_type)) {
|
||||
IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
|
||||
get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
|
||||
false, false, PtrLenUnknown, get_abi_alignment(irb->codegen, irb->codegen->builtin_types.entry_u8),
|
||||
0, 0));
|
||||
false, false, PtrLenUnknown, 0, 0, 0));
|
||||
IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr);
|
||||
IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, result_ptr);
|
||||
IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len,
|
||||
@@ -7576,8 +7544,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
|
||||
IrInstruction *coro_mem_ptr_maybe = ir_build_coro_free(irb, scope, node, coro_id, irb->exec->coro_handle);
|
||||
IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
|
||||
get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
|
||||
false, false, PtrLenUnknown, get_abi_alignment(irb->codegen, irb->codegen->builtin_types.entry_u8),
|
||||
0, 0));
|
||||
false, false, PtrLenUnknown, 0, 0, 0));
|
||||
IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe);
|
||||
IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false);
|
||||
IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var);
|
||||
@@ -8548,6 +8515,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
|
||||
ConstCastOnly result = {};
|
||||
result.id = ConstCastResultIdOk;
|
||||
|
||||
Error err;
|
||||
|
||||
if (wanted_type == actual_type)
|
||||
return result;
|
||||
|
||||
@@ -8560,6 +8529,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
|
||||
{
|
||||
ConstCastOnly child = types_match_const_cast_only(ira,
|
||||
wanted_type->data.maybe.child_type, actual_type, source_node, wanted_is_mutable);
|
||||
if (child.id == ConstCastResultIdInvalid)
|
||||
return child;
|
||||
if (child.id != ConstCastResultIdOk) {
|
||||
result.id = ConstCastResultIdNullWrapPtr;
|
||||
result.data.null_wrap_ptr_child = allocate_nonzero<ConstCastOnly>(1);
|
||||
@@ -8576,7 +8547,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
|
||||
(!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) &&
|
||||
(!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile))
|
||||
{
|
||||
assert(actual_type->data.pointer.alignment >= wanted_type->data.pointer.alignment);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -8584,6 +8554,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
|
||||
if (wanted_type->id == ZigTypeIdPointer && actual_type->id == ZigTypeIdPointer) {
|
||||
ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
|
||||
actual_type->data.pointer.child_type, source_node, !wanted_type->data.pointer.is_const);
|
||||
if (child.id == ConstCastResultIdInvalid)
|
||||
return child;
|
||||
if (child.id != ConstCastResultIdOk) {
|
||||
result.id = ConstCastResultIdPointerChild;
|
||||
result.data.pointer_mismatch = allocate_nonzero<ConstCastPointerMismatch>(1);
|
||||
@@ -8592,12 +8564,20 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
|
||||
result.data.pointer_mismatch->actual_child = actual_type->data.pointer.child_type;
|
||||
return result;
|
||||
}
|
||||
if ((err = type_resolve(g, actual_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) {
|
||||
result.id = ConstCastResultIdInvalid;
|
||||
return result;
|
||||
}
|
||||
if ((err = type_resolve(g, wanted_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) {
|
||||
result.id = ConstCastResultIdInvalid;
|
||||
return result;
|
||||
}
|
||||
if ((actual_type->data.pointer.ptr_len == wanted_type->data.pointer.ptr_len) &&
|
||||
(!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) &&
|
||||
(!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile) &&
|
||||
actual_type->data.pointer.bit_offset == wanted_type->data.pointer.bit_offset &&
|
||||
actual_type->data.pointer.unaligned_bit_count == wanted_type->data.pointer.unaligned_bit_count &&
|
||||
actual_type->data.pointer.alignment >= wanted_type->data.pointer.alignment)
|
||||
get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, wanted_type))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
@@ -8607,14 +8587,24 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
|
||||
if (is_slice(wanted_type) && is_slice(actual_type)) {
|
||||
ZigType *actual_ptr_type = actual_type->data.structure.fields[slice_ptr_index].type_entry;
|
||||
ZigType *wanted_ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
|
||||
if ((err = type_resolve(g, actual_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) {
|
||||
result.id = ConstCastResultIdInvalid;
|
||||
return result;
|
||||
}
|
||||
if ((err = type_resolve(g, wanted_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) {
|
||||
result.id = ConstCastResultIdInvalid;
|
||||
return result;
|
||||
}
|
||||
if ((!actual_ptr_type->data.pointer.is_const || wanted_ptr_type->data.pointer.is_const) &&
|
||||
(!actual_ptr_type->data.pointer.is_volatile || wanted_ptr_type->data.pointer.is_volatile) &&
|
||||
actual_ptr_type->data.pointer.bit_offset == wanted_ptr_type->data.pointer.bit_offset &&
|
||||
actual_ptr_type->data.pointer.unaligned_bit_count == wanted_ptr_type->data.pointer.unaligned_bit_count &&
|
||||
actual_ptr_type->data.pointer.alignment >= wanted_ptr_type->data.pointer.alignment)
|
||||
get_ptr_align(g, actual_ptr_type) >= get_ptr_align(g, wanted_ptr_type))
|
||||
{
|
||||
ConstCastOnly child = types_match_const_cast_only(ira, wanted_ptr_type->data.pointer.child_type,
|
||||
actual_ptr_type->data.pointer.child_type, source_node, !wanted_ptr_type->data.pointer.is_const);
|
||||
if (child.id == ConstCastResultIdInvalid)
|
||||
return child;
|
||||
if (child.id != ConstCastResultIdOk) {
|
||||
result.id = ConstCastResultIdSliceChild;
|
||||
result.data.slice_mismatch = allocate_nonzero<ConstCastSliceMismatch>(1);
|
||||
@@ -8630,6 +8620,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
|
||||
if (wanted_type->id == ZigTypeIdOptional && actual_type->id == ZigTypeIdOptional) {
|
||||
ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.maybe.child_type,
|
||||
actual_type->data.maybe.child_type, source_node, wanted_is_mutable);
|
||||
if (child.id == ConstCastResultIdInvalid)
|
||||
return child;
|
||||
if (child.id != ConstCastResultIdOk) {
|
||||
result.id = ConstCastResultIdOptionalChild;
|
||||
result.data.optional = allocate_nonzero<ConstCastOptionalMismatch>(1);
|
||||
@@ -8644,6 +8636,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
|
||||
if (wanted_type->id == ZigTypeIdErrorUnion && actual_type->id == ZigTypeIdErrorUnion) {
|
||||
ConstCastOnly payload_child = types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type,
|
||||
actual_type->data.error_union.payload_type, source_node, wanted_is_mutable);
|
||||
if (payload_child.id == ConstCastResultIdInvalid)
|
||||
return payload_child;
|
||||
if (payload_child.id != ConstCastResultIdOk) {
|
||||
result.id = ConstCastResultIdErrorUnionPayload;
|
||||
result.data.error_union_payload = allocate_nonzero<ConstCastErrUnionPayloadMismatch>(1);
|
||||
@@ -8654,6 +8648,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
|
||||
}
|
||||
ConstCastOnly error_set_child = types_match_const_cast_only(ira, wanted_type->data.error_union.err_set_type,
|
||||
actual_type->data.error_union.err_set_type, source_node, wanted_is_mutable);
|
||||
if (error_set_child.id == ConstCastResultIdInvalid)
|
||||
return error_set_child;
|
||||
if (error_set_child.id != ConstCastResultIdOk) {
|
||||
result.id = ConstCastResultIdErrorUnionErrorSet;
|
||||
result.data.error_union_error_set = allocate_nonzero<ConstCastErrUnionErrSetMismatch>(1);
|
||||
@@ -8741,6 +8737,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
|
||||
{
|
||||
ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.fn.fn_type_id.return_type,
|
||||
actual_type->data.fn.fn_type_id.return_type, source_node, false);
|
||||
if (child.id == ConstCastResultIdInvalid)
|
||||
return child;
|
||||
if (child.id != ConstCastResultIdOk) {
|
||||
result.id = ConstCastResultIdFnReturnType;
|
||||
result.data.return_type = allocate_nonzero<ConstCastOnly>(1);
|
||||
@@ -8753,6 +8751,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
|
||||
actual_type->data.fn.fn_type_id.async_allocator_type,
|
||||
wanted_type->data.fn.fn_type_id.async_allocator_type,
|
||||
source_node, false);
|
||||
if (child.id == ConstCastResultIdInvalid)
|
||||
return child;
|
||||
if (child.id != ConstCastResultIdOk) {
|
||||
result.id = ConstCastResultIdAsyncAllocatorType;
|
||||
result.data.async_allocator_type = allocate_nonzero<ConstCastOnly>(1);
|
||||
@@ -8777,6 +8777,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
|
||||
|
||||
ConstCastOnly arg_child = types_match_const_cast_only(ira, actual_param_info->type,
|
||||
expected_param_info->type, source_node, false);
|
||||
if (arg_child.id == ConstCastResultIdInvalid)
|
||||
return arg_child;
|
||||
if (arg_child.id != ConstCastResultIdOk) {
|
||||
result.id = ConstCastResultIdFnArg;
|
||||
result.data.fn_arg.arg_index = i;
|
||||
@@ -9270,7 +9272,7 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
|
||||
if (prev_type->id == ZigTypeIdEnum && cur_type->id == ZigTypeIdUnion &&
|
||||
(cur_type->data.unionation.decl_node->data.container_decl.auto_enum || cur_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr))
|
||||
{
|
||||
if ((err = type_ensure_zero_bits_known(ira->codegen, cur_type)))
|
||||
if ((err = type_resolve(ira->codegen, cur_type, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
if (cur_type->data.unionation.tag_type == prev_type) {
|
||||
continue;
|
||||
@@ -9280,7 +9282,7 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
|
||||
if (cur_type->id == ZigTypeIdEnum && prev_type->id == ZigTypeIdUnion &&
|
||||
(prev_type->data.unionation.decl_node->data.container_decl.auto_enum || prev_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr))
|
||||
{
|
||||
if ((err = type_ensure_zero_bits_known(ira->codegen, prev_type)))
|
||||
if ((err = type_resolve(ira->codegen, prev_type, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
if (prev_type->data.unionation.tag_type == cur_type) {
|
||||
prev_inst = cur_inst;
|
||||
@@ -9306,8 +9308,7 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
|
||||
ZigType *ptr_type = get_pointer_to_type_extra(
|
||||
ira->codegen, prev_inst->value.type->data.array.child_type,
|
||||
true, false, PtrLenUnknown,
|
||||
get_abi_alignment(ira->codegen, prev_inst->value.type->data.array.child_type),
|
||||
0, 0);
|
||||
0, 0, 0);
|
||||
ZigType *slice_type = get_slice_type(ira->codegen, ptr_type);
|
||||
if (err_set_type != nullptr) {
|
||||
return get_error_union_type(ira->codegen, err_set_type, slice_type);
|
||||
@@ -9504,7 +9505,16 @@ static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira,
|
||||
IrInstruction *value, ZigType *wanted_type)
|
||||
{
|
||||
assert(value->value.type->id == ZigTypeIdPointer);
|
||||
wanted_type = adjust_ptr_align(ira->codegen, wanted_type, value->value.type->data.pointer.alignment);
|
||||
|
||||
Error err;
|
||||
|
||||
if ((err = type_resolve(ira->codegen, value->value.type->data.pointer.child_type,
|
||||
ResolveStatusAlignmentKnown)))
|
||||
{
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
wanted_type = adjust_ptr_align(ira->codegen, wanted_type, get_ptr_align(ira->codegen, value->value.type));
|
||||
|
||||
if (instr_is_comptime(value)) {
|
||||
ConstExprValue *pointee = ir_const_ptr_pointee(ira, &value->value, source_instr->source_node);
|
||||
@@ -9532,7 +9542,15 @@ static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira,
|
||||
static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruction *source_instr,
|
||||
IrInstruction *value, ZigType *wanted_type)
|
||||
{
|
||||
wanted_type = adjust_slice_align(ira->codegen, wanted_type, value->value.type->data.pointer.alignment);
|
||||
Error err;
|
||||
|
||||
if ((err = type_resolve(ira->codegen, value->value.type->data.pointer.child_type,
|
||||
ResolveStatusAlignmentKnown)))
|
||||
{
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
wanted_type = adjust_slice_align(ira->codegen, wanted_type, get_ptr_align(ira->codegen, value->value.type));
|
||||
|
||||
if (instr_is_comptime(value)) {
|
||||
ConstExprValue *pointee = ir_const_ptr_pointee(ira, &value->value, source_instr->source_node);
|
||||
@@ -9719,8 +9737,7 @@ static ZigType *ir_analyze_const_ptr(IrAnalyze *ira, IrInstruction *instruction,
|
||||
ConstPtrMut ptr_mut, bool ptr_is_const, bool ptr_is_volatile)
|
||||
{
|
||||
IrInstruction *const_instr = ir_get_const_ptr(ira, instruction, pointee,
|
||||
pointee_type, ptr_mut, ptr_is_const, ptr_is_volatile,
|
||||
get_abi_alignment(ira->codegen, pointee_type));
|
||||
pointee_type, ptr_mut, ptr_is_const, ptr_is_volatile, 0);
|
||||
ir_link_new_instruction(const_instr, instruction);
|
||||
return const_instr->value.type;
|
||||
}
|
||||
@@ -10037,20 +10054,24 @@ static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *so
|
||||
static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *value,
|
||||
bool is_const, bool is_volatile)
|
||||
{
|
||||
Error err;
|
||||
|
||||
if (type_is_invalid(value->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
if ((err = type_resolve(ira->codegen, value->value.type, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
if (instr_is_comptime(value)) {
|
||||
ConstExprValue *val = ir_resolve_const(ira, value, UndefOk);
|
||||
if (!val)
|
||||
return ira->codegen->invalid_instruction;
|
||||
return ir_get_const_ptr(ira, source_instruction, val, value->value.type,
|
||||
ConstPtrMutComptimeConst, is_const, is_volatile,
|
||||
get_abi_alignment(ira->codegen, value->value.type));
|
||||
ConstPtrMutComptimeConst, is_const, is_volatile, 0);
|
||||
}
|
||||
|
||||
ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, value->value.type,
|
||||
is_const, is_volatile, PtrLenSingle, get_abi_alignment(ira->codegen, value->value.type), 0, 0);
|
||||
is_const, is_volatile, PtrLenSingle, 0, 0, 0);
|
||||
IrInstruction *new_instruction = ir_build_ref(&ira->new_irb, source_instruction->scope,
|
||||
source_instruction->source_node, value, is_const, is_volatile);
|
||||
new_instruction->value.type = ptr_type;
|
||||
@@ -10113,7 +10134,7 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour
|
||||
IrInstruction *target, ZigType *wanted_type)
|
||||
{
|
||||
Error err;
|
||||
assert(wanted_type->id == ZigTypeIdInt);
|
||||
assert(wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdComptimeInt);
|
||||
|
||||
ZigType *actual_type = target->value.type;
|
||||
if ((err = ensure_complete_type(ira->codegen, actual_type)))
|
||||
@@ -10139,6 +10160,18 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour
|
||||
return result;
|
||||
}
|
||||
|
||||
// If there is only one possible tag, then we know at comptime what it is.
|
||||
if (actual_type->data.enumeration.layout == ContainerLayoutAuto &&
|
||||
actual_type->data.enumeration.src_field_count == 1)
|
||||
{
|
||||
assert(wanted_type== ira->codegen->builtin_types.entry_num_lit_int);
|
||||
IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
|
||||
source_instr->source_node, wanted_type);
|
||||
init_const_bigint(&result->value, wanted_type,
|
||||
&actual_type->data.enumeration.fields[0].value);
|
||||
return result;
|
||||
}
|
||||
|
||||
IrInstruction *result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope,
|
||||
source_instr->source_node, target);
|
||||
result->value.type = wanted_type;
|
||||
@@ -10164,6 +10197,19 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou
|
||||
return result;
|
||||
}
|
||||
|
||||
// If there is only 1 possible tag, then we know at comptime what it is.
|
||||
if (wanted_type->data.enumeration.layout == ContainerLayoutAuto &&
|
||||
wanted_type->data.enumeration.src_field_count == 1)
|
||||
{
|
||||
IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
|
||||
source_instr->source_node, wanted_type);
|
||||
result->value.special = ConstValSpecialStatic;
|
||||
result->value.type = wanted_type;
|
||||
TypeEnumField *enum_field = target->value.type->data.unionation.fields[0].enum_field;
|
||||
bigint_init_bigint(&result->value.data.x_enum_tag, &enum_field->value);
|
||||
return result;
|
||||
}
|
||||
|
||||
IrInstruction *result = ir_build_union_tag(&ira->new_irb, source_instr->scope,
|
||||
source_instr->source_node, target);
|
||||
result->value.type = wanted_type;
|
||||
@@ -10192,9 +10238,9 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so
|
||||
return ira->codegen->invalid_instruction;
|
||||
TypeUnionField *union_field = find_union_field_by_tag(wanted_type, &val->data.x_enum_tag);
|
||||
assert(union_field != nullptr);
|
||||
if ((err = type_ensure_zero_bits_known(ira->codegen, union_field->type_entry)))
|
||||
if ((err = type_resolve(ira->codegen, union_field->type_entry, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
if (!union_field->type_entry->zero_bits) {
|
||||
if (type_has_bits(union_field->type_entry)) {
|
||||
AstNode *field_node = wanted_type->data.unionation.decl_node->data.container_decl.fields.at(
|
||||
union_field->enum_field->decl_index);
|
||||
ErrorMsg *msg = ir_add_error(ira, source_instr,
|
||||
@@ -10497,7 +10543,10 @@ static IrInstruction *ir_analyze_ptr_to_array(IrAnalyze *ira, IrInstruction *sou
|
||||
ZigType *wanted_type)
|
||||
{
|
||||
assert(wanted_type->id == ZigTypeIdPointer);
|
||||
wanted_type = adjust_ptr_align(ira->codegen, wanted_type, target->value.type->data.pointer.alignment);
|
||||
Error err;
|
||||
if ((err = type_resolve(ira->codegen, target->value.type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
wanted_type = adjust_ptr_align(ira->codegen, wanted_type, get_ptr_align(ira->codegen, target->value.type));
|
||||
ZigType *array_type = wanted_type->data.pointer.child_type;
|
||||
assert(array_type->id == ZigTypeIdArray);
|
||||
assert(array_type->data.array.len == 1);
|
||||
@@ -10544,6 +10593,8 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa
|
||||
switch (cast_result->id) {
|
||||
case ConstCastResultIdOk:
|
||||
zig_unreachable();
|
||||
case ConstCastResultIdInvalid:
|
||||
zig_unreachable();
|
||||
case ConstCastResultIdOptionalChild: {
|
||||
ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node,
|
||||
buf_sprintf("optional type child '%s' cannot cast into optional type child '%s'",
|
||||
@@ -10643,6 +10694,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
|
||||
// perfect match or non-const to const
|
||||
ConstCastOnly const_cast_result = types_match_const_cast_only(ira, wanted_type, actual_type,
|
||||
source_node, false);
|
||||
if (const_cast_result.id == ConstCastResultIdInvalid)
|
||||
return ira->codegen->invalid_instruction;
|
||||
if (const_cast_result.id == ConstCastResultIdOk) {
|
||||
return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false);
|
||||
}
|
||||
@@ -10758,13 +10811,19 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
|
||||
wanted_type->data.pointer.ptr_len == PtrLenUnknown &&
|
||||
actual_type->id == ZigTypeIdPointer &&
|
||||
actual_type->data.pointer.ptr_len == PtrLenSingle &&
|
||||
actual_type->data.pointer.child_type->id == ZigTypeIdArray &&
|
||||
actual_type->data.pointer.alignment >= wanted_type->data.pointer.alignment &&
|
||||
types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
|
||||
actual_type->data.pointer.child_type->data.array.child_type, source_node,
|
||||
!wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
|
||||
actual_type->data.pointer.child_type->id == ZigTypeIdArray)
|
||||
{
|
||||
return ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, wanted_type);
|
||||
if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
if ((err = type_resolve(ira->codegen, wanted_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
if (get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, wanted_type) &&
|
||||
types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
|
||||
actual_type->data.pointer.child_type->data.array.child_type, source_node,
|
||||
!wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
|
||||
{
|
||||
return ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, wanted_type);
|
||||
}
|
||||
}
|
||||
|
||||
// *[N]T to []T
|
||||
@@ -10818,16 +10877,23 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
|
||||
wanted_child_type->data.pointer.ptr_len == PtrLenUnknown &&
|
||||
actual_type->id == ZigTypeIdPointer &&
|
||||
actual_type->data.pointer.ptr_len == PtrLenSingle &&
|
||||
actual_type->data.pointer.child_type->id == ZigTypeIdArray &&
|
||||
actual_type->data.pointer.alignment >= wanted_child_type->data.pointer.alignment &&
|
||||
types_match_const_cast_only(ira, wanted_child_type->data.pointer.child_type,
|
||||
actual_type->data.pointer.child_type->data.array.child_type, source_node,
|
||||
!wanted_child_type->data.pointer.is_const).id == ConstCastResultIdOk)
|
||||
actual_type->data.pointer.child_type->id == ZigTypeIdArray)
|
||||
{
|
||||
IrInstruction *cast1 = ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, wanted_child_type);
|
||||
if (type_is_invalid(cast1->value.type))
|
||||
if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
return ir_analyze_maybe_wrap(ira, source_instr, cast1, wanted_type);
|
||||
if ((err = type_resolve(ira->codegen, wanted_child_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
if (get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, wanted_child_type) &&
|
||||
types_match_const_cast_only(ira, wanted_child_type->data.pointer.child_type,
|
||||
actual_type->data.pointer.child_type->data.array.child_type, source_node,
|
||||
!wanted_child_type->data.pointer.is_const).id == ConstCastResultIdOk)
|
||||
{
|
||||
IrInstruction *cast1 = ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value,
|
||||
wanted_child_type);
|
||||
if (type_is_invalid(cast1->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
return ir_analyze_maybe_wrap(ira, source_instr, cast1, wanted_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10970,7 +11036,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
|
||||
|
||||
// cast from union to the enum type of the union
|
||||
if (actual_type->id == ZigTypeIdUnion && wanted_type->id == ZigTypeIdEnum) {
|
||||
if ((err = type_ensure_zero_bits_known(ira->codegen, actual_type)))
|
||||
if ((err = type_resolve(ira->codegen, actual_type, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
if (actual_type->data.unionation.tag_type == wanted_type) {
|
||||
@@ -10983,7 +11049,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
|
||||
(wanted_type->data.unionation.decl_node->data.container_decl.auto_enum ||
|
||||
wanted_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr))
|
||||
{
|
||||
if ((err = type_ensure_zero_bits_known(ira->codegen, wanted_type)))
|
||||
if ((err = type_resolve(ira->codegen, wanted_type, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
if (wanted_type->data.unionation.tag_type == actual_type) {
|
||||
@@ -10997,7 +11063,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
|
||||
if (union_type->data.unionation.decl_node->data.container_decl.auto_enum ||
|
||||
union_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr)
|
||||
{
|
||||
if ((err = type_ensure_zero_bits_known(ira->codegen, union_type)))
|
||||
if ((err = type_resolve(ira->codegen, union_type, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
if (union_type->data.unionation.tag_type == actual_type) {
|
||||
@@ -11024,14 +11090,24 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
|
||||
actual_type->data.pointer.child_type, source_node,
|
||||
!wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
|
||||
{
|
||||
if (wanted_type->data.pointer.alignment > actual_type->data.pointer.alignment) {
|
||||
if ((err = type_resolve(ira->codegen, wanted_type->data.pointer.child_type,
|
||||
ResolveStatusAlignmentKnown)))
|
||||
{
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type,
|
||||
ResolveStatusAlignmentKnown)))
|
||||
{
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
uint32_t wanted_align = get_ptr_align(ira->codegen, wanted_type);
|
||||
uint32_t actual_align = get_ptr_align(ira->codegen, actual_type);
|
||||
if (wanted_align > actual_align) {
|
||||
ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("cast increases pointer alignment"));
|
||||
add_error_note(ira->codegen, msg, value->source_node,
|
||||
buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&actual_type->name),
|
||||
actual_type->data.pointer.alignment));
|
||||
buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&actual_type->name), actual_align));
|
||||
add_error_note(ira->codegen, msg, source_instr->source_node,
|
||||
buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&wanted_type->name),
|
||||
wanted_type->data.pointer.alignment));
|
||||
buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&wanted_type->name), wanted_align));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
return ir_analyze_ptr_to_array(ira, source_instr, value, wanted_type);
|
||||
@@ -11043,7 +11119,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
|
||||
types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
|
||||
actual_type, source_node, !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
|
||||
{
|
||||
if ((err = type_ensure_zero_bits_known(ira->codegen, actual_type))) {
|
||||
if ((err = type_resolve(ira->codegen, actual_type, ResolveStatusZeroBitsKnown))) {
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
if (!type_has_bits(actual_type)) {
|
||||
@@ -11289,8 +11365,7 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) {
|
||||
return nullptr;
|
||||
|
||||
ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
|
||||
true, false, PtrLenUnknown,
|
||||
get_abi_alignment(ira->codegen, ira->codegen->builtin_types.entry_u8), 0, 0);
|
||||
true, false, PtrLenUnknown, 0, 0, 0);
|
||||
ZigType *str_type = get_slice_type(ira->codegen, ptr_type);
|
||||
IrInstruction *casted_value = ir_implicit_cast(ira, value, str_type);
|
||||
if (type_is_invalid(casted_value->value.type))
|
||||
@@ -11580,8 +11655,6 @@ static ZigType *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op
|
||||
ZigType *resolved_type = ir_resolve_peer_types(ira, source_node, nullptr, instructions, 2);
|
||||
if (type_is_invalid(resolved_type))
|
||||
return resolved_type;
|
||||
if ((err = type_ensure_zero_bits_known(ira->codegen, resolved_type)))
|
||||
return resolved_type;
|
||||
|
||||
bool operator_allowed;
|
||||
switch (resolved_type->id) {
|
||||
@@ -11603,7 +11676,6 @@ static ZigType *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdOpaque:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdPromise:
|
||||
@@ -11638,6 +11710,9 @@ static ZigType *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op
|
||||
if (casted_op2 == ira->codegen->invalid_instruction)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
if ((err = type_resolve(ira->codegen, resolved_type, ResolveStatusZeroBitsKnown)))
|
||||
return resolved_type;
|
||||
|
||||
bool one_possible_value = !type_requires_comptime(resolved_type) && !type_has_bits(resolved_type);
|
||||
if (one_possible_value || (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2))) {
|
||||
ConstExprValue *op1_val = one_possible_value ? &casted_op1->value : ir_resolve_const(ira, casted_op1, UndefBad);
|
||||
@@ -12324,7 +12399,7 @@ static ZigType *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *instruc
|
||||
out_array_val = out_val;
|
||||
} else if (is_slice(op1_type) || is_slice(op2_type)) {
|
||||
ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, child_type,
|
||||
true, false, PtrLenUnknown, get_abi_alignment(ira->codegen, child_type), 0, 0);
|
||||
true, false, PtrLenUnknown, 0, 0, 0);
|
||||
result_type = get_slice_type(ira->codegen, ptr_type);
|
||||
out_array_val = create_const_vals(1);
|
||||
out_array_val->special = ConstValSpecialStatic;
|
||||
@@ -12345,8 +12420,7 @@ static ZigType *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *instruc
|
||||
new_len += 1; // null byte
|
||||
|
||||
// TODO make this `[*]null T` instead of `[*]T`
|
||||
result_type = get_pointer_to_type_extra(ira->codegen, child_type, true, false,
|
||||
PtrLenUnknown, get_abi_alignment(ira->codegen, child_type), 0, 0);
|
||||
result_type = get_pointer_to_type_extra(ira->codegen, child_type, true, false, PtrLenUnknown, 0, 0, 0);
|
||||
|
||||
out_array_val = create_const_vals(1);
|
||||
out_array_val->special = ConstValSpecialStatic;
|
||||
@@ -12444,10 +12518,22 @@ static ZigType *ir_analyze_merge_error_sets(IrAnalyze *ira, IrInstructionBinOp *
|
||||
if (type_is_invalid(op1_type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
if (op1_type->id != ZigTypeIdErrorSet) {
|
||||
ir_add_error(ira, instruction->op1,
|
||||
buf_sprintf("expected error set type, found '%s'", buf_ptr(&op1_type->name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
ZigType *op2_type = ir_resolve_type(ira, instruction->op2->other);
|
||||
if (type_is_invalid(op2_type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
if (op2_type->id != ZigTypeIdErrorSet) {
|
||||
ir_add_error(ira, instruction->op2,
|
||||
buf_sprintf("expected error set type, found '%s'", buf_ptr(&op2_type->name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
if (type_is_global_error_set(op1_type) ||
|
||||
type_is_global_error_set(op2_type))
|
||||
{
|
||||
@@ -12559,7 +12645,7 @@ static ZigType *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstructionDec
|
||||
if (type_is_invalid(result_type)) {
|
||||
result_type = ira->codegen->builtin_types.entry_invalid;
|
||||
} else {
|
||||
if ((err = type_ensure_zero_bits_known(ira->codegen, result_type))) {
|
||||
if ((err = type_resolve(ira->codegen, result_type, ResolveStatusZeroBitsKnown))) {
|
||||
result_type = ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
}
|
||||
@@ -12627,6 +12713,11 @@ static ZigType *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstructionDec
|
||||
}
|
||||
|
||||
if (decl_var_instruction->align_value == nullptr) {
|
||||
if ((err = type_resolve(ira->codegen, result_type, ResolveStatusAlignmentKnown))) {
|
||||
var->value->type = ira->codegen->builtin_types.entry_invalid;
|
||||
decl_var_instruction->base.other = &decl_var_instruction->base;
|
||||
return ira->codegen->builtin_types.entry_void;
|
||||
}
|
||||
var->align_bytes = get_abi_alignment(ira->codegen, result_type);
|
||||
} else {
|
||||
if (!ir_resolve_align(ira, decl_var_instruction->align_value->other, &var->align_bytes)) {
|
||||
@@ -12792,7 +12883,6 @@ static ZigType *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructionExpor
|
||||
case ZigTypeIdErrorUnion:
|
||||
case ZigTypeIdErrorSet:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdOpaque:
|
||||
@@ -12817,7 +12907,6 @@ static ZigType *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructionExpor
|
||||
case ZigTypeIdErrorSet:
|
||||
zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name));
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdOpaque:
|
||||
@@ -13098,7 +13187,6 @@ static ZigVar *get_fn_var_by_index(ZigFn *fn_entry, size_t index) {
|
||||
static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
|
||||
ZigVar *var)
|
||||
{
|
||||
Error err;
|
||||
while (var->next_var != nullptr) {
|
||||
var = var->next_var;
|
||||
}
|
||||
@@ -13156,8 +13244,6 @@ no_mem_slot:
|
||||
instruction->scope, instruction->source_node, var);
|
||||
var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->value->type,
|
||||
var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0);
|
||||
if ((err = type_ensure_zero_bits_known(ira->codegen, var->value->type)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr);
|
||||
var_ptr_instruction->value.data.rh_ptr = in_fn_scope ? RuntimeHintPtrStack : RuntimeHintPtrNonStack;
|
||||
@@ -13354,8 +13440,7 @@ static ZigType *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instr
|
||||
IrInstruction *casted_new_stack = nullptr;
|
||||
if (call_instruction->new_stack != nullptr) {
|
||||
ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
|
||||
false, false, PtrLenUnknown,
|
||||
get_abi_alignment(ira->codegen, ira->codegen->builtin_types.entry_u8), 0, 0);
|
||||
false, false, PtrLenUnknown, 0, 0, 0);
|
||||
ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr);
|
||||
IrInstruction *new_stack = call_instruction->new_stack->other;
|
||||
if (type_is_invalid(new_stack->value.type))
|
||||
@@ -13534,7 +13619,7 @@ static ZigType *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instr
|
||||
inst_fn_type_id.return_type = specified_return_type;
|
||||
}
|
||||
|
||||
if ((err = type_ensure_zero_bits_known(ira->codegen, specified_return_type)))
|
||||
if ((err = type_resolve(ira->codegen, specified_return_type, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
if (type_requires_comptime(specified_return_type)) {
|
||||
@@ -13875,7 +13960,6 @@ static ZigType *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_instru
|
||||
case ZigTypeIdUnion:
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdPromise:
|
||||
@@ -14211,7 +14295,7 @@ static ZigType *adjust_ptr_len(CodeGen *g, ZigType *ptr_type, PtrLen ptr_len) {
|
||||
ptr_type->data.pointer.child_type,
|
||||
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
|
||||
ptr_len,
|
||||
ptr_type->data.pointer.alignment,
|
||||
ptr_type->data.pointer.explicit_alignment,
|
||||
ptr_type->data.pointer.bit_offset, ptr_type->data.pointer.unaligned_bit_count);
|
||||
}
|
||||
|
||||
@@ -14263,7 +14347,7 @@ static ZigType *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstructionEle
|
||||
return_type = get_pointer_to_type_extra(ira->codegen, child_type,
|
||||
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
|
||||
elem_ptr_instruction->ptr_len,
|
||||
ptr_type->data.pointer.alignment, 0, 0);
|
||||
ptr_type->data.pointer.explicit_alignment, 0, 0);
|
||||
} else {
|
||||
uint64_t elem_val_scalar;
|
||||
if (!ir_resolve_usize(ira, elem_index, &elem_val_scalar))
|
||||
@@ -14335,7 +14419,7 @@ static ZigType *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstructionEle
|
||||
|
||||
uint64_t elem_size = type_size(ira->codegen, return_type->data.pointer.child_type);
|
||||
uint64_t abi_align = get_abi_alignment(ira->codegen, return_type->data.pointer.child_type);
|
||||
uint64_t ptr_align = return_type->data.pointer.alignment;
|
||||
uint64_t ptr_align = get_ptr_align(ira->codegen, return_type);
|
||||
if (instr_is_comptime(casted_elem_index)) {
|
||||
uint64_t index = bigint_as_unsigned(&casted_elem_index->value.data.x_bigint);
|
||||
if (array_type->id == ZigTypeIdArray) {
|
||||
@@ -14652,9 +14736,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
|
||||
}
|
||||
|
||||
ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field_type,
|
||||
is_const, is_volatile,
|
||||
PtrLenSingle,
|
||||
get_abi_alignment(ira->codegen, field_type), 0, 0);
|
||||
is_const, is_volatile, PtrLenSingle, 0, 0, 0);
|
||||
|
||||
IrInstruction *result = ir_get_const(ira, source_instr);
|
||||
ConstExprValue *const_val = &result->value;
|
||||
@@ -14668,7 +14750,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
|
||||
|
||||
IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, container_ptr, field);
|
||||
result->value.type = get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile,
|
||||
PtrLenSingle, get_abi_alignment(ira->codegen, field->type_entry), 0, 0);
|
||||
PtrLenSingle, 0, 0, 0);
|
||||
return result;
|
||||
} else {
|
||||
return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
|
||||
@@ -15001,9 +15083,14 @@ static ZigType *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstructionFi
|
||||
} else if (buf_eql_str(field_name, "alignment")) {
|
||||
bool ptr_is_const = true;
|
||||
bool ptr_is_volatile = false;
|
||||
if ((err = type_resolve(ira->codegen, child_type->data.pointer.child_type,
|
||||
ResolveStatusAlignmentKnown)))
|
||||
{
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
|
||||
create_const_unsigned_negative(ira->codegen->builtin_types.entry_num_lit_int,
|
||||
child_type->data.pointer.alignment, false),
|
||||
get_ptr_align(ira->codegen, child_type), false),
|
||||
ira->codegen->builtin_types.entry_num_lit_int,
|
||||
ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
|
||||
} else {
|
||||
@@ -15233,7 +15320,6 @@ static ZigType *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructionTypeO
|
||||
case ZigTypeIdUndefined:
|
||||
case ZigTypeIdNull:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdMetaType:
|
||||
case ZigTypeIdVoid:
|
||||
@@ -15342,6 +15428,7 @@ static ZigType *ir_analyze_instruction_set_cold(IrAnalyze *ira, IrInstructionSet
|
||||
ir_build_const_from(ira, &instruction->base);
|
||||
return ira->codegen->builtin_types.entry_void;
|
||||
}
|
||||
|
||||
static ZigType *ir_analyze_instruction_set_runtime_safety(IrAnalyze *ira,
|
||||
IrInstructionSetRuntimeSafety *set_runtime_safety_instruction)
|
||||
{
|
||||
@@ -15402,14 +15489,6 @@ static ZigType *ir_analyze_instruction_set_runtime_safety(IrAnalyze *ira,
|
||||
static ZigType *ir_analyze_instruction_set_float_mode(IrAnalyze *ira,
|
||||
IrInstructionSetFloatMode *instruction)
|
||||
{
|
||||
IrInstruction *target_instruction = instruction->scope_value->other;
|
||||
ZigType *target_type = target_instruction->value.type;
|
||||
if (type_is_invalid(target_type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
ConstExprValue *target_val = ir_resolve_const(ira, target_instruction, UndefBad);
|
||||
if (!target_val)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
if (ira->new_irb.exec->is_inline) {
|
||||
// ignore setFloatMode when running functions at compile time
|
||||
ir_build_const_from(ira, &instruction->base);
|
||||
@@ -15418,40 +15497,34 @@ static ZigType *ir_analyze_instruction_set_float_mode(IrAnalyze *ira,
|
||||
|
||||
bool *fast_math_on_ptr;
|
||||
AstNode **fast_math_set_node_ptr;
|
||||
if (target_type->id == ZigTypeIdBlock) {
|
||||
ScopeBlock *block_scope = (ScopeBlock *)target_val->data.x_block;
|
||||
fast_math_on_ptr = &block_scope->fast_math_on;
|
||||
fast_math_set_node_ptr = &block_scope->fast_math_set_node;
|
||||
} else if (target_type->id == ZigTypeIdFn) {
|
||||
assert(target_val->data.x_ptr.special == ConstPtrSpecialFunction);
|
||||
ZigFn *target_fn = target_val->data.x_ptr.data.fn.fn_entry;
|
||||
assert(target_fn->def_scope);
|
||||
fast_math_on_ptr = &target_fn->def_scope->fast_math_on;
|
||||
fast_math_set_node_ptr = &target_fn->def_scope->fast_math_set_node;
|
||||
} else if (target_type->id == ZigTypeIdMetaType) {
|
||||
ScopeDecls *decls_scope;
|
||||
ZigType *type_arg = target_val->data.x_type;
|
||||
if (type_arg->id == ZigTypeIdStruct) {
|
||||
decls_scope = type_arg->data.structure.decls_scope;
|
||||
} else if (type_arg->id == ZigTypeIdEnum) {
|
||||
decls_scope = type_arg->data.enumeration.decls_scope;
|
||||
} else if (type_arg->id == ZigTypeIdUnion) {
|
||||
decls_scope = type_arg->data.unionation.decls_scope;
|
||||
|
||||
Scope *scope = instruction->base.scope;
|
||||
while (scope != nullptr) {
|
||||
if (scope->id == ScopeIdBlock) {
|
||||
ScopeBlock *block_scope = (ScopeBlock *)scope;
|
||||
fast_math_on_ptr = &block_scope->fast_math_on;
|
||||
fast_math_set_node_ptr = &block_scope->fast_math_set_node;
|
||||
break;
|
||||
} else if (scope->id == ScopeIdFnDef) {
|
||||
ScopeFnDef *def_scope = (ScopeFnDef *)scope;
|
||||
ZigFn *target_fn = def_scope->fn_entry;
|
||||
assert(target_fn->def_scope != nullptr);
|
||||
fast_math_on_ptr = &target_fn->def_scope->fast_math_on;
|
||||
fast_math_set_node_ptr = &target_fn->def_scope->fast_math_set_node;
|
||||
break;
|
||||
} else if (scope->id == ScopeIdDecls) {
|
||||
ScopeDecls *decls_scope = (ScopeDecls *)scope;
|
||||
fast_math_on_ptr = &decls_scope->fast_math_on;
|
||||
fast_math_set_node_ptr = &decls_scope->fast_math_set_node;
|
||||
break;
|
||||
} else {
|
||||
ir_add_error_node(ira, target_instruction->source_node,
|
||||
buf_sprintf("expected scope reference, found type '%s'", buf_ptr(&type_arg->name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
scope = scope->parent;
|
||||
continue;
|
||||
}
|
||||
fast_math_on_ptr = &decls_scope->fast_math_on;
|
||||
fast_math_set_node_ptr = &decls_scope->fast_math_set_node;
|
||||
} else {
|
||||
ir_add_error_node(ira, target_instruction->source_node,
|
||||
buf_sprintf("expected scope reference, found type '%s'", buf_ptr(&target_type->name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
assert(scope != nullptr);
|
||||
|
||||
IrInstruction *float_mode_value = instruction->mode_value->other;
|
||||
|
||||
FloatMode float_mode_scalar;
|
||||
if (!ir_resolve_float_mode(ira, float_mode_value, &float_mode_scalar))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
@@ -15474,7 +15547,7 @@ static ZigType *ir_analyze_instruction_slice_type(IrAnalyze *ira,
|
||||
IrInstructionSliceType *slice_type_instruction)
|
||||
{
|
||||
Error err;
|
||||
uint32_t align_bytes;
|
||||
uint32_t align_bytes = 0;
|
||||
if (slice_type_instruction->align_value != nullptr) {
|
||||
if (!ir_resolve_align(ira, slice_type_instruction->align_value->other, &align_bytes))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
@@ -15484,12 +15557,6 @@ static ZigType *ir_analyze_instruction_slice_type(IrAnalyze *ira,
|
||||
if (type_is_invalid(child_type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
if (slice_type_instruction->align_value == nullptr) {
|
||||
if ((err = type_ensure_zero_bits_known(ira->codegen, child_type)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
align_bytes = get_abi_alignment(ira->codegen, child_type);
|
||||
}
|
||||
|
||||
bool is_const = slice_type_instruction->is_const;
|
||||
bool is_volatile = slice_type_instruction->is_volatile;
|
||||
|
||||
@@ -15499,7 +15566,6 @@ static ZigType *ir_analyze_instruction_slice_type(IrAnalyze *ira,
|
||||
case ZigTypeIdUnreachable:
|
||||
case ZigTypeIdUndefined:
|
||||
case ZigTypeIdNull:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdOpaque:
|
||||
ir_add_error_node(ira, slice_type_instruction->base.source_node,
|
||||
@@ -15525,7 +15591,7 @@ static ZigType *ir_analyze_instruction_slice_type(IrAnalyze *ira,
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdPromise:
|
||||
{
|
||||
if ((err = type_ensure_zero_bits_known(ira->codegen, child_type)))
|
||||
if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, child_type,
|
||||
is_const, is_volatile, PtrLenUnknown, align_bytes, 0, 0);
|
||||
@@ -15610,7 +15676,6 @@ static ZigType *ir_analyze_instruction_array_type(IrAnalyze *ira,
|
||||
case ZigTypeIdUnreachable:
|
||||
case ZigTypeIdUndefined:
|
||||
case ZigTypeIdNull:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdOpaque:
|
||||
ir_add_error_node(ira, array_type_instruction->base.source_node,
|
||||
@@ -15681,7 +15746,6 @@ static ZigType *ir_analyze_instruction_size_of(IrAnalyze *ira,
|
||||
case ZigTypeIdUnreachable:
|
||||
case ZigTypeIdUndefined:
|
||||
case ZigTypeIdNull:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdComptimeFloat:
|
||||
case ZigTypeIdComptimeInt:
|
||||
case ZigTypeIdBoundFn:
|
||||
@@ -15767,9 +15831,7 @@ static ZigType *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
|
||||
}
|
||||
ZigType *child_type = type_entry->data.maybe.child_type;
|
||||
ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type,
|
||||
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
|
||||
PtrLenSingle,
|
||||
get_abi_alignment(ira->codegen, child_type), 0, 0);
|
||||
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0);
|
||||
|
||||
if (instr_is_comptime(value)) {
|
||||
ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
|
||||
@@ -16139,7 +16201,7 @@ static ZigType *ir_analyze_instruction_switch_target(IrAnalyze *ira,
|
||||
return tag_type;
|
||||
}
|
||||
case ZigTypeIdEnum: {
|
||||
if ((err = type_ensure_zero_bits_known(ira->codegen, target_type)))
|
||||
if ((err = type_resolve(ira->codegen, target_type, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
if (target_type->data.enumeration.src_field_count < 2) {
|
||||
TypeEnumField *only_field = &target_type->data.enumeration.fields[0];
|
||||
@@ -16167,7 +16229,6 @@ static ZigType *ir_analyze_instruction_switch_target(IrAnalyze *ira,
|
||||
case ZigTypeIdUndefined:
|
||||
case ZigTypeIdNull:
|
||||
case ZigTypeIdOptional:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdOpaque:
|
||||
@@ -16231,6 +16292,8 @@ static ZigType *ir_analyze_instruction_union_tag(IrAnalyze *ira, IrInstructionUn
|
||||
}
|
||||
|
||||
static ZigType *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructionImport *import_instruction) {
|
||||
Error err;
|
||||
|
||||
IrInstruction *name_value = import_instruction->name->other;
|
||||
Buf *import_target_str = ir_resolve_str(ira, name_value);
|
||||
if (!import_target_str)
|
||||
@@ -16274,8 +16337,7 @@ static ZigType *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructionImpor
|
||||
return ira->codegen->builtin_types.entry_namespace;
|
||||
}
|
||||
|
||||
int err;
|
||||
if ((err = os_fetch_file_path(resolved_path, import_code, true))) {
|
||||
if ((err = file_fetch(ira->codegen, resolved_path, import_code))) {
|
||||
if (err == ErrorFileNotFound) {
|
||||
ir_add_error_node(ira, source_node,
|
||||
buf_sprintf("unable to find '%s'", buf_ptr(import_target_path)));
|
||||
@@ -16286,6 +16348,7 @@ static ZigType *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructionImpor
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
ImportTableEntry *target_import = add_source_file(ira->codegen, target_package, resolved_path, import_code);
|
||||
|
||||
scan_import(ira->codegen, target_import);
|
||||
@@ -16367,7 +16430,7 @@ static ZigType *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrInstruc
|
||||
if (casted_field_value == ira->codegen->invalid_instruction)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
if ((err = type_ensure_zero_bits_known(ira->codegen, casted_field_value->value.type)))
|
||||
if ((err = type_resolve(ira->codegen, casted_field_value->value.type, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope);
|
||||
@@ -16686,7 +16749,6 @@ static ZigType *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_instruc
|
||||
case ZigTypeIdUnion:
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdOpaque:
|
||||
@@ -16768,7 +16830,7 @@ static ZigType *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstructionErr
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
ZigType *u8_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
|
||||
true, false, PtrLenUnknown, get_abi_alignment(ira->codegen, ira->codegen->builtin_types.entry_u8), 0, 0);
|
||||
true, false, PtrLenUnknown, 0, 0, 0);
|
||||
ZigType *str_type = get_slice_type(ira->codegen, u8_ptr_type);
|
||||
if (casted_value->value.special == ConstValSpecialStatic) {
|
||||
ErrorTableEntry *err = casted_value->value.data.x_err_set;
|
||||
@@ -16795,7 +16857,7 @@ static ZigType *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstructi
|
||||
assert(target->value.type->id == ZigTypeIdEnum);
|
||||
|
||||
if (instr_is_comptime(target)) {
|
||||
if ((err = type_ensure_zero_bits_known(ira->codegen, target->value.type)))
|
||||
if ((err = type_resolve(ira->codegen, target->value.type, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
TypeEnumField *field = find_enum_field_by_tag(target->value.type, &target->value.data.x_bigint);
|
||||
ConstExprValue *array_val = create_const_str_lit(ira->codegen, field->name);
|
||||
@@ -16810,8 +16872,7 @@ static ZigType *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstructi
|
||||
ZigType *u8_ptr_type = get_pointer_to_type_extra(
|
||||
ira->codegen, ira->codegen->builtin_types.entry_u8,
|
||||
true, false, PtrLenUnknown,
|
||||
get_abi_alignment(ira->codegen, ira->codegen->builtin_types.entry_u8),
|
||||
0, 0);
|
||||
0, 0, 0);
|
||||
result->value.type = get_slice_type(ira->codegen, u8_ptr_type);
|
||||
return result->value.type;
|
||||
}
|
||||
@@ -17174,8 +17235,7 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco
|
||||
ZigType *u8_ptr = get_pointer_to_type_extra(
|
||||
ira->codegen, ira->codegen->builtin_types.entry_u8,
|
||||
true, false, PtrLenUnknown,
|
||||
get_abi_alignment(ira->codegen, ira->codegen->builtin_types.entry_u8),
|
||||
0, 0);
|
||||
0, 0, 0);
|
||||
fn_def_fields[6].type = get_optional_type(ira->codegen, get_slice_type(ira->codegen, u8_ptr));
|
||||
if (fn_node->is_extern && buf_len(fn_node->lib_name) > 0) {
|
||||
fn_def_fields[6].data.x_optional = create_const_vals(1);
|
||||
@@ -17295,7 +17355,7 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty
|
||||
ensure_field_index(result->type, "alignment", 3);
|
||||
fields[3].special = ConstValSpecialStatic;
|
||||
fields[3].type = get_int_type(ira->codegen, false, 29);
|
||||
bigint_init_unsigned(&fields[3].data.x_bigint, attrs_type->data.pointer.alignment);
|
||||
bigint_init_unsigned(&fields[3].data.x_bigint, get_ptr_align(ira->codegen, attrs_type));
|
||||
// child: type
|
||||
ensure_field_index(result->type, "child", 4);
|
||||
fields[4].special = ConstValSpecialStatic;
|
||||
@@ -17349,7 +17409,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
|
||||
case ZigTypeIdUndefined:
|
||||
case ZigTypeIdNull:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdOpaque:
|
||||
*out = nullptr;
|
||||
@@ -17959,6 +18018,12 @@ static ZigType *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTy
|
||||
}
|
||||
|
||||
static ZigType *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstructionCImport *instruction) {
|
||||
if (ira->codegen->enable_cache) {
|
||||
ir_add_error(ira, &instruction->base,
|
||||
buf_sprintf("TODO @cImport is incompatible with --cache on. The cache system currently is unable to detect subsequent changes in .h files."));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
AstNode *node = instruction->base.source_node;
|
||||
assert(node->type == NodeTypeFnCallExpr);
|
||||
AstNode *block_node = node->data.fn_call_expr.params.at(0);
|
||||
@@ -18105,7 +18170,7 @@ static ZigType *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstructionE
|
||||
// load from file system into const expr
|
||||
Buf *file_contents = buf_alloc();
|
||||
int err;
|
||||
if ((err = os_fetch_file_path(&file_path, file_contents, false))) {
|
||||
if ((err = file_fetch(ira->codegen, &file_path, file_contents))) {
|
||||
if (err == ErrorFileNotFound) {
|
||||
ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
@@ -18115,9 +18180,6 @@ static ZigType *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstructionE
|
||||
}
|
||||
}
|
||||
|
||||
// TODO add dependency on the file we embedded so that we know if it changes
|
||||
// we'll have to invalidate the cache
|
||||
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
init_const_str_lit(ira->codegen, out_val, file_contents);
|
||||
|
||||
@@ -18383,7 +18445,21 @@ static ZigType *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInstructio
|
||||
return dest_type;
|
||||
}
|
||||
|
||||
static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) {
|
||||
Error err;
|
||||
|
||||
if (ty->id == ZigTypeIdPointer) {
|
||||
if ((err = type_resolve(ira->codegen, ty->data.pointer.child_type, ResolveStatusAlignmentKnown)))
|
||||
return err;
|
||||
}
|
||||
|
||||
*result_align = get_ptr_align(ira->codegen, ty);
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
static ZigType *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstructionFromBytes *instruction) {
|
||||
Error err;
|
||||
|
||||
ZigType *dest_child_type = ir_resolve_type(ira, instruction->dest_child_type->other);
|
||||
if (type_is_invalid(dest_child_type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
@@ -18398,15 +18474,23 @@ static ZigType *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstructionF
|
||||
if (target->value.type->id == ZigTypeIdPointer) {
|
||||
src_ptr_const = target->value.type->data.pointer.is_const;
|
||||
src_ptr_volatile = target->value.type->data.pointer.is_volatile;
|
||||
src_ptr_align = target->value.type->data.pointer.alignment;
|
||||
|
||||
if ((err = resolve_ptr_align(ira, target->value.type, &src_ptr_align)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
} else if (is_slice(target->value.type)) {
|
||||
ZigType *src_ptr_type = target->value.type->data.structure.fields[slice_ptr_index].type_entry;
|
||||
src_ptr_const = src_ptr_type->data.pointer.is_const;
|
||||
src_ptr_volatile = src_ptr_type->data.pointer.is_volatile;
|
||||
src_ptr_align = src_ptr_type->data.pointer.alignment;
|
||||
|
||||
if ((err = resolve_ptr_align(ira, src_ptr_type, &src_ptr_align)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
} else {
|
||||
src_ptr_const = true;
|
||||
src_ptr_volatile = false;
|
||||
|
||||
if ((err = type_resolve(ira->codegen, target->value.type, ResolveStatusAlignmentKnown)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
src_ptr_align = get_abi_alignment(ira->codegen, target->value.type);
|
||||
}
|
||||
|
||||
@@ -18464,6 +18548,8 @@ static ZigType *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstructionF
|
||||
}
|
||||
|
||||
static ZigType *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstructionToBytes *instruction) {
|
||||
Error err;
|
||||
|
||||
IrInstruction *target = instruction->target->other;
|
||||
if (type_is_invalid(target->value.type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
@@ -18476,9 +18562,13 @@ static ZigType *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstructionToB
|
||||
|
||||
ZigType *src_ptr_type = target->value.type->data.structure.fields[slice_ptr_index].type_entry;
|
||||
|
||||
uint32_t alignment;
|
||||
if ((err = resolve_ptr_align(ira, src_ptr_type, &alignment)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
ZigType *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
|
||||
src_ptr_type->data.pointer.is_const, src_ptr_type->data.pointer.is_volatile, PtrLenUnknown,
|
||||
src_ptr_type->data.pointer.alignment, 0, 0);
|
||||
alignment, 0, 0);
|
||||
ZigType *dest_slice_type = get_slice_type(ira->codegen, dest_ptr_type);
|
||||
|
||||
IrInstruction *result = ir_resolve_cast(ira, &instruction->base, target, dest_slice_type, CastOpResizeSlice, true);
|
||||
@@ -18636,6 +18726,8 @@ static ZigType *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstructionBoo
|
||||
}
|
||||
|
||||
static ZigType *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructionMemset *instruction) {
|
||||
Error err;
|
||||
|
||||
IrInstruction *dest_ptr = instruction->dest_ptr->other;
|
||||
if (type_is_invalid(dest_ptr->value.type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
@@ -18654,8 +18746,13 @@ static ZigType *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructionMemse
|
||||
|
||||
ZigType *usize = ira->codegen->builtin_types.entry_usize;
|
||||
ZigType *u8 = ira->codegen->builtin_types.entry_u8;
|
||||
uint32_t dest_align = (dest_uncasted_type->id == ZigTypeIdPointer) ?
|
||||
dest_uncasted_type->data.pointer.alignment : get_abi_alignment(ira->codegen, u8);
|
||||
uint32_t dest_align;
|
||||
if (dest_uncasted_type->id == ZigTypeIdPointer) {
|
||||
if ((err = resolve_ptr_align(ira, dest_uncasted_type, &dest_align)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
} else {
|
||||
dest_align = get_abi_alignment(ira->codegen, u8);
|
||||
}
|
||||
ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, u8, false, dest_is_volatile,
|
||||
PtrLenUnknown, dest_align, 0, 0);
|
||||
|
||||
@@ -18728,6 +18825,8 @@ static ZigType *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructionMemse
|
||||
}
|
||||
|
||||
static ZigType *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructionMemcpy *instruction) {
|
||||
Error err;
|
||||
|
||||
IrInstruction *dest_ptr = instruction->dest_ptr->other;
|
||||
if (type_is_invalid(dest_ptr->value.type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
@@ -18747,10 +18846,22 @@ static ZigType *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructionMemcp
|
||||
dest_uncasted_type->data.pointer.is_volatile;
|
||||
bool src_is_volatile = (src_uncasted_type->id == ZigTypeIdPointer) &&
|
||||
src_uncasted_type->data.pointer.is_volatile;
|
||||
uint32_t dest_align = (dest_uncasted_type->id == ZigTypeIdPointer) ?
|
||||
dest_uncasted_type->data.pointer.alignment : get_abi_alignment(ira->codegen, u8);
|
||||
uint32_t src_align = (src_uncasted_type->id == ZigTypeIdPointer) ?
|
||||
src_uncasted_type->data.pointer.alignment : get_abi_alignment(ira->codegen, u8);
|
||||
|
||||
uint32_t dest_align;
|
||||
if (dest_uncasted_type->id == ZigTypeIdPointer) {
|
||||
if ((err = resolve_ptr_align(ira, dest_uncasted_type, &dest_align)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
} else {
|
||||
dest_align = get_abi_alignment(ira->codegen, u8);
|
||||
}
|
||||
|
||||
uint32_t src_align;
|
||||
if (src_uncasted_type->id == ZigTypeIdPointer) {
|
||||
if ((err = resolve_ptr_align(ira, src_uncasted_type, &src_align)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
} else {
|
||||
src_align = get_abi_alignment(ira->codegen, u8);
|
||||
}
|
||||
|
||||
ZigType *usize = ira->codegen->builtin_types.entry_usize;
|
||||
ZigType *u8_ptr_mut = get_pointer_to_type_extra(ira->codegen, u8, false, dest_is_volatile,
|
||||
@@ -18895,17 +19006,13 @@ static ZigType *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructionSlice
|
||||
ZigType *return_type;
|
||||
|
||||
if (array_type->id == ZigTypeIdArray) {
|
||||
uint32_t byte_alignment = ptr_type->data.pointer.alignment;
|
||||
if (array_type->data.array.len == 0 && byte_alignment == 0) {
|
||||
byte_alignment = get_abi_alignment(ira->codegen, array_type->data.array.child_type);
|
||||
}
|
||||
bool is_comptime_const = ptr_ptr->value.special == ConstValSpecialStatic &&
|
||||
ptr_ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst;
|
||||
ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.array.child_type,
|
||||
ptr_type->data.pointer.is_const || is_comptime_const,
|
||||
ptr_type->data.pointer.is_volatile,
|
||||
PtrLenUnknown,
|
||||
byte_alignment, 0, 0);
|
||||
ptr_type->data.pointer.explicit_alignment, 0, 0);
|
||||
return_type = get_slice_type(ira->codegen, slice_ptr_type);
|
||||
} else if (array_type->id == ZigTypeIdPointer) {
|
||||
if (array_type->data.pointer.ptr_len == PtrLenSingle) {
|
||||
@@ -18915,7 +19022,7 @@ static ZigType *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructionSlice
|
||||
main_type->data.pointer.child_type,
|
||||
array_type->data.pointer.is_const, array_type->data.pointer.is_volatile,
|
||||
PtrLenUnknown,
|
||||
array_type->data.pointer.alignment, 0, 0);
|
||||
array_type->data.pointer.explicit_alignment, 0, 0);
|
||||
return_type = get_slice_type(ira->codegen, slice_ptr_type);
|
||||
} else {
|
||||
ir_add_error(ira, &instruction->base, buf_sprintf("slice of single-item pointer"));
|
||||
@@ -18925,7 +19032,7 @@ static ZigType *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructionSlice
|
||||
ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.pointer.child_type,
|
||||
array_type->data.pointer.is_const, array_type->data.pointer.is_volatile,
|
||||
PtrLenUnknown,
|
||||
array_type->data.pointer.alignment, 0, 0);
|
||||
array_type->data.pointer.explicit_alignment, 0, 0);
|
||||
return_type = get_slice_type(ira->codegen, slice_ptr_type);
|
||||
if (!end) {
|
||||
ir_add_error(ira, &instruction->base, buf_sprintf("slice of pointer must include end value"));
|
||||
@@ -19306,7 +19413,7 @@ static ZigType *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstructionAli
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
ZigType *type_entry = ir_resolve_type(ira, type_value);
|
||||
|
||||
if ((err = type_ensure_zero_bits_known(ira->codegen, type_entry)))
|
||||
if ((err = type_resolve(ira->codegen, type_entry, ResolveStatusAlignmentKnown)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
switch (type_entry->id) {
|
||||
@@ -19319,7 +19426,6 @@ static ZigType *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstructionAli
|
||||
case ZigTypeIdUndefined:
|
||||
case ZigTypeIdNull:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdVoid:
|
||||
@@ -19351,6 +19457,8 @@ static ZigType *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstructionAli
|
||||
}
|
||||
|
||||
static ZigType *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstructionOverflowOp *instruction) {
|
||||
Error err;
|
||||
|
||||
IrInstruction *type_value = instruction->type_value->other;
|
||||
if (type_is_invalid(type_value->value.type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
@@ -19394,10 +19502,13 @@ static ZigType *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstruction
|
||||
|
||||
ZigType *expected_ptr_type;
|
||||
if (result_ptr->value.type->id == ZigTypeIdPointer) {
|
||||
uint32_t alignment;
|
||||
if ((err = resolve_ptr_align(ira, result_ptr->value.type, &alignment)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
expected_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_type,
|
||||
false, result_ptr->value.type->data.pointer.is_volatile,
|
||||
PtrLenSingle,
|
||||
result_ptr->value.type->data.pointer.alignment, 0, 0);
|
||||
alignment, 0, 0);
|
||||
} else {
|
||||
expected_ptr_type = get_pointer_to_type(ira->codegen, dest_type, false);
|
||||
}
|
||||
@@ -19559,8 +19670,7 @@ static ZigType *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
|
||||
}
|
||||
ZigType *result_type = get_pointer_to_type_extra(ira->codegen, payload_type,
|
||||
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
|
||||
PtrLenSingle,
|
||||
get_abi_alignment(ira->codegen, payload_type), 0, 0);
|
||||
PtrLenSingle, 0, 0, 0);
|
||||
if (instr_is_comptime(value)) {
|
||||
ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);
|
||||
if (!ptr_val)
|
||||
@@ -19639,7 +19749,7 @@ static ZigType *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnP
|
||||
ZigType *param_type = ir_resolve_type(ira, param_type_value);
|
||||
if (type_is_invalid(param_type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
if ((err = type_ensure_zero_bits_known(ira->codegen, param_type)))
|
||||
if ((err = type_resolve(ira->codegen, param_type, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
if (type_requires_comptime(param_type)) {
|
||||
if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
|
||||
@@ -19914,7 +20024,7 @@ static ZigType *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstructionPanic
|
||||
}
|
||||
|
||||
ZigType *u8_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
|
||||
true, false, PtrLenUnknown, get_abi_alignment(ira->codegen, ira->codegen->builtin_types.entry_u8), 0, 0);
|
||||
true, false, PtrLenUnknown, 0, 0, 0);
|
||||
ZigType *str_type = get_slice_type(ira->codegen, u8_ptr_type);
|
||||
IrInstruction *casted_msg = ir_implicit_cast(ira, msg, str_type);
|
||||
if (type_is_invalid(casted_msg->value.type))
|
||||
@@ -19927,6 +20037,8 @@ static ZigType *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstructionPanic
|
||||
}
|
||||
|
||||
static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint32_t align_bytes, bool safety_check_on) {
|
||||
Error err;
|
||||
|
||||
ZigType *target_type = target->value.type;
|
||||
assert(!type_is_invalid(target_type));
|
||||
|
||||
@@ -19935,7 +20047,8 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3
|
||||
|
||||
if (target_type->id == ZigTypeIdPointer) {
|
||||
result_type = adjust_ptr_align(ira->codegen, target_type, align_bytes);
|
||||
old_align_bytes = target_type->data.pointer.alignment;
|
||||
if ((err = resolve_ptr_align(ira, target_type, &old_align_bytes)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
} else if (target_type->id == ZigTypeIdFn) {
|
||||
FnTypeId fn_type_id = target_type->data.fn.fn_type_id;
|
||||
old_align_bytes = fn_type_id.alignment;
|
||||
@@ -19945,7 +20058,8 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3
|
||||
target_type->data.maybe.child_type->id == ZigTypeIdPointer)
|
||||
{
|
||||
ZigType *ptr_type = target_type->data.maybe.child_type;
|
||||
old_align_bytes = ptr_type->data.pointer.alignment;
|
||||
if ((err = resolve_ptr_align(ira, ptr_type, &old_align_bytes)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
ZigType *better_ptr_type = adjust_ptr_align(ira->codegen, ptr_type, align_bytes);
|
||||
|
||||
result_type = get_optional_type(ira->codegen, better_ptr_type);
|
||||
@@ -19959,7 +20073,8 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3
|
||||
result_type = get_optional_type(ira->codegen, fn_type);
|
||||
} else if (is_slice(target_type)) {
|
||||
ZigType *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index].type_entry;
|
||||
old_align_bytes = slice_ptr_type->data.pointer.alignment;
|
||||
if ((err = resolve_ptr_align(ira, slice_ptr_type, &old_align_bytes)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
ZigType *result_ptr_type = adjust_ptr_align(ira->codegen, slice_ptr_type, align_bytes);
|
||||
result_type = get_slice_type(ira->codegen, result_ptr_type);
|
||||
} else {
|
||||
@@ -20038,8 +20153,13 @@ static ZigType *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtr
|
||||
return dest_type;
|
||||
}
|
||||
|
||||
uint32_t src_align_bytes = get_ptr_align(src_type);
|
||||
uint32_t dest_align_bytes = get_ptr_align(dest_type);
|
||||
uint32_t src_align_bytes;
|
||||
if ((err = resolve_ptr_align(ira, src_type, &src_align_bytes)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
uint32_t dest_align_bytes;
|
||||
if ((err = resolve_ptr_align(ira, dest_type, &dest_align_bytes)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
if (dest_align_bytes > src_align_bytes) {
|
||||
ErrorMsg *msg = ir_add_error(ira, &instruction->base, buf_sprintf("cast increases pointer alignment"));
|
||||
@@ -20056,7 +20176,7 @@ static ZigType *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtr
|
||||
|
||||
// Keep the bigger alignment, it can only help-
|
||||
// unless the target is zero bits.
|
||||
if ((err = type_ensure_zero_bits_known(ira->codegen, dest_type)))
|
||||
if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
IrInstruction *result;
|
||||
@@ -20080,7 +20200,6 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdUnreachable:
|
||||
case ZigTypeIdComptimeFloat:
|
||||
case ZigTypeIdComptimeInt:
|
||||
@@ -20147,7 +20266,6 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdUnreachable:
|
||||
case ZigTypeIdComptimeFloat:
|
||||
case ZigTypeIdComptimeInt:
|
||||
@@ -20227,7 +20345,6 @@ static ZigType *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstructionBit
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdUnreachable:
|
||||
case ZigTypeIdComptimeFloat:
|
||||
case ZigTypeIdComptimeInt:
|
||||
@@ -20253,7 +20370,6 @@ static ZigType *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstructionBit
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBlock:
|
||||
case ZigTypeIdUnreachable:
|
||||
case ZigTypeIdComptimeFloat:
|
||||
case ZigTypeIdComptimeInt:
|
||||
@@ -20308,7 +20424,7 @@ static ZigType *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstructionI
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
if ((err = type_ensure_zero_bits_known(ira->codegen, dest_type)))
|
||||
if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
if (!type_has_bits(dest_type)) {
|
||||
ir_add_error(ira, dest_type_value,
|
||||
@@ -20459,12 +20575,15 @@ static ZigType *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstructionPtr
|
||||
if (instruction->align_value != nullptr) {
|
||||
if (!ir_resolve_align(ira, instruction->align_value->other, &align_bytes))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
} else {
|
||||
if ((err = type_ensure_zero_bits_known(ira->codegen, child_type)))
|
||||
if ((err = type_resolve(ira->codegen, child_type, ResolveStatusAlignmentKnown)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
align_bytes = get_abi_alignment(ira->codegen, child_type);
|
||||
} else {
|
||||
if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
align_bytes = 0;
|
||||
}
|
||||
|
||||
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
out_val->data.x_type = get_pointer_to_type_extra(ira->codegen, child_type,
|
||||
instruction->is_const, instruction->is_volatile,
|
||||
@@ -21108,7 +21227,7 @@ static ZigType *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstruction
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
if ((err = type_ensure_zero_bits_known(ira->codegen, target->value.type)))
|
||||
if ((err = type_resolve(ira->codegen, target->value.type, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
ZigType *tag_type = target->value.type->data.enumeration.tag_int_type;
|
||||
@@ -21131,7 +21250,7 @@ static ZigType *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInstruction
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
if ((err = type_ensure_zero_bits_known(ira->codegen, dest_type)))
|
||||
if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
ZigType *tag_type = dest_type->data.enumeration.tag_int_type;
|
||||
|
||||
+18
-61
@@ -5,7 +5,6 @@
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "link.hpp"
|
||||
#include "os.hpp"
|
||||
#include "config.h"
|
||||
#include "codegen.hpp"
|
||||
@@ -13,7 +12,6 @@
|
||||
|
||||
struct LinkJob {
|
||||
CodeGen *codegen;
|
||||
Buf out_file;
|
||||
ZigList<const char *> args;
|
||||
bool link_in_crt;
|
||||
HashMap<Buf *, bool, buf_hash, buf_eql_buf> rpath_table;
|
||||
@@ -44,8 +42,6 @@ static Buf *build_o_raw(CodeGen *parent_gen, const char *oname, Buf *full_path)
|
||||
child_gen->verbose_llvm_ir = parent_gen->verbose_llvm_ir;
|
||||
child_gen->verbose_cimport = parent_gen->verbose_cimport;
|
||||
|
||||
codegen_set_cache_dir(child_gen, parent_gen->cache_dir);
|
||||
|
||||
codegen_set_strip(child_gen, parent_gen->strip_debug_symbols);
|
||||
codegen_set_is_static(child_gen, parent_gen->is_static);
|
||||
|
||||
@@ -62,16 +58,9 @@ static Buf *build_o_raw(CodeGen *parent_gen, const char *oname, Buf *full_path)
|
||||
new_link_lib->provided_explicitly = link_lib->provided_explicitly;
|
||||
}
|
||||
|
||||
codegen_build(child_gen);
|
||||
const char *o_ext = target_o_file_ext(&child_gen->zig_target);
|
||||
Buf *o_out_name = buf_sprintf("%s%s", oname, o_ext);
|
||||
Buf *output_path = buf_alloc();
|
||||
os_path_join(&parent_gen->cache_dir, o_out_name, output_path);
|
||||
codegen_link(child_gen, buf_ptr(output_path));
|
||||
|
||||
codegen_destroy(child_gen);
|
||||
|
||||
return output_path;
|
||||
child_gen->enable_cache = true;
|
||||
codegen_build_and_link(child_gen);
|
||||
return &child_gen->output_file_path;
|
||||
}
|
||||
|
||||
static Buf *build_o(CodeGen *parent_gen, const char *oname) {
|
||||
@@ -239,15 +228,15 @@ static void construct_linker_job_elf(LinkJob *lj) {
|
||||
} else if (shared) {
|
||||
lj->args.append("-shared");
|
||||
|
||||
if (buf_len(&lj->out_file) == 0) {
|
||||
buf_appendf(&lj->out_file, "lib%s.so.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize "",
|
||||
if (buf_len(&g->output_file_path) == 0) {
|
||||
buf_appendf(&g->output_file_path, "lib%s.so.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize "",
|
||||
buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch);
|
||||
}
|
||||
soname = buf_sprintf("lib%s.so.%" ZIG_PRI_usize "", buf_ptr(g->root_out_name), g->version_major);
|
||||
}
|
||||
|
||||
lj->args.append("-o");
|
||||
lj->args.append(buf_ptr(&lj->out_file));
|
||||
lj->args.append(buf_ptr(&g->output_file_path));
|
||||
|
||||
if (lj->link_in_crt) {
|
||||
const char *crt1o;
|
||||
@@ -399,7 +388,7 @@ static void construct_linker_job_wasm(LinkJob *lj) {
|
||||
|
||||
lj->args.append("--relocatable"); // So lld doesn't look for _start.
|
||||
lj->args.append("-o");
|
||||
lj->args.append(buf_ptr(&lj->out_file));
|
||||
lj->args.append(buf_ptr(&g->output_file_path));
|
||||
|
||||
// .o files
|
||||
for (size_t i = 0; i < g->link_objects.length; i += 1) {
|
||||
@@ -480,7 +469,7 @@ static void construct_linker_job_coff(LinkJob *lj) {
|
||||
// }
|
||||
//}
|
||||
|
||||
lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&lj->out_file))));
|
||||
lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path))));
|
||||
|
||||
if (g->libc_link_lib != nullptr) {
|
||||
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->msvc_lib_dir))));
|
||||
@@ -587,11 +576,11 @@ static void construct_linker_job_coff(LinkJob *lj) {
|
||||
buf_appendf(def_contents, "\n");
|
||||
|
||||
Buf *def_path = buf_alloc();
|
||||
os_path_join(&g->cache_dir, buf_sprintf("%s.def", buf_ptr(link_lib->name)), def_path);
|
||||
os_path_join(&g->artifact_dir, buf_sprintf("%s.def", buf_ptr(link_lib->name)), def_path);
|
||||
os_write_file(def_path, def_contents);
|
||||
|
||||
Buf *generated_lib_path = buf_alloc();
|
||||
os_path_join(&g->cache_dir, buf_sprintf("%s.lib", buf_ptr(link_lib->name)), generated_lib_path);
|
||||
os_path_join(&g->artifact_dir, buf_sprintf("%s.lib", buf_ptr(link_lib->name)), generated_lib_path);
|
||||
|
||||
gen_lib_args.resize(0);
|
||||
gen_lib_args.append("link");
|
||||
@@ -799,8 +788,8 @@ static void construct_linker_job_macho(LinkJob *lj) {
|
||||
//lj->args.append("-install_name");
|
||||
//lj->args.append(buf_ptr(dylib_install_name));
|
||||
|
||||
if (buf_len(&lj->out_file) == 0) {
|
||||
buf_appendf(&lj->out_file, "lib%s.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".dylib",
|
||||
if (buf_len(&g->output_file_path) == 0) {
|
||||
buf_appendf(&g->output_file_path, "lib%s.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".dylib",
|
||||
buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch);
|
||||
}
|
||||
}
|
||||
@@ -834,13 +823,13 @@ static void construct_linker_job_macho(LinkJob *lj) {
|
||||
}
|
||||
|
||||
lj->args.append("-o");
|
||||
lj->args.append(buf_ptr(&lj->out_file));
|
||||
lj->args.append(buf_ptr(&g->output_file_path));
|
||||
|
||||
for (size_t i = 0; i < g->rpath_list.length; i += 1) {
|
||||
Buf *rpath = g->rpath_list.at(i);
|
||||
add_rpath(lj, rpath);
|
||||
}
|
||||
add_rpath(lj, &lj->out_file);
|
||||
add_rpath(lj, &g->output_file_path);
|
||||
|
||||
if (shared) {
|
||||
lj->args.append("-headerpad_max_install_names");
|
||||
@@ -944,7 +933,8 @@ static void construct_linker_job(LinkJob *lj) {
|
||||
}
|
||||
}
|
||||
|
||||
void codegen_link(CodeGen *g, const char *out_file) {
|
||||
void codegen_link(CodeGen *g) {
|
||||
assert(g->out_type != OutTypeObj);
|
||||
codegen_add_time_event(g, "Build Dependencies");
|
||||
|
||||
LinkJob lj = {0};
|
||||
@@ -955,11 +945,6 @@ void codegen_link(CodeGen *g, const char *out_file) {
|
||||
|
||||
lj.rpath_table.init(4);
|
||||
lj.codegen = g;
|
||||
if (out_file) {
|
||||
buf_init_from_str(&lj.out_file, out_file);
|
||||
} else {
|
||||
buf_resize(&lj.out_file, 0);
|
||||
}
|
||||
|
||||
if (g->verbose_llvm_ir) {
|
||||
fprintf(stderr, "\nOptimization:\n");
|
||||
@@ -968,35 +953,9 @@ void codegen_link(CodeGen *g, const char *out_file) {
|
||||
LLVMDumpModule(g->module);
|
||||
}
|
||||
|
||||
bool override_out_file = (buf_len(&lj.out_file) != 0);
|
||||
if (!override_out_file) {
|
||||
assert(g->root_out_name);
|
||||
|
||||
buf_init_from_buf(&lj.out_file, g->root_out_name);
|
||||
if (g->out_type == OutTypeExe) {
|
||||
buf_append_str(&lj.out_file, target_exe_file_ext(&g->zig_target));
|
||||
}
|
||||
}
|
||||
|
||||
if (g->out_type == OutTypeObj) {
|
||||
if (override_out_file) {
|
||||
assert(g->link_objects.length == 1);
|
||||
Buf *o_file_path = g->link_objects.at(0);
|
||||
int err;
|
||||
if ((err = os_rename(o_file_path, &lj.out_file))) {
|
||||
zig_panic("unable to rename object file %s into final output %s: %s", buf_ptr(o_file_path), buf_ptr(&lj.out_file), err_str(err));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (g->out_type == OutTypeLib && g->is_static) {
|
||||
// invoke `ar`
|
||||
// example:
|
||||
// # static link into libfoo.a
|
||||
// ar rcs libfoo.a foo1.o foo2.o
|
||||
zig_panic("TODO invoke ar");
|
||||
return;
|
||||
fprintf(stderr, "Zig does not yet support creating static libraries\nSee https://github.com/ziglang/zig/issues/1493\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
lj.link_in_crt = (g->libc_link_lib != nullptr && g->out_type == OutTypeExe);
|
||||
@@ -1019,6 +978,4 @@ void codegen_link(CodeGen *g, const char *out_file) {
|
||||
fprintf(stderr, "%s\n", buf_ptr(&diag));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
codegen_add_time_event(g, "Done");
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Andrew Kelley
|
||||
*
|
||||
* This file is part of zig, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#ifndef ZIG_LINK_HPP
|
||||
#define ZIG_LINK_HPP
|
||||
|
||||
#include "all_types.hpp"
|
||||
|
||||
void codegen_link(CodeGen *g, const char *out_file);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
+95
-54
@@ -8,9 +8,9 @@
|
||||
#include "ast_render.hpp"
|
||||
#include "buffer.hpp"
|
||||
#include "codegen.hpp"
|
||||
#include "compiler.hpp"
|
||||
#include "config.h"
|
||||
#include "error.hpp"
|
||||
#include "link.hpp"
|
||||
#include "os.hpp"
|
||||
#include "target.hpp"
|
||||
|
||||
@@ -24,6 +24,7 @@ static int usage(const char *arg0) {
|
||||
" build-lib [source] create library from source or object files\n"
|
||||
" build-obj [source] create object from source or assembly\n"
|
||||
" builtin show the source code of that @import(\"builtin\")\n"
|
||||
" id print the base64-encoded compiler id\n"
|
||||
" run [source] create executable and run immediately\n"
|
||||
" translate-c [source] convert c code to zig code\n"
|
||||
" targets list available compilation targets\n"
|
||||
@@ -33,9 +34,10 @@ static int usage(const char *arg0) {
|
||||
"Compile Options:\n"
|
||||
" --assembly [source] add assembly file to build\n"
|
||||
" --cache-dir [path] override the cache directory\n"
|
||||
" --cache [auto|off|on] build to the global cache and print output path to stdout\n"
|
||||
" --color [auto|off|on] enable or disable colored error messages\n"
|
||||
" --emit [asm|bin|llvm-ir] emit a specific file format as compilation output\n"
|
||||
" --enable-timing-info print timing diagnostics\n"
|
||||
" -ftime-report print timing diagnostics\n"
|
||||
" --libc-include-dir [path] directory where libc stdlib.h resides\n"
|
||||
" --name [name] override output name\n"
|
||||
" --output [file] override destination path\n"
|
||||
@@ -256,6 +258,24 @@ static void add_package(CodeGen *g, CliPkg *cli_pkg, PackageTableEntry *pkg) {
|
||||
}
|
||||
}
|
||||
|
||||
enum CacheOpt {
|
||||
CacheOptAuto,
|
||||
CacheOptOn,
|
||||
CacheOptOff,
|
||||
};
|
||||
|
||||
static bool get_cache_opt(CacheOpt opt, bool default_value) {
|
||||
switch (opt) {
|
||||
case CacheOptAuto:
|
||||
return default_value;
|
||||
case CacheOptOn:
|
||||
return true;
|
||||
case CacheOptOff:
|
||||
return false;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc == 2 && strcmp(argv[1], "BUILD_INFO") == 0) {
|
||||
printf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
|
||||
@@ -270,6 +290,17 @@ int main(int argc, char **argv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (argc == 2 && strcmp(argv[1], "id") == 0) {
|
||||
Error err;
|
||||
Buf *compiler_id;
|
||||
if ((err = get_compiler_id(&compiler_id))) {
|
||||
fprintf(stderr, "Unable to determine compiler id: %s\n", err_str(err));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
printf("%s\n", buf_ptr(compiler_id));
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
os_init();
|
||||
|
||||
char *arg0 = argv[0];
|
||||
@@ -289,6 +320,7 @@ int main(int argc, char **argv) {
|
||||
bool verbose_llvm_ir = false;
|
||||
bool verbose_cimport = false;
|
||||
ErrColor color = ErrColorAuto;
|
||||
CacheOpt enable_cache = CacheOptAuto;
|
||||
const char *libc_lib_dir = nullptr;
|
||||
const char *libc_static_lib_dir = nullptr;
|
||||
const char *libc_include_dir = nullptr;
|
||||
@@ -325,8 +357,7 @@ int main(int argc, char **argv) {
|
||||
CliPkg *cur_pkg = allocate<CliPkg>(1);
|
||||
BuildMode build_mode = BuildModeDebug;
|
||||
ZigList<const char *> test_exec_args = {0};
|
||||
int comptime_args_end = 0;
|
||||
int runtime_args_start = argc;
|
||||
int runtime_args_start = -1;
|
||||
bool no_rosegment_workaround = false;
|
||||
|
||||
if (argc >= 2 && strcmp(argv[1], "build") == 0) {
|
||||
@@ -370,8 +401,9 @@ int main(int argc, char **argv) {
|
||||
Buf *build_runner_path = buf_alloc();
|
||||
os_path_join(special_dir, buf_create_from_str("build_runner.zig"), build_runner_path);
|
||||
|
||||
|
||||
CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, zig_lib_dir_buf);
|
||||
g->enable_time_report = timing_info;
|
||||
buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name);
|
||||
codegen_set_out_name(g, buf_create_from_str("build"));
|
||||
|
||||
Buf *build_file_buf = buf_create_from_str(build_file);
|
||||
@@ -380,6 +412,7 @@ int main(int argc, char **argv) {
|
||||
Buf build_file_dirname = BUF_INIT;
|
||||
os_path_split(&build_file_abs, &build_file_dirname, &build_file_basename);
|
||||
|
||||
|
||||
Buf full_cache_dir = BUF_INIT;
|
||||
if (cache_dir == nullptr) {
|
||||
os_path_join(&build_file_dirname, buf_create_from_str(default_zig_cache_name), &full_cache_dir);
|
||||
@@ -388,10 +421,6 @@ int main(int argc, char **argv) {
|
||||
full_cache_dir = os_path_resolve(&cache_dir_buf, 1);
|
||||
}
|
||||
|
||||
Buf *path_to_build_exe = buf_alloc();
|
||||
os_path_join(&full_cache_dir, buf_create_from_str("build"), path_to_build_exe);
|
||||
codegen_set_cache_dir(g, full_cache_dir);
|
||||
|
||||
args.items[1] = buf_ptr(&build_file_dirname);
|
||||
args.items[2] = buf_ptr(&full_cache_dir);
|
||||
|
||||
@@ -459,15 +488,14 @@ int main(int argc, char **argv) {
|
||||
PackageTableEntry *build_pkg = codegen_create_package(g, buf_ptr(&build_file_dirname),
|
||||
buf_ptr(&build_file_basename));
|
||||
g->root_package->package_table.put(buf_create_from_str("@build"), build_pkg);
|
||||
codegen_build(g);
|
||||
codegen_link(g, buf_ptr(path_to_build_exe));
|
||||
codegen_destroy(g);
|
||||
g->enable_cache = get_cache_opt(enable_cache, true);
|
||||
codegen_build_and_link(g);
|
||||
|
||||
Termination term;
|
||||
os_spawn_process(buf_ptr(path_to_build_exe), args, &term);
|
||||
os_spawn_process(buf_ptr(&g->output_file_path), args, &term);
|
||||
if (term.how != TerminationIdClean || term.code != 0) {
|
||||
fprintf(stderr, "\nBuild failed. The following command failed:\n");
|
||||
fprintf(stderr, "%s", buf_ptr(path_to_build_exe));
|
||||
fprintf(stderr, "%s", buf_ptr(&g->output_file_path));
|
||||
for (size_t i = 0; i < args.length; i += 1) {
|
||||
fprintf(stderr, " %s", args.at(i));
|
||||
}
|
||||
@@ -476,15 +504,11 @@ int main(int argc, char **argv) {
|
||||
return (term.how == TerminationIdClean) ? term.code : -1;
|
||||
}
|
||||
|
||||
for (int i = 1; i < argc; i += 1, comptime_args_end += 1) {
|
||||
for (int i = 1; i < argc; i += 1) {
|
||||
char *arg = argv[i];
|
||||
|
||||
if (arg[0] == '-') {
|
||||
if (strcmp(arg, "--") == 0) {
|
||||
// ignore -- from both compile and runtime arg sets
|
||||
runtime_args_start = i + 1;
|
||||
break;
|
||||
} else if (strcmp(arg, "--release-fast") == 0) {
|
||||
if (strcmp(arg, "--release-fast") == 0) {
|
||||
build_mode = BuildModeFastRelease;
|
||||
} else if (strcmp(arg, "--release-safe") == 0) {
|
||||
build_mode = BuildModeSafeRelease;
|
||||
@@ -516,7 +540,7 @@ int main(int argc, char **argv) {
|
||||
no_rosegment_workaround = true;
|
||||
} else if (strcmp(arg, "--each-lib-rpath") == 0) {
|
||||
each_lib_rpath = true;
|
||||
} else if (strcmp(arg, "--enable-timing-info") == 0) {
|
||||
} else if (strcmp(arg, "-ftime-report") == 0) {
|
||||
timing_info = true;
|
||||
} else if (strcmp(arg, "--test-cmd-bin") == 0) {
|
||||
test_exec_args.append(nullptr);
|
||||
@@ -562,6 +586,17 @@ int main(int argc, char **argv) {
|
||||
fprintf(stderr, "--color options are 'auto', 'on', or 'off'\n");
|
||||
return usage(arg0);
|
||||
}
|
||||
} else if (strcmp(arg, "--cache") == 0) {
|
||||
if (strcmp(argv[i], "auto") == 0) {
|
||||
enable_cache = CacheOptAuto;
|
||||
} else if (strcmp(argv[i], "on") == 0) {
|
||||
enable_cache = CacheOptOn;
|
||||
} else if (strcmp(argv[i], "off") == 0) {
|
||||
enable_cache = CacheOptOff;
|
||||
} else {
|
||||
fprintf(stderr, "--cache options are 'auto', 'on', or 'off'\n");
|
||||
return usage(arg0);
|
||||
}
|
||||
} else if (strcmp(arg, "--emit") == 0) {
|
||||
if (strcmp(argv[i], "asm") == 0) {
|
||||
emit_file_type = EmitFileTypeAssembly;
|
||||
@@ -681,6 +716,10 @@ int main(int argc, char **argv) {
|
||||
case CmdTest:
|
||||
if (!in_file) {
|
||||
in_file = arg;
|
||||
if (cmd == CmdRun) {
|
||||
runtime_args_start = i + 1;
|
||||
break; // rest of the args are for the program
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Unexpected extra parameter: %s\n", arg);
|
||||
return usage(arg0);
|
||||
@@ -790,32 +829,18 @@ int main(int argc, char **argv) {
|
||||
|
||||
Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf;
|
||||
|
||||
Buf full_cache_dir = BUF_INIT;
|
||||
Buf *run_exec_path = buf_alloc();
|
||||
if (cmd == CmdRun) {
|
||||
if (buf_out_name == nullptr) {
|
||||
buf_out_name = buf_create_from_str("run");
|
||||
}
|
||||
|
||||
Buf *global_cache_dir = buf_alloc();
|
||||
os_get_global_cache_directory(global_cache_dir);
|
||||
os_path_join(global_cache_dir, buf_out_name, run_exec_path);
|
||||
full_cache_dir = os_path_resolve(&global_cache_dir, 1);
|
||||
|
||||
out_file = buf_ptr(run_exec_path);
|
||||
} else {
|
||||
Buf *resolve_paths = buf_create_from_str((cache_dir == nullptr) ? default_zig_cache_name : cache_dir);
|
||||
full_cache_dir = os_path_resolve(&resolve_paths, 1);
|
||||
if (cmd == CmdRun && buf_out_name == nullptr) {
|
||||
buf_out_name = buf_create_from_str("run");
|
||||
}
|
||||
|
||||
Buf *zig_lib_dir_buf = resolve_zig_lib_dir();
|
||||
|
||||
CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, zig_lib_dir_buf);
|
||||
g->enable_time_report = timing_info;
|
||||
buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name);
|
||||
codegen_set_out_name(g, buf_out_name);
|
||||
codegen_set_lib_version(g, ver_major, ver_minor, ver_patch);
|
||||
codegen_set_is_test(g, cmd == CmdTest);
|
||||
codegen_set_linker_script(g, linker_script);
|
||||
codegen_set_cache_dir(g, full_cache_dir);
|
||||
if (each_lib_rpath)
|
||||
codegen_set_each_lib_rpath(g, each_lib_rpath);
|
||||
|
||||
@@ -885,6 +910,8 @@ int main(int argc, char **argv) {
|
||||
codegen_set_test_name_prefix(g, buf_create_from_str(test_name_prefix));
|
||||
}
|
||||
|
||||
if (out_file)
|
||||
codegen_set_output_path(g, buf_create_from_str(out_file));
|
||||
if (out_file_h)
|
||||
codegen_set_output_h_path(g, buf_create_from_str(out_file_h));
|
||||
|
||||
@@ -904,8 +931,8 @@ int main(int argc, char **argv) {
|
||||
if (cmd == CmdBuild || cmd == CmdRun) {
|
||||
codegen_set_emit_file_type(g, emit_file_type);
|
||||
|
||||
codegen_build(g);
|
||||
codegen_link(g, out_file);
|
||||
g->enable_cache = get_cache_opt(enable_cache, cmd == CmdRun);
|
||||
codegen_build_and_link(g);
|
||||
if (timing_info)
|
||||
codegen_print_timing_report(g, stdout);
|
||||
|
||||
@@ -915,12 +942,26 @@ int main(int argc, char **argv) {
|
||||
args.append(argv[i]);
|
||||
}
|
||||
|
||||
Termination term;
|
||||
os_spawn_process(buf_ptr(run_exec_path), args, &term);
|
||||
return term.code;
|
||||
}
|
||||
const char *exec_path = buf_ptr(&g->output_file_path);
|
||||
args.append(nullptr);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
os_execv(exec_path, args.items);
|
||||
|
||||
args.pop();
|
||||
Termination term;
|
||||
os_spawn_process(exec_path, args, &term);
|
||||
return term.code;
|
||||
} else if (cmd == CmdBuild) {
|
||||
if (g->enable_cache) {
|
||||
printf("%s\n", buf_ptr(&g->output_file_path));
|
||||
if (g->out_h_path != nullptr) {
|
||||
printf("%s\n", buf_ptr(g->out_h_path));
|
||||
}
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
} else if (cmd == CmdTranslateC) {
|
||||
codegen_translate_c(g, in_file_buf);
|
||||
ast_render(g, stdout, g->root_import->root, 4);
|
||||
@@ -933,11 +974,16 @@ int main(int argc, char **argv) {
|
||||
ZigTarget native;
|
||||
get_native_target(&native);
|
||||
|
||||
ZigTarget *non_null_target = target ? target : &native;
|
||||
g->enable_cache = get_cache_opt(enable_cache, false);
|
||||
codegen_build_and_link(g);
|
||||
|
||||
Buf *test_exe_name = buf_sprintf("test%s", target_exe_file_ext(non_null_target));
|
||||
if (timing_info) {
|
||||
codegen_print_timing_report(g, stdout);
|
||||
}
|
||||
|
||||
Buf *test_exe_path_unresolved = &g->output_file_path;
|
||||
Buf *test_exe_path = buf_alloc();
|
||||
os_path_join(&full_cache_dir, test_exe_name, test_exe_path);
|
||||
*test_exe_path = os_path_resolve(&test_exe_path_unresolved, 1);
|
||||
|
||||
for (size_t i = 0; i < test_exec_args.length; i += 1) {
|
||||
if (test_exec_args.items[i] == nullptr) {
|
||||
@@ -945,9 +991,6 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
}
|
||||
|
||||
codegen_build(g);
|
||||
codegen_link(g, buf_ptr(test_exe_path));
|
||||
|
||||
if (!target_can_exec(&native, target)) {
|
||||
fprintf(stderr, "Created %s but skipping execution because it is non-native.\n",
|
||||
buf_ptr(test_exe_path));
|
||||
@@ -969,8 +1012,6 @@ int main(int argc, char **argv) {
|
||||
if (term.how != TerminationIdClean || term.code != 0) {
|
||||
fprintf(stderr, "\nTests failed. Use the following command to reproduce the failure:\n");
|
||||
fprintf(stderr, "%s\n", buf_ptr(test_exe_path));
|
||||
} else if (timing_info) {
|
||||
codegen_print_timing_report(g, stdout);
|
||||
}
|
||||
return (term.how == TerminationIdClean) ? term.code : -1;
|
||||
} else {
|
||||
|
||||
+479
-120
@@ -24,6 +24,7 @@
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
@@ -40,6 +41,10 @@ typedef SSIZE_T ssize_t;
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(ZIG_OS_LINUX)
|
||||
#include <link.h>
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__MACH__)
|
||||
#include <mach/clock.h>
|
||||
@@ -57,54 +62,6 @@ static clock_serv_t cclock;
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
// Ported from std/mem.zig.
|
||||
// Coordinate struct fields with memSplit function
|
||||
struct SplitIterator {
|
||||
size_t index;
|
||||
Slice<uint8_t> buffer;
|
||||
Slice<uint8_t> split_bytes;
|
||||
};
|
||||
|
||||
// Ported from std/mem.zig.
|
||||
static bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte) {
|
||||
for (size_t i = 0; i < self->split_bytes.len; i += 1) {
|
||||
if (byte == self->split_bytes.ptr[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ported from std/mem.zig.
|
||||
static Optional<Slice<uint8_t>> SplitIterator_next(SplitIterator *self) {
|
||||
// move to beginning of token
|
||||
while (self->index < self->buffer.len &&
|
||||
SplitIterator_isSplitByte(self, self->buffer.ptr[self->index]))
|
||||
{
|
||||
self->index += 1;
|
||||
}
|
||||
size_t start = self->index;
|
||||
if (start == self->buffer.len) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// move to end of token
|
||||
while (self->index < self->buffer.len &&
|
||||
!SplitIterator_isSplitByte(self, self->buffer.ptr[self->index]))
|
||||
{
|
||||
self->index += 1;
|
||||
}
|
||||
size_t end = self->index;
|
||||
|
||||
return Optional<Slice<uint8_t>>::some(self->buffer.slice(start, end));
|
||||
}
|
||||
|
||||
// Ported from std/mem.zig
|
||||
static SplitIterator memSplit(Slice<uint8_t> buffer, Slice<uint8_t> split_bytes) {
|
||||
return SplitIterator{0, buffer, split_bytes};
|
||||
}
|
||||
|
||||
|
||||
#if defined(ZIG_OS_POSIX)
|
||||
static void populate_termination(Termination *term, int status) {
|
||||
if (WIFEXITED(status)) {
|
||||
@@ -765,7 +722,7 @@ Buf os_path_resolve(Buf **paths_ptr, size_t paths_len) {
|
||||
#endif
|
||||
}
|
||||
|
||||
int os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) {
|
||||
Error os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) {
|
||||
static const ssize_t buf_size = 0x2000;
|
||||
buf_resize(out_buf, buf_size);
|
||||
ssize_t actual_buf_len = 0;
|
||||
@@ -801,7 +758,7 @@ int os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) {
|
||||
if (amt_read != buf_size) {
|
||||
if (feof(f)) {
|
||||
buf_resize(out_buf, actual_buf_len);
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
} else {
|
||||
return ErrorFileSystem;
|
||||
}
|
||||
@@ -813,13 +770,13 @@ int os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
int os_file_exists(Buf *full_path, bool *result) {
|
||||
Error os_file_exists(Buf *full_path, bool *result) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
*result = GetFileAttributes(buf_ptr(full_path)) != INVALID_FILE_ATTRIBUTES;
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
#else
|
||||
*result = access(buf_ptr(full_path), F_OK) != -1;
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -878,13 +835,15 @@ static int os_exec_process_posix(const char *exe, ZigList<const char *> &args,
|
||||
|
||||
FILE *stdout_f = fdopen(stdout_pipe[0], "rb");
|
||||
FILE *stderr_f = fdopen(stderr_pipe[0], "rb");
|
||||
os_fetch_file(stdout_f, out_stdout, false);
|
||||
os_fetch_file(stderr_f, out_stderr, false);
|
||||
Error err1 = os_fetch_file(stdout_f, out_stdout, false);
|
||||
Error err2 = os_fetch_file(stderr_f, out_stderr, false);
|
||||
|
||||
fclose(stdout_f);
|
||||
fclose(stderr_f);
|
||||
|
||||
return 0;
|
||||
if (err1) return err1;
|
||||
if (err2) return err2;
|
||||
return ErrorNone;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1016,6 +975,22 @@ static int os_exec_process_windows(const char *exe, ZigList<const char *> &args,
|
||||
}
|
||||
#endif
|
||||
|
||||
Error os_execv(const char *exe, const char **argv) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
return ErrorUnsupportedOperatingSystem;
|
||||
#else
|
||||
execv(exe, (char *const *)argv);
|
||||
switch (errno) {
|
||||
case ENOMEM:
|
||||
return ErrorSystemResources;
|
||||
case EIO:
|
||||
return ErrorFileSystem;
|
||||
default:
|
||||
return ErrorUnexpected;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int os_exec_process(const char *exe, ZigList<const char *> &args,
|
||||
Termination *term, Buf *out_stderr, Buf *out_stdout)
|
||||
{
|
||||
@@ -1092,7 +1067,7 @@ int os_copy_file(Buf *src_path, Buf *dest_path) {
|
||||
}
|
||||
}
|
||||
|
||||
int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) {
|
||||
Error os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) {
|
||||
FILE *f = fopen(buf_ptr(full_path), "rb");
|
||||
if (!f) {
|
||||
switch (errno) {
|
||||
@@ -1111,7 +1086,7 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) {
|
||||
return ErrorFileSystem;
|
||||
}
|
||||
}
|
||||
int result = os_fetch_file(f, out_contents, skip_shebang);
|
||||
Error result = os_fetch_file(f, out_contents, skip_shebang);
|
||||
fclose(f);
|
||||
return result;
|
||||
}
|
||||
@@ -1282,44 +1257,6 @@ int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(ZIG_OS_POSIX)
|
||||
int os_get_global_cache_directory(Buf *out_tmp_path) {
|
||||
const char *tmp_dir = getenv("TMPDIR");
|
||||
if (!tmp_dir) {
|
||||
tmp_dir = P_tmpdir;
|
||||
}
|
||||
|
||||
Buf *tmp_dir_buf = buf_create_from_str(tmp_dir);
|
||||
Buf *cache_dirname_buf = buf_create_from_str("zig-cache");
|
||||
|
||||
buf_resize(out_tmp_path, 0);
|
||||
os_path_join(tmp_dir_buf, cache_dirname_buf, out_tmp_path);
|
||||
|
||||
buf_deinit(tmp_dir_buf);
|
||||
buf_deinit(cache_dirname_buf);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
int os_get_global_cache_directory(Buf *out_tmp_path) {
|
||||
char tmp_dir[MAX_PATH + 1];
|
||||
if (GetTempPath(MAX_PATH, tmp_dir) == 0) {
|
||||
zig_panic("GetTempPath failed");
|
||||
}
|
||||
|
||||
Buf *tmp_dir_buf = buf_create_from_str(tmp_dir);
|
||||
Buf *cache_dirname_buf = buf_create_from_str("zig-cache");
|
||||
|
||||
buf_resize(out_tmp_path, 0);
|
||||
os_path_join(tmp_dir_buf, cache_dirname_buf, out_tmp_path);
|
||||
|
||||
buf_deinit(tmp_dir_buf);
|
||||
buf_deinit(cache_dirname_buf);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int os_delete_file(Buf *path) {
|
||||
if (remove(buf_ptr(path))) {
|
||||
return ErrorFileSystem;
|
||||
@@ -1368,16 +1305,16 @@ double os_get_time(void) {
|
||||
#endif
|
||||
}
|
||||
|
||||
int os_make_path(Buf *path) {
|
||||
Error os_make_path(Buf *path) {
|
||||
Buf resolved_path = os_path_resolve(&path, 1);
|
||||
|
||||
size_t end_index = buf_len(&resolved_path);
|
||||
int err;
|
||||
Error err;
|
||||
while (true) {
|
||||
if ((err = os_make_dir(buf_slice(&resolved_path, 0, end_index)))) {
|
||||
if (err == ErrorPathAlreadyExists) {
|
||||
if (end_index == buf_len(&resolved_path))
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
} else if (err == ErrorFileNotFound) {
|
||||
// march end_index backward until next path component
|
||||
while (true) {
|
||||
@@ -1391,7 +1328,7 @@ int os_make_path(Buf *path) {
|
||||
}
|
||||
}
|
||||
if (end_index == buf_len(&resolved_path))
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
// march end_index forward until next path component
|
||||
while (true) {
|
||||
end_index += 1;
|
||||
@@ -1399,10 +1336,10 @@ int os_make_path(Buf *path) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
int os_make_dir(Buf *path) {
|
||||
Error os_make_dir(Buf *path) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
if (!CreateDirectory(buf_ptr(path), NULL)) {
|
||||
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
||||
@@ -1413,7 +1350,7 @@ int os_make_dir(Buf *path) {
|
||||
return ErrorAccess;
|
||||
return ErrorUnexpected;
|
||||
}
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
#else
|
||||
if (mkdir(buf_ptr(path), 0755) == -1) {
|
||||
if (errno == EEXIST)
|
||||
@@ -1424,7 +1361,7 @@ int os_make_dir(Buf *path) {
|
||||
return ErrorAccess;
|
||||
return ErrorUnexpected;
|
||||
}
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1447,7 +1384,7 @@ int os_init(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int os_self_exe_path(Buf *out_path) {
|
||||
Error os_self_exe_path(Buf *out_path) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
buf_resize(out_path, 256);
|
||||
for (;;) {
|
||||
@@ -1457,7 +1394,7 @@ int os_self_exe_path(Buf *out_path) {
|
||||
}
|
||||
if (copied_amt < buf_len(out_path)) {
|
||||
buf_resize(out_path, copied_amt);
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
}
|
||||
buf_resize(out_path, buf_len(out_path) * 2);
|
||||
}
|
||||
@@ -1480,27 +1417,21 @@ int os_self_exe_path(Buf *out_path) {
|
||||
char *real_path = realpath(buf_ptr(tmp), buf_ptr(out_path));
|
||||
if (!real_path) {
|
||||
buf_init_from_buf(out_path, tmp);
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
// Resize out_path for the correct length.
|
||||
buf_resize(out_path, strlen(buf_ptr(out_path)));
|
||||
|
||||
return 0;
|
||||
return ErrorNone;
|
||||
#elif defined(ZIG_OS_LINUX)
|
||||
buf_resize(out_path, 256);
|
||||
for (;;) {
|
||||
ssize_t amt = readlink("/proc/self/exe", buf_ptr(out_path), buf_len(out_path));
|
||||
if (amt == -1) {
|
||||
return ErrorUnexpected;
|
||||
}
|
||||
if (amt == (ssize_t)buf_len(out_path)) {
|
||||
buf_resize(out_path, buf_len(out_path) * 2);
|
||||
continue;
|
||||
}
|
||||
buf_resize(out_path, amt);
|
||||
return 0;
|
||||
buf_resize(out_path, PATH_MAX);
|
||||
ssize_t amt = readlink("/proc/self/exe", buf_ptr(out_path), buf_len(out_path));
|
||||
if (amt == -1) {
|
||||
return ErrorUnexpected;
|
||||
}
|
||||
buf_resize(out_path, amt);
|
||||
return ErrorNone;
|
||||
#endif
|
||||
return ErrorFileNotFound;
|
||||
}
|
||||
@@ -1685,3 +1616,431 @@ int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchTy
|
||||
return ErrorFileNotFound;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
// Ported from std/unicode.zig
|
||||
struct Utf16LeIterator {
|
||||
uint8_t *bytes;
|
||||
size_t i;
|
||||
};
|
||||
|
||||
// Ported from std/unicode.zig
|
||||
static Utf16LeIterator Utf16LeIterator_init(WCHAR *ptr) {
|
||||
return {(uint8_t*)ptr, 0};
|
||||
}
|
||||
|
||||
// Ported from std/unicode.zig
|
||||
static Optional<uint32_t> Utf16LeIterator_nextCodepoint(Utf16LeIterator *it) {
|
||||
if (it->bytes[it->i] == 0 && it->bytes[it->i + 1] == 0)
|
||||
return {};
|
||||
uint32_t c0 = ((uint32_t)it->bytes[it->i]) | (((uint32_t)it->bytes[it->i + 1]) << 8);
|
||||
if (c0 & ~((uint32_t)0x03ff) == 0xd800) {
|
||||
// surrogate pair
|
||||
it->i += 2;
|
||||
assert(it->bytes[it->i] != 0 || it->bytes[it->i + 1] != 0);
|
||||
uint32_t c1 = ((uint32_t)it->bytes[it->i]) | (((uint32_t)it->bytes[it->i + 1]) << 8);
|
||||
assert(c1 & ~((uint32_t)0x03ff) == 0xdc00);
|
||||
it->i += 2;
|
||||
return Optional<uint32_t>::some(0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff)));
|
||||
} else {
|
||||
assert(c0 & ~((uint32_t)0x03ff) != 0xdc00);
|
||||
it->i += 2;
|
||||
return Optional<uint32_t>::some(c0);
|
||||
}
|
||||
}
|
||||
|
||||
// Ported from std/unicode.zig
|
||||
static uint8_t utf8CodepointSequenceLength(uint32_t c) {
|
||||
if (c < 0x80) return 1;
|
||||
if (c < 0x800) return 2;
|
||||
if (c < 0x10000) return 3;
|
||||
if (c < 0x110000) return 4;
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
// Ported from std/unicode.zig
|
||||
static size_t utf8Encode(uint32_t c, Slice<uint8_t> out) {
|
||||
size_t length = utf8CodepointSequenceLength(c);
|
||||
assert(out.len >= length);
|
||||
switch (length) {
|
||||
// The pattern for each is the same
|
||||
// - Increasing the initial shift by 6 each time
|
||||
// - Each time after the first shorten the shifted
|
||||
// value to a max of 0b111111 (63)
|
||||
case 1:
|
||||
out.ptr[0] = c; // Can just do 0 + codepoint for initial range
|
||||
break;
|
||||
case 2:
|
||||
out.ptr[0] = 0b11000000 | (c >> 6);
|
||||
out.ptr[1] = 0b10000000 | (c & 0b111111);
|
||||
break;
|
||||
case 3:
|
||||
assert(!(0xd800 <= c && c <= 0xdfff));
|
||||
out.ptr[0] = 0b11100000 | (c >> 12);
|
||||
out.ptr[1] = 0b10000000 | ((c >> 6) & 0b111111);
|
||||
out.ptr[2] = 0b10000000 | (c & 0b111111);
|
||||
break;
|
||||
case 4:
|
||||
out.ptr[0] = 0b11110000 | (c >> 18);
|
||||
out.ptr[1] = 0b10000000 | ((c >> 12) & 0b111111);
|
||||
out.ptr[2] = 0b10000000 | ((c >> 6) & 0b111111);
|
||||
out.ptr[3] = 0b10000000 | (c & 0b111111);
|
||||
break;
|
||||
default:
|
||||
zig_unreachable();
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
// Ported from std.unicode.utf16leToUtf8Alloc
|
||||
static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le) {
|
||||
// optimistically guess that it will all be ascii.
|
||||
buf_resize(out, 0);
|
||||
size_t out_index = 0;
|
||||
Utf16LeIterator it = Utf16LeIterator_init(utf16le);
|
||||
for (;;) {
|
||||
Optional<uint32_t> opt_codepoint = Utf16LeIterator_nextCodepoint(&it);
|
||||
if (!opt_codepoint.is_some) break;
|
||||
uint32_t codepoint = opt_codepoint.value;
|
||||
|
||||
size_t utf8_len = utf8CodepointSequenceLength(codepoint);
|
||||
buf_resize(out, buf_len(out) + utf8_len);
|
||||
utf8Encode(codepoint, {(uint8_t*)buf_ptr(out)+out_index, buf_len(out)-out_index});
|
||||
out_index += utf8_len;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Ported from std.os.getAppDataDir
|
||||
Error os_get_app_data_dir(Buf *out_path, const char *appname) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
Error err;
|
||||
WCHAR *dir_path_ptr;
|
||||
switch (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, nullptr, &dir_path_ptr)) {
|
||||
case S_OK:
|
||||
// defer os.windows.CoTaskMemFree(@ptrCast(*c_void, dir_path_ptr));
|
||||
utf16le_ptr_to_utf8(out_path, dir_path_ptr);
|
||||
CoTaskMemFree(dir_path_ptr);
|
||||
buf_appendf(out_path, "\\%s", appname);
|
||||
return ErrorNone;
|
||||
case E_OUTOFMEMORY:
|
||||
return ErrorNoMem;
|
||||
default:
|
||||
return ErrorUnexpected;
|
||||
}
|
||||
zig_unreachable();
|
||||
#elif defined(ZIG_OS_DARWIN)
|
||||
const char *home_dir = getenv("HOME");
|
||||
if (home_dir == nullptr) {
|
||||
// TODO use /etc/passwd
|
||||
return ErrorFileNotFound;
|
||||
}
|
||||
buf_resize(out_path, 0);
|
||||
buf_appendf(out_path, "%s/Library/Application Support/%s", home_dir, appname);
|
||||
return ErrorNone;
|
||||
#elif defined(ZIG_OS_LINUX)
|
||||
const char *home_dir = getenv("HOME");
|
||||
if (home_dir == nullptr) {
|
||||
// TODO use /etc/passwd
|
||||
return ErrorFileNotFound;
|
||||
}
|
||||
buf_resize(out_path, 0);
|
||||
buf_appendf(out_path, "%s/.local/share/%s", home_dir, appname);
|
||||
return ErrorNone;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if defined(ZIG_OS_LINUX)
|
||||
static int self_exe_shared_libs_callback(struct dl_phdr_info *info, size_t size, void *data) {
|
||||
ZigList<Buf *> *libs = reinterpret_cast< ZigList<Buf *> *>(data);
|
||||
if (info->dlpi_name[0] == '/') {
|
||||
libs->append(buf_create_from_str(info->dlpi_name));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
Error os_self_exe_shared_libs(ZigList<Buf *> &paths) {
|
||||
#if defined(ZIG_OS_LINUX)
|
||||
paths.resize(0);
|
||||
dl_iterate_phdr(self_exe_shared_libs_callback, &paths);
|
||||
return ErrorNone;
|
||||
#elif defined(ZIG_OS_DARWIN)
|
||||
paths.resize(0);
|
||||
uint32_t img_count = _dyld_image_count();
|
||||
for (uint32_t i = 0; i != img_count; i += 1) {
|
||||
const char *name = _dyld_get_image_name(i);
|
||||
paths.append(buf_create_from_str(name));
|
||||
}
|
||||
return ErrorNone;
|
||||
#elif defined(ZIG_OS_WINDOWS)
|
||||
// zig is built statically on windows, so we can return an empty list
|
||||
paths.resize(0);
|
||||
return ErrorNone;
|
||||
#else
|
||||
#error unimplemented
|
||||
#endif
|
||||
}
|
||||
|
||||
Error os_file_open_r(Buf *full_path, OsFile *out_file) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
// TODO use CreateFileW
|
||||
HANDLE result = CreateFileA(buf_ptr(full_path), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
|
||||
if (result == INVALID_HANDLE_VALUE) {
|
||||
DWORD err = GetLastError();
|
||||
switch (err) {
|
||||
case ERROR_SHARING_VIOLATION:
|
||||
return ErrorSharingViolation;
|
||||
case ERROR_ALREADY_EXISTS:
|
||||
return ErrorPathAlreadyExists;
|
||||
case ERROR_FILE_EXISTS:
|
||||
return ErrorPathAlreadyExists;
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
return ErrorFileNotFound;
|
||||
case ERROR_PATH_NOT_FOUND:
|
||||
return ErrorFileNotFound;
|
||||
case ERROR_ACCESS_DENIED:
|
||||
return ErrorAccess;
|
||||
case ERROR_PIPE_BUSY:
|
||||
return ErrorPipeBusy;
|
||||
default:
|
||||
return ErrorUnexpected;
|
||||
}
|
||||
}
|
||||
|
||||
*out_file = result;
|
||||
return ErrorNone;
|
||||
#else
|
||||
for (;;) {
|
||||
int fd = open(buf_ptr(full_path), O_RDONLY|O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
continue;
|
||||
case EINVAL:
|
||||
zig_unreachable();
|
||||
case EFAULT:
|
||||
zig_unreachable();
|
||||
case EACCES:
|
||||
return ErrorAccess;
|
||||
case EISDIR:
|
||||
return ErrorIsDir;
|
||||
case ENOENT:
|
||||
return ErrorFileNotFound;
|
||||
default:
|
||||
return ErrorFileSystem;
|
||||
}
|
||||
}
|
||||
*out_file = fd;
|
||||
return ErrorNone;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
for (;;) {
|
||||
HANDLE result = CreateFileA(buf_ptr(full_path), GENERIC_READ | GENERIC_WRITE,
|
||||
0, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
|
||||
if (result == INVALID_HANDLE_VALUE) {
|
||||
DWORD err = GetLastError();
|
||||
switch (err) {
|
||||
case ERROR_SHARING_VIOLATION:
|
||||
// TODO wait for the lock instead of sleeping
|
||||
Sleep(10);
|
||||
continue;
|
||||
case ERROR_ALREADY_EXISTS:
|
||||
return ErrorPathAlreadyExists;
|
||||
case ERROR_FILE_EXISTS:
|
||||
return ErrorPathAlreadyExists;
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
return ErrorFileNotFound;
|
||||
case ERROR_PATH_NOT_FOUND:
|
||||
return ErrorFileNotFound;
|
||||
case ERROR_ACCESS_DENIED:
|
||||
return ErrorAccess;
|
||||
case ERROR_PIPE_BUSY:
|
||||
return ErrorPipeBusy;
|
||||
default:
|
||||
return ErrorUnexpected;
|
||||
}
|
||||
}
|
||||
*out_file = result;
|
||||
return ErrorNone;
|
||||
}
|
||||
#else
|
||||
int fd;
|
||||
for (;;) {
|
||||
fd = open(buf_ptr(full_path), O_RDWR|O_CLOEXEC|O_CREAT, 0666);
|
||||
if (fd == -1) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
continue;
|
||||
case EINVAL:
|
||||
zig_unreachable();
|
||||
case EFAULT:
|
||||
zig_unreachable();
|
||||
case EACCES:
|
||||
return ErrorAccess;
|
||||
case EISDIR:
|
||||
return ErrorIsDir;
|
||||
case ENOENT:
|
||||
return ErrorFileNotFound;
|
||||
default:
|
||||
return ErrorFileSystem;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
for (;;) {
|
||||
struct flock lock;
|
||||
lock.l_type = F_WRLCK;
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = 0;
|
||||
lock.l_len = 0;
|
||||
if (fcntl(fd, F_SETLKW, &lock) == -1) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
continue;
|
||||
case EBADF:
|
||||
zig_unreachable();
|
||||
case EFAULT:
|
||||
zig_unreachable();
|
||||
case EINVAL:
|
||||
zig_unreachable();
|
||||
default:
|
||||
close(fd);
|
||||
return ErrorFileSystem;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
*out_file = fd;
|
||||
return ErrorNone;
|
||||
#endif
|
||||
}
|
||||
|
||||
Error os_file_mtime(OsFile file, OsTimeStamp *mtime) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
FILETIME last_write_time;
|
||||
if (!GetFileTime(file, nullptr, nullptr, &last_write_time))
|
||||
return ErrorUnexpected;
|
||||
mtime->sec = last_write_time.dwLowDateTime | (last_write_time.dwHighDateTime << 32);
|
||||
mtime->nsec = 0;
|
||||
return ErrorNone;
|
||||
#elif defined(ZIG_OS_LINUX)
|
||||
struct stat statbuf;
|
||||
if (fstat(file, &statbuf) == -1)
|
||||
return ErrorFileSystem;
|
||||
|
||||
mtime->sec = statbuf.st_mtim.tv_sec;
|
||||
mtime->nsec = statbuf.st_mtim.tv_nsec;
|
||||
return ErrorNone;
|
||||
#elif defined(ZIG_OS_DARWIN)
|
||||
struct stat statbuf;
|
||||
if (fstat(file, &statbuf) == -1)
|
||||
return ErrorFileSystem;
|
||||
|
||||
mtime->sec = statbuf.st_mtimespec.tv_sec;
|
||||
mtime->nsec = statbuf.st_mtimespec.tv_nsec;
|
||||
return ErrorNone;
|
||||
#else
|
||||
#error unimplemented
|
||||
#endif
|
||||
}
|
||||
|
||||
Error os_file_read(OsFile file, void *ptr, size_t *len) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
DWORD amt_read;
|
||||
if (ReadFile(file, ptr, *len, &amt_read, nullptr) == 0)
|
||||
return ErrorUnexpected;
|
||||
*len = amt_read;
|
||||
return ErrorNone;
|
||||
#else
|
||||
for (;;) {
|
||||
ssize_t rc = read(file, ptr, *len);
|
||||
if (rc == -1) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
continue;
|
||||
case EBADF:
|
||||
zig_unreachable();
|
||||
case EFAULT:
|
||||
zig_unreachable();
|
||||
case EISDIR:
|
||||
zig_unreachable();
|
||||
default:
|
||||
return ErrorFileSystem;
|
||||
}
|
||||
}
|
||||
*len = rc;
|
||||
return ErrorNone;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Error os_file_read_all(OsFile file, Buf *contents) {
|
||||
Error err;
|
||||
size_t index = 0;
|
||||
for (;;) {
|
||||
size_t amt = buf_len(contents) - index;
|
||||
|
||||
if (amt < 4096) {
|
||||
buf_resize(contents, buf_len(contents) + (4096 - amt));
|
||||
amt = buf_len(contents) - index;
|
||||
}
|
||||
|
||||
if ((err = os_file_read(file, buf_ptr(contents) + index, &amt)))
|
||||
return err;
|
||||
|
||||
if (amt == 0) {
|
||||
buf_resize(contents, index);
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
index += amt;
|
||||
}
|
||||
}
|
||||
|
||||
Error os_file_overwrite(OsFile file, Buf *contents) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
if (SetFilePointer(file, 0, nullptr, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
|
||||
return ErrorFileSystem;
|
||||
if (!SetEndOfFile(file))
|
||||
return ErrorFileSystem;
|
||||
if (!WriteFile(file, buf_ptr(contents), buf_len(contents), nullptr, nullptr))
|
||||
return ErrorFileSystem;
|
||||
return ErrorNone;
|
||||
#else
|
||||
if (lseek(file, 0, SEEK_SET) == -1)
|
||||
return ErrorFileSystem;
|
||||
if (ftruncate(file, 0) == -1)
|
||||
return ErrorFileSystem;
|
||||
for (;;) {
|
||||
if (write(file, buf_ptr(contents), buf_len(contents)) == -1) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
continue;
|
||||
case EINVAL:
|
||||
zig_unreachable();
|
||||
case EBADF:
|
||||
zig_unreachable();
|
||||
default:
|
||||
return ErrorFileSystem;
|
||||
}
|
||||
}
|
||||
return ErrorNone;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void os_file_close(OsFile file) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
CloseHandle(file);
|
||||
#else
|
||||
close(file);
|
||||
#endif
|
||||
}
|
||||
|
||||
+90
-67
@@ -13,77 +13,11 @@
|
||||
#include "error.hpp"
|
||||
#include "zig_llvm.h"
|
||||
#include "windows_sdk.h"
|
||||
#include "result.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
enum TermColor {
|
||||
TermColorRed,
|
||||
TermColorGreen,
|
||||
TermColorCyan,
|
||||
TermColorWhite,
|
||||
TermColorBold,
|
||||
TermColorReset,
|
||||
};
|
||||
|
||||
enum TerminationId {
|
||||
TerminationIdClean,
|
||||
TerminationIdSignaled,
|
||||
TerminationIdStopped,
|
||||
TerminationIdUnknown,
|
||||
};
|
||||
|
||||
struct Termination {
|
||||
TerminationId how;
|
||||
int code;
|
||||
};
|
||||
|
||||
int os_init(void);
|
||||
|
||||
void os_spawn_process(const char *exe, ZigList<const char *> &args, Termination *term);
|
||||
int os_exec_process(const char *exe, ZigList<const char *> &args,
|
||||
Termination *term, Buf *out_stderr, Buf *out_stdout);
|
||||
|
||||
void os_path_dirname(Buf *full_path, Buf *out_dirname);
|
||||
void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename);
|
||||
void os_path_extname(Buf *full_path, Buf *out_basename, Buf *out_extname);
|
||||
void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path);
|
||||
int os_path_real(Buf *rel_path, Buf *out_abs_path);
|
||||
Buf os_path_resolve(Buf **paths_ptr, size_t paths_len);
|
||||
bool os_path_is_absolute(Buf *path);
|
||||
|
||||
int os_get_global_cache_directory(Buf *out_tmp_path);
|
||||
|
||||
int os_make_path(Buf *path);
|
||||
int os_make_dir(Buf *path);
|
||||
|
||||
void os_write_file(Buf *full_path, Buf *contents);
|
||||
int os_copy_file(Buf *src_path, Buf *dest_path);
|
||||
|
||||
int os_fetch_file(FILE *file, Buf *out_contents, bool skip_shebang);
|
||||
int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang);
|
||||
|
||||
int os_get_cwd(Buf *out_cwd);
|
||||
|
||||
bool os_stderr_tty(void);
|
||||
void os_stderr_set_color(TermColor color);
|
||||
|
||||
int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path);
|
||||
int os_delete_file(Buf *path);
|
||||
|
||||
int os_file_exists(Buf *full_path, bool *result);
|
||||
|
||||
int os_rename(Buf *src_path, Buf *dest_path);
|
||||
double os_get_time(void);
|
||||
|
||||
bool os_is_sep(uint8_t c);
|
||||
|
||||
int os_self_exe_path(Buf *out_path);
|
||||
|
||||
int os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf *output_buf);
|
||||
int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
|
||||
int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#define ZIG_OS_DARWIN
|
||||
#elif defined(_WIN32)
|
||||
@@ -116,4 +50,93 @@ int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchTy
|
||||
#define ZIG_OS_SEP_CHAR '/'
|
||||
#endif
|
||||
|
||||
enum TermColor {
|
||||
TermColorRed,
|
||||
TermColorGreen,
|
||||
TermColorCyan,
|
||||
TermColorWhite,
|
||||
TermColorBold,
|
||||
TermColorReset,
|
||||
};
|
||||
|
||||
enum TerminationId {
|
||||
TerminationIdClean,
|
||||
TerminationIdSignaled,
|
||||
TerminationIdStopped,
|
||||
TerminationIdUnknown,
|
||||
};
|
||||
|
||||
struct Termination {
|
||||
TerminationId how;
|
||||
int code;
|
||||
};
|
||||
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
#define OsFile void *
|
||||
#else
|
||||
#define OsFile int
|
||||
#endif
|
||||
|
||||
struct OsTimeStamp {
|
||||
uint64_t sec;
|
||||
uint64_t nsec;
|
||||
};
|
||||
|
||||
int os_init(void);
|
||||
|
||||
void os_spawn_process(const char *exe, ZigList<const char *> &args, Termination *term);
|
||||
int os_exec_process(const char *exe, ZigList<const char *> &args,
|
||||
Termination *term, Buf *out_stderr, Buf *out_stdout);
|
||||
Error os_execv(const char *exe, const char **argv);
|
||||
|
||||
void os_path_dirname(Buf *full_path, Buf *out_dirname);
|
||||
void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename);
|
||||
void os_path_extname(Buf *full_path, Buf *out_basename, Buf *out_extname);
|
||||
void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path);
|
||||
int os_path_real(Buf *rel_path, Buf *out_abs_path);
|
||||
Buf os_path_resolve(Buf **paths_ptr, size_t paths_len);
|
||||
bool os_path_is_absolute(Buf *path);
|
||||
|
||||
Error ATTRIBUTE_MUST_USE os_make_path(Buf *path);
|
||||
Error ATTRIBUTE_MUST_USE os_make_dir(Buf *path);
|
||||
|
||||
Error ATTRIBUTE_MUST_USE os_file_open_r(Buf *full_path, OsFile *out_file);
|
||||
Error ATTRIBUTE_MUST_USE os_file_open_lock_rw(Buf *full_path, OsFile *out_file);
|
||||
Error ATTRIBUTE_MUST_USE os_file_mtime(OsFile file, OsTimeStamp *mtime);
|
||||
Error ATTRIBUTE_MUST_USE os_file_read(OsFile file, void *ptr, size_t *len);
|
||||
Error ATTRIBUTE_MUST_USE os_file_read_all(OsFile file, Buf *contents);
|
||||
Error ATTRIBUTE_MUST_USE os_file_overwrite(OsFile file, Buf *contents);
|
||||
void os_file_close(OsFile file);
|
||||
|
||||
void os_write_file(Buf *full_path, Buf *contents);
|
||||
int os_copy_file(Buf *src_path, Buf *dest_path);
|
||||
|
||||
Error ATTRIBUTE_MUST_USE os_fetch_file(FILE *file, Buf *out_contents, bool skip_shebang);
|
||||
Error ATTRIBUTE_MUST_USE os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang);
|
||||
|
||||
int os_get_cwd(Buf *out_cwd);
|
||||
|
||||
bool os_stderr_tty(void);
|
||||
void os_stderr_set_color(TermColor color);
|
||||
|
||||
int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path);
|
||||
int os_delete_file(Buf *path);
|
||||
|
||||
Error ATTRIBUTE_MUST_USE os_file_exists(Buf *full_path, bool *result);
|
||||
|
||||
int os_rename(Buf *src_path, Buf *dest_path);
|
||||
double os_get_time(void);
|
||||
|
||||
bool os_is_sep(uint8_t c);
|
||||
|
||||
Error ATTRIBUTE_MUST_USE os_self_exe_path(Buf *out_path);
|
||||
|
||||
Error ATTRIBUTE_MUST_USE os_get_app_data_dir(Buf *out_path, const char *appname);
|
||||
|
||||
int os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf *output_buf);
|
||||
int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
|
||||
int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
|
||||
|
||||
Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths);
|
||||
|
||||
#endif
|
||||
|
||||
+1
-8
@@ -700,7 +700,7 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b
|
||||
|
||||
/*
|
||||
PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | PromiseType
|
||||
KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" | "suspend"
|
||||
KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "unreachable" | "suspend"
|
||||
ErrorSetDecl = "error" "{" list(Symbol, ",") "}"
|
||||
*/
|
||||
static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
|
||||
@@ -756,10 +756,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo
|
||||
AstNode *node = ast_create_node(pc, NodeTypeUndefinedLiteral, token);
|
||||
*token_index += 1;
|
||||
return node;
|
||||
} else if (token->id == TokenIdKeywordThis) {
|
||||
AstNode *node = ast_create_node(pc, NodeTypeThisLiteral, token);
|
||||
*token_index += 1;
|
||||
return node;
|
||||
} else if (token->id == TokenIdKeywordUnreachable) {
|
||||
AstNode *node = ast_create_node(pc, NodeTypeUnreachable, token);
|
||||
*token_index += 1;
|
||||
@@ -3021,9 +3017,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
|
||||
case NodeTypeUndefinedLiteral:
|
||||
// none
|
||||
break;
|
||||
case NodeTypeThisLiteral:
|
||||
// none
|
||||
break;
|
||||
case NodeTypeIfBoolExpr:
|
||||
visit_field(&node->data.if_bool_expr.condition, visit, context);
|
||||
visit_field(&node->data.if_bool_expr.then_block, visit, context);
|
||||
|
||||
@@ -812,6 +812,22 @@ const char *target_exe_file_ext(ZigTarget *target) {
|
||||
}
|
||||
}
|
||||
|
||||
const char *target_lib_file_ext(ZigTarget *target, bool is_static, size_t version_major, size_t version_minor, size_t version_patch) {
|
||||
if (target->os == OsWindows) {
|
||||
if (is_static) {
|
||||
return ".lib";
|
||||
} else {
|
||||
return ".dll";
|
||||
}
|
||||
} else {
|
||||
if (is_static) {
|
||||
return ".a";
|
||||
} else {
|
||||
return buf_ptr(buf_sprintf(".so.%zu", version_major));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum FloatAbi {
|
||||
FloatAbiHard,
|
||||
FloatAbiSoft,
|
||||
|
||||
@@ -114,6 +114,7 @@ const char *target_o_file_ext(ZigTarget *target);
|
||||
const char *target_asm_file_ext(ZigTarget *target);
|
||||
const char *target_llvm_ir_file_ext(ZigTarget *target);
|
||||
const char *target_exe_file_ext(ZigTarget *target);
|
||||
const char *target_lib_file_ext(ZigTarget *target, bool is_static, size_t version_major, size_t version_minor, size_t version_patch);
|
||||
|
||||
Buf *target_dynamic_linker(ZigTarget *target);
|
||||
|
||||
|
||||
@@ -146,7 +146,6 @@ static const struct ZigKeyword zig_keywords[] = {
|
||||
{"suspend", TokenIdKeywordSuspend},
|
||||
{"switch", TokenIdKeywordSwitch},
|
||||
{"test", TokenIdKeywordTest},
|
||||
{"this", TokenIdKeywordThis},
|
||||
{"true", TokenIdKeywordTrue},
|
||||
{"try", TokenIdKeywordTry},
|
||||
{"undefined", TokenIdKeywordUndefined},
|
||||
@@ -1588,7 +1587,6 @@ const char * token_name(TokenId id) {
|
||||
case TokenIdKeywordStruct: return "struct";
|
||||
case TokenIdKeywordSwitch: return "switch";
|
||||
case TokenIdKeywordTest: return "test";
|
||||
case TokenIdKeywordThis: return "this";
|
||||
case TokenIdKeywordTrue: return "true";
|
||||
case TokenIdKeywordTry: return "try";
|
||||
case TokenIdKeywordUndefined: return "undefined";
|
||||
|
||||
@@ -87,7 +87,6 @@ enum TokenId {
|
||||
TokenIdKeywordSuspend,
|
||||
TokenIdKeywordSwitch,
|
||||
TokenIdKeywordTest,
|
||||
TokenIdKeywordThis,
|
||||
TokenIdKeywordTrue,
|
||||
TokenIdKeywordTry,
|
||||
TokenIdKeywordUndefined,
|
||||
|
||||
@@ -43,3 +43,52 @@ uint32_t ptr_hash(const void *ptr) {
|
||||
bool ptr_eq(const void *a, const void *b) {
|
||||
return a == b;
|
||||
}
|
||||
|
||||
// Ported from std/mem.zig.
|
||||
bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte) {
|
||||
for (size_t i = 0; i < self->split_bytes.len; i += 1) {
|
||||
if (byte == self->split_bytes.ptr[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ported from std/mem.zig.
|
||||
Optional<Slice<uint8_t>> SplitIterator_next(SplitIterator *self) {
|
||||
// move to beginning of token
|
||||
while (self->index < self->buffer.len &&
|
||||
SplitIterator_isSplitByte(self, self->buffer.ptr[self->index]))
|
||||
{
|
||||
self->index += 1;
|
||||
}
|
||||
size_t start = self->index;
|
||||
if (start == self->buffer.len) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// move to end of token
|
||||
while (self->index < self->buffer.len &&
|
||||
!SplitIterator_isSplitByte(self, self->buffer.ptr[self->index]))
|
||||
{
|
||||
self->index += 1;
|
||||
}
|
||||
size_t end = self->index;
|
||||
|
||||
return Optional<Slice<uint8_t>>::some(self->buffer.slice(start, end));
|
||||
}
|
||||
|
||||
// Ported from std/mem.zig
|
||||
Slice<uint8_t> SplitIterator_rest(SplitIterator *self) {
|
||||
// move to beginning of token
|
||||
size_t index = self->index;
|
||||
while (index < self->buffer.len && SplitIterator_isSplitByte(self, self->buffer.ptr[index])) {
|
||||
index += 1;
|
||||
}
|
||||
return self->buffer.sliceFrom(index);
|
||||
}
|
||||
|
||||
// Ported from std/mem.zig
|
||||
SplitIterator memSplit(Slice<uint8_t> buffer, Slice<uint8_t> split_bytes) {
|
||||
return SplitIterator{0, buffer, split_bytes};
|
||||
}
|
||||
|
||||
@@ -254,4 +254,17 @@ static inline void memCopy(Slice<T> dest, Slice<T> src) {
|
||||
memcpy(dest.ptr, src.ptr, src.len * sizeof(T));
|
||||
}
|
||||
|
||||
// Ported from std/mem.zig.
|
||||
// Coordinate struct fields with memSplit function
|
||||
struct SplitIterator {
|
||||
size_t index;
|
||||
Slice<uint8_t> buffer;
|
||||
Slice<uint8_t> split_bytes;
|
||||
};
|
||||
|
||||
bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte);
|
||||
Optional< Slice<uint8_t> > SplitIterator_next(SplitIterator *self);
|
||||
Slice<uint8_t> SplitIterator_rest(SplitIterator *self);
|
||||
SplitIterator memSplit(Slice<uint8_t> buffer, Slice<uint8_t> split_bytes);
|
||||
|
||||
#endif
|
||||
|
||||
+8
-1
@@ -30,6 +30,7 @@
|
||||
#include <llvm/PassRegistry.h>
|
||||
#include <llvm/Support/FileSystem.h>
|
||||
#include <llvm/Support/TargetParser.h>
|
||||
#include <llvm/Support/Timer.h>
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
#include <llvm/Target/TargetMachine.h>
|
||||
#include <llvm/Transforms/Coroutines.h>
|
||||
@@ -82,8 +83,11 @@ static const bool assertions_on = false;
|
||||
#endif
|
||||
|
||||
bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
|
||||
const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug, bool is_small)
|
||||
const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug,
|
||||
bool is_small, bool time_report)
|
||||
{
|
||||
TimePassesIsEnabled = time_report;
|
||||
|
||||
std::error_code EC;
|
||||
raw_fd_ostream dest(filename, EC, sys::fs::F_None);
|
||||
if (EC) {
|
||||
@@ -183,6 +187,9 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
|
||||
}
|
||||
}
|
||||
|
||||
if (time_report) {
|
||||
TimerGroup::printAll(errs());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -55,7 +55,8 @@ enum ZigLLVM_EmitOutputType {
|
||||
};
|
||||
|
||||
ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
|
||||
const char *filename, enum ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug, bool is_small);
|
||||
const char *filename, enum ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug,
|
||||
bool is_small, bool time_report);
|
||||
|
||||
ZIG_EXTERN_C LLVMTypeRef ZigLLVMTokenTypeInContext(LLVMContextRef context_ref);
|
||||
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ pub fn ArrayList(comptime T: type) type {
|
||||
|
||||
pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
|
||||
/// Use toSlice instead of slicing this directly, because if you don't
|
||||
/// specify the end position of the slice, this will potentially give
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ pub fn Int(comptime T: type) type {
|
||||
return struct {
|
||||
unprotected_value: T,
|
||||
|
||||
pub const Self = this;
|
||||
pub const Self = @This();
|
||||
|
||||
pub fn init(init_val: T) Self {
|
||||
return Self{ .unprotected_value = init_val };
|
||||
|
||||
@@ -12,7 +12,7 @@ pub fn Queue(comptime T: type) type {
|
||||
tail: ?*Node,
|
||||
mutex: std.Mutex,
|
||||
|
||||
pub const Self = this;
|
||||
pub const Self = @This();
|
||||
pub const Node = std.LinkedList(T).Node;
|
||||
|
||||
pub fn init() Self {
|
||||
@@ -114,7 +114,7 @@ pub fn Queue(comptime T: type) type {
|
||||
|
||||
fn dumpRecursive(optional_node: ?*Node, indent: usize) void {
|
||||
var stderr_file = std.io.getStdErr() catch return;
|
||||
const stderr = &std.io.FileOutStream.init(&stderr_file).stream;
|
||||
const stderr = &std.io.FileOutStream.init(stderr_file).stream;
|
||||
stderr.writeByteNTimes(' ', indent) catch return;
|
||||
if (optional_node) |node| {
|
||||
std.debug.warn("0x{x}={}\n", @ptrToInt(node), node.data);
|
||||
|
||||
@@ -9,7 +9,7 @@ pub fn Stack(comptime T: type) type {
|
||||
root: ?*Node,
|
||||
lock: u8,
|
||||
|
||||
pub const Self = this;
|
||||
pub const Self = @This();
|
||||
|
||||
pub const Node = struct {
|
||||
next: ?*Node,
|
||||
|
||||
+27
-1
@@ -232,6 +232,8 @@ pub const Builder = struct {
|
||||
}
|
||||
|
||||
pub fn make(self: *Builder, step_names: []const []const u8) !void {
|
||||
try self.makePath(self.cache_root);
|
||||
|
||||
var wanted_steps = ArrayList(*Step).init(self.allocator);
|
||||
defer wanted_steps.deinit();
|
||||
|
||||
@@ -1641,6 +1643,7 @@ pub const TestStep = struct {
|
||||
lib_paths: ArrayList([]const u8),
|
||||
object_files: ArrayList([]const u8),
|
||||
no_rosegment: bool,
|
||||
output_path: ?[]const u8,
|
||||
|
||||
pub fn init(builder: *Builder, root_src: []const u8) TestStep {
|
||||
const step_name = builder.fmt("test {}", root_src);
|
||||
@@ -1659,6 +1662,7 @@ pub const TestStep = struct {
|
||||
.lib_paths = ArrayList([]const u8).init(builder.allocator),
|
||||
.object_files = ArrayList([]const u8).init(builder.allocator),
|
||||
.no_rosegment = false,
|
||||
.output_path = null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1682,6 +1686,24 @@ pub const TestStep = struct {
|
||||
self.build_mode = mode;
|
||||
}
|
||||
|
||||
pub fn setOutputPath(self: *TestStep, file_path: []const u8) void {
|
||||
self.output_path = file_path;
|
||||
|
||||
// catch a common mistake
|
||||
if (mem.eql(u8, self.builder.pathFromRoot(file_path), self.builder.pathFromRoot("."))) {
|
||||
debug.panic("setOutputPath wants a file path, not a directory\n");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getOutputPath(self: *TestStep) []const u8 {
|
||||
if (self.output_path) |output_path| {
|
||||
return output_path;
|
||||
} else {
|
||||
const basename = self.builder.fmt("test{}", self.target.exeFileExt());
|
||||
return os.path.join(self.builder.allocator, self.builder.cache_root, basename) catch unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn linkSystemLibrary(self: *TestStep, name: []const u8) void {
|
||||
self.link_libs.put(name) catch unreachable;
|
||||
}
|
||||
@@ -1746,6 +1768,10 @@ pub const TestStep = struct {
|
||||
builtin.Mode.ReleaseSmall => try zig_args.append("--release-small"),
|
||||
}
|
||||
|
||||
const output_path = builder.pathFromRoot(self.getOutputPath());
|
||||
try zig_args.append("--output");
|
||||
try zig_args.append(output_path);
|
||||
|
||||
switch (self.target) {
|
||||
Target.Native => {},
|
||||
Target.Cross => |cross_target| {
|
||||
@@ -1864,7 +1890,7 @@ const InstallArtifactStep = struct {
|
||||
artifact: *LibExeObjStep,
|
||||
dest_file: []const u8,
|
||||
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
|
||||
pub fn create(builder: *Builder, artifact: *LibExeObjStep) *Self {
|
||||
const dest_dir = switch (artifact.kind) {
|
||||
|
||||
+23
-29
@@ -8,9 +8,9 @@ const ArrayList = std.ArrayList;
|
||||
|
||||
// CoffHeader.machine values
|
||||
// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680313(v=vs.85).aspx
|
||||
const IMAGE_FILE_MACHINE_I386 = 0x014c;
|
||||
const IMAGE_FILE_MACHINE_IA64 = 0x0200;
|
||||
const IMAGE_FILE_MACHINE_AMD64 = 0x8664;
|
||||
const IMAGE_FILE_MACHINE_I386 = 0x014c;
|
||||
const IMAGE_FILE_MACHINE_IA64 = 0x0200;
|
||||
const IMAGE_FILE_MACHINE_AMD64 = 0x8664;
|
||||
|
||||
// OptionalHeader.magic values
|
||||
// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680339(v=vs.85).aspx
|
||||
@@ -20,7 +20,7 @@ const IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b;
|
||||
const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
|
||||
const DEBUG_DIRECTORY = 6;
|
||||
|
||||
pub const CoffError = error {
|
||||
pub const CoffError = error{
|
||||
InvalidPEMagic,
|
||||
InvalidPEHeader,
|
||||
InvalidMachine,
|
||||
@@ -56,24 +56,21 @@ pub const Coff = struct {
|
||||
|
||||
var pe_header_magic: [4]u8 = undefined;
|
||||
try in.readNoEof(pe_header_magic[0..]);
|
||||
if (!mem.eql(u8, pe_header_magic, []u8{'P', 'E', 0, 0}))
|
||||
if (!mem.eql(u8, pe_header_magic, []u8{ 'P', 'E', 0, 0 }))
|
||||
return error.InvalidPEHeader;
|
||||
|
||||
self.coff_header = CoffHeader {
|
||||
self.coff_header = CoffHeader{
|
||||
.machine = try in.readIntLe(u16),
|
||||
.number_of_sections = try in.readIntLe(u16),
|
||||
.timedate_stamp = try in.readIntLe(u32),
|
||||
.pointer_to_symbol_table = try in.readIntLe(u32),
|
||||
.number_of_symbols = try in.readIntLe(u32),
|
||||
.size_of_optional_header = try in.readIntLe(u16),
|
||||
.characteristics = try in.readIntLe(u16),
|
||||
.number_of_sections = try in.readIntLe(u16),
|
||||
.timedate_stamp = try in.readIntLe(u32),
|
||||
.pointer_to_symbol_table = try in.readIntLe(u32),
|
||||
.number_of_symbols = try in.readIntLe(u32),
|
||||
.size_of_optional_header = try in.readIntLe(u16),
|
||||
.characteristics = try in.readIntLe(u16),
|
||||
};
|
||||
|
||||
switch (self.coff_header.machine) {
|
||||
IMAGE_FILE_MACHINE_I386,
|
||||
IMAGE_FILE_MACHINE_AMD64,
|
||||
IMAGE_FILE_MACHINE_IA64
|
||||
=> {},
|
||||
IMAGE_FILE_MACHINE_I386, IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_IA64 => {},
|
||||
else => return error.InvalidMachine,
|
||||
}
|
||||
|
||||
@@ -89,11 +86,9 @@ pub const Coff = struct {
|
||||
var skip_size: u16 = undefined;
|
||||
if (self.pe_header.magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
||||
skip_size = 2 * @sizeOf(u8) + 8 * @sizeOf(u16) + 18 * @sizeOf(u32);
|
||||
}
|
||||
else if (self.pe_header.magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
|
||||
} else if (self.pe_header.magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
|
||||
skip_size = 2 * @sizeOf(u8) + 8 * @sizeOf(u16) + 12 * @sizeOf(u32) + 5 * @sizeOf(u64);
|
||||
}
|
||||
else
|
||||
} else
|
||||
return error.InvalidPEMagic;
|
||||
|
||||
try self.in_file.seekForward(skip_size);
|
||||
@@ -103,7 +98,7 @@ pub const Coff = struct {
|
||||
return error.InvalidPEHeader;
|
||||
|
||||
for (self.pe_header.data_directory) |*data_dir| {
|
||||
data_dir.* = OptionalHeader.DataDirectory {
|
||||
data_dir.* = OptionalHeader.DataDirectory{
|
||||
.virtual_address = try in.readIntLe(u32),
|
||||
.size = try in.readIntLe(u32),
|
||||
};
|
||||
@@ -114,7 +109,7 @@ pub const Coff = struct {
|
||||
try self.loadSections();
|
||||
const header = (self.getSection(".rdata") orelse return error.MissingCoffSection).header;
|
||||
|
||||
// The linker puts a chunk that contains the .pdb path right after the
|
||||
// The linker puts a chunk that contains the .pdb path right after the
|
||||
// debug_directory.
|
||||
const debug_dir = &self.pe_header.data_directory[DEBUG_DIRECTORY];
|
||||
const file_offset = debug_dir.virtual_address - header.virtual_address + header.pointer_to_raw_data;
|
||||
@@ -159,10 +154,10 @@ pub const Coff = struct {
|
||||
var i: u16 = 0;
|
||||
while (i < self.coff_header.number_of_sections) : (i += 1) {
|
||||
try in.readNoEof(name[0..]);
|
||||
try self.sections.append(Section {
|
||||
.header = SectionHeader {
|
||||
try self.sections.append(Section{
|
||||
.header = SectionHeader{
|
||||
.name = name,
|
||||
.misc = SectionHeader.Misc { .physical_address = try in.readIntLe(u32) },
|
||||
.misc = SectionHeader.Misc{ .physical_address = try in.readIntLe(u32) },
|
||||
.virtual_address = try in.readIntLe(u32),
|
||||
.size_of_raw_data = try in.readIntLe(u32),
|
||||
.pointer_to_raw_data = try in.readIntLe(u32),
|
||||
@@ -184,7 +179,6 @@ pub const Coff = struct {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const CoffHeader = struct {
|
||||
@@ -194,13 +188,13 @@ const CoffHeader = struct {
|
||||
pointer_to_symbol_table: u32,
|
||||
number_of_symbols: u32,
|
||||
size_of_optional_header: u16,
|
||||
characteristics: u16
|
||||
characteristics: u16,
|
||||
};
|
||||
|
||||
const OptionalHeader = struct {
|
||||
const DataDirectory = struct {
|
||||
virtual_address: u32,
|
||||
size: u32
|
||||
size: u32,
|
||||
};
|
||||
|
||||
magic: u16,
|
||||
@@ -214,7 +208,7 @@ pub const Section = struct {
|
||||
const SectionHeader = struct {
|
||||
const Misc = union {
|
||||
physical_address: u32,
|
||||
virtual_size: u32
|
||||
virtual_size: u32,
|
||||
};
|
||||
|
||||
name: [8]u8,
|
||||
|
||||
@@ -33,7 +33,7 @@ pub const Blake2s256 = Blake2s(256);
|
||||
|
||||
fn Blake2s(comptime out_len: usize) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
const block_length = 64;
|
||||
const digest_length = out_len / 8;
|
||||
|
||||
@@ -266,7 +266,7 @@ pub const Blake2b512 = Blake2b(512);
|
||||
|
||||
fn Blake2b(comptime out_len: usize) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
const block_length = 128;
|
||||
const digest_length = out_len / 8;
|
||||
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ pub const HmacSha256 = Hmac(crypto.Sha256);
|
||||
|
||||
pub fn Hmac(comptime Hash: type) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
pub const mac_length = Hash.digest_length;
|
||||
pub const minimum_key_length = 0;
|
||||
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, k: usize, s: u32, t: u32) RoundPar
|
||||
}
|
||||
|
||||
pub const Md5 = struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
const block_length = 64;
|
||||
const digest_length = 16;
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ const readInt = std.mem.readInt;
|
||||
const writeInt = std.mem.writeInt;
|
||||
|
||||
pub const Poly1305 = struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
|
||||
pub const mac_length = 16;
|
||||
pub const minimum_key_length = 32;
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) RoundParam {
|
||||
}
|
||||
|
||||
pub const Sha1 = struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
const block_length = 64;
|
||||
const digest_length = 20;
|
||||
|
||||
|
||||
+2
-2
@@ -77,7 +77,7 @@ pub const Sha256 = Sha2_32(Sha256Params);
|
||||
|
||||
fn Sha2_32(comptime params: Sha2Params32) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
const block_length = 64;
|
||||
const digest_length = params.out_len / 8;
|
||||
|
||||
@@ -418,7 +418,7 @@ pub const Sha512 = Sha2_64(Sha512Params);
|
||||
|
||||
fn Sha2_64(comptime params: Sha2Params64) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
const block_length = 128;
|
||||
const digest_length = params.out_len / 8;
|
||||
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ pub const Sha3_512 = Keccak(512, 0x06);
|
||||
|
||||
fn Keccak(comptime bits: usize, comptime delim: u8) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
const block_length = 200;
|
||||
const digest_length = bits / 8;
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ pub const X25519 = struct {
|
||||
return !zerocmp(u8, out);
|
||||
}
|
||||
|
||||
pub fn createPublicKey(public_key: [] u8, private_key: []const u8) bool {
|
||||
pub fn createPublicKey(public_key: []u8, private_key: []const u8) bool {
|
||||
var base_point = []u8{9} ++ []u8{0} ** 31;
|
||||
return create(public_key, private_key, base_point);
|
||||
}
|
||||
|
||||
+15
-14
@@ -242,9 +242,12 @@ pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color
|
||||
}
|
||||
}
|
||||
|
||||
pub fn writeCurrentStackTraceWindows(out_stream: var, debug_info: *DebugInfo,
|
||||
tty_color: bool, start_addr: ?usize) !void
|
||||
{
|
||||
pub fn writeCurrentStackTraceWindows(
|
||||
out_stream: var,
|
||||
debug_info: *DebugInfo,
|
||||
tty_color: bool,
|
||||
start_addr: ?usize,
|
||||
) !void {
|
||||
var addr_buf: [1024]usize = undefined;
|
||||
const casted_len = @intCast(u32, addr_buf.len); // TODO shouldn't need this cast
|
||||
const n = windows.RtlCaptureStackBackTrace(0, casted_len, @ptrCast(**c_void, &addr_buf), null);
|
||||
@@ -391,7 +394,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres
|
||||
break :subsections null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
if (tty_color) {
|
||||
setTtyColor(TtyColor.White);
|
||||
if (opt_line_info) |li| {
|
||||
@@ -438,7 +441,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres
|
||||
}
|
||||
}
|
||||
|
||||
const TtyColor = enum{
|
||||
const TtyColor = enum {
|
||||
Red,
|
||||
Green,
|
||||
Cyan,
|
||||
@@ -465,18 +468,16 @@ fn setTtyColor(tty_color: TtyColor) void {
|
||||
// TODO handle errors
|
||||
switch (tty_color) {
|
||||
TtyColor.Red => {
|
||||
_ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED|windows.FOREGROUND_INTENSITY);
|
||||
_ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_INTENSITY);
|
||||
},
|
||||
TtyColor.Green => {
|
||||
_ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN|windows.FOREGROUND_INTENSITY);
|
||||
_ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY);
|
||||
},
|
||||
TtyColor.Cyan => {
|
||||
_ = windows.SetConsoleTextAttribute(stderr_file.handle,
|
||||
windows.FOREGROUND_GREEN|windows.FOREGROUND_BLUE|windows.FOREGROUND_INTENSITY);
|
||||
_ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY);
|
||||
},
|
||||
TtyColor.White, TtyColor.Bold => {
|
||||
_ = windows.SetConsoleTextAttribute(stderr_file.handle,
|
||||
windows.FOREGROUND_RED|windows.FOREGROUND_GREEN|windows.FOREGROUND_BLUE|windows.FOREGROUND_INTENSITY);
|
||||
_ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY);
|
||||
},
|
||||
TtyColor.Dim => {
|
||||
_ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_INTENSITY);
|
||||
@@ -915,7 +916,7 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {
|
||||
} else {
|
||||
return error.MissingDebugInfo;
|
||||
};
|
||||
const syms = @ptrCast([*]macho.nlist_64, hdr_base + symtab.symoff)[0..symtab.nsyms];
|
||||
const syms = @ptrCast([*]macho.nlist_64, @alignCast(@alignOf(macho.nlist_64), hdr_base + symtab.symoff))[0..symtab.nsyms];
|
||||
const strings = @ptrCast([*]u8, hdr_base + symtab.stroff)[0..symtab.strsize];
|
||||
|
||||
const symbols_buf = try allocator.alloc(MachoSymbol, syms.len);
|
||||
@@ -1496,14 +1497,14 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
|
||||
const segcmd = while (ncmd != 0) : (ncmd -= 1) {
|
||||
const lc = @ptrCast(*const std.macho.load_command, ptr);
|
||||
switch (lc.cmd) {
|
||||
std.macho.LC_SEGMENT_64 => break @ptrCast(*const std.macho.segment_command_64, ptr),
|
||||
std.macho.LC_SEGMENT_64 => break @ptrCast(*const std.macho.segment_command_64, @alignCast(@alignOf(std.macho.segment_command_64), ptr)),
|
||||
else => {},
|
||||
}
|
||||
ptr += lc.cmdsize; // TODO https://github.com/ziglang/zig/issues/1403
|
||||
} else {
|
||||
return error.MissingDebugInfo;
|
||||
};
|
||||
const sections = @alignCast(@alignOf(macho.section_64), @ptrCast([*]const macho.section_64, ptr + @sizeOf(std.macho.segment_command_64)))[0..segcmd.nsects];
|
||||
const sections = @ptrCast([*]const macho.section_64, @alignCast(@alignOf(macho.section_64), ptr + @sizeOf(std.macho.segment_command_64)))[0..segcmd.nsects];
|
||||
for (sections) |*sect| {
|
||||
if (sect.flags & macho.SECTION_TYPE == macho.S_REGULAR and
|
||||
(sect.flags & macho.SECTION_ATTRIBUTES) & macho.S_ATTR_DEBUG == macho.S_ATTR_DEBUG)
|
||||
|
||||
@@ -25,7 +25,7 @@ pub fn Channel(comptime T: type) type {
|
||||
buffer_index: usize,
|
||||
buffer_len: usize,
|
||||
|
||||
const SelfChannel = this;
|
||||
const SelfChannel = @This();
|
||||
const GetNode = struct {
|
||||
tick_node: *Loop.NextTickNode,
|
||||
data: Data,
|
||||
|
||||
+42
-46
@@ -109,30 +109,28 @@ pub async fn pwriteWindows(loop: *Loop, fd: os.FileHandle, data: []const u8, off
|
||||
.base = Loop.ResumeNode{
|
||||
.id = Loop.ResumeNode.Id.Basic,
|
||||
.handle = @handle(),
|
||||
.overlapped = windows.OVERLAPPED{
|
||||
.Internal = 0,
|
||||
.InternalHigh = 0,
|
||||
.Offset = @truncate(u32, offset),
|
||||
.OffsetHigh = @truncate(u32, offset >> 32),
|
||||
.hEvent = null,
|
||||
},
|
||||
},
|
||||
};
|
||||
const completion_key = @ptrToInt(&resume_node.base);
|
||||
// TODO support concurrent async ops on the file handle
|
||||
// we can do this by ignoring completion key and using @fieldParentPtr with the *Overlapped
|
||||
_ = try os.windowsCreateIoCompletionPort(fd, loop.os_data.io_port, completion_key, undefined);
|
||||
var overlapped = windows.OVERLAPPED{
|
||||
.Internal = 0,
|
||||
.InternalHigh = 0,
|
||||
.Offset = @truncate(u32, offset),
|
||||
.OffsetHigh = @truncate(u32, offset >> 32),
|
||||
.hEvent = null,
|
||||
};
|
||||
// TODO only call create io completion port once per fd
|
||||
_ = windows.CreateIoCompletionPort(fd, loop.os_data.io_port, undefined, undefined);
|
||||
loop.beginOneEvent();
|
||||
errdefer loop.finishOneEvent();
|
||||
|
||||
errdefer {
|
||||
_ = windows.CancelIoEx(fd, &overlapped);
|
||||
_ = windows.CancelIoEx(fd, &resume_node.base.overlapped);
|
||||
}
|
||||
suspend {
|
||||
_ = windows.WriteFile(fd, data.ptr, @intCast(windows.DWORD, data.len), null, &overlapped);
|
||||
_ = windows.WriteFile(fd, data.ptr, @intCast(windows.DWORD, data.len), null, &resume_node.base.overlapped);
|
||||
}
|
||||
var bytes_transferred: windows.DWORD = undefined;
|
||||
if (windows.GetOverlappedResult(fd, &overlapped, &bytes_transferred, windows.FALSE) == 0) {
|
||||
if (windows.GetOverlappedResult(fd, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {
|
||||
const err = windows.GetLastError();
|
||||
return switch (err) {
|
||||
windows.ERROR.IO_PENDING => unreachable,
|
||||
@@ -243,37 +241,36 @@ pub async fn preadWindows(loop: *Loop, fd: os.FileHandle, data: []u8, offset: u6
|
||||
.base = Loop.ResumeNode{
|
||||
.id = Loop.ResumeNode.Id.Basic,
|
||||
.handle = @handle(),
|
||||
.overlapped = windows.OVERLAPPED{
|
||||
.Internal = 0,
|
||||
.InternalHigh = 0,
|
||||
.Offset = @truncate(u32, offset),
|
||||
.OffsetHigh = @truncate(u32, offset >> 32),
|
||||
.hEvent = null,
|
||||
},
|
||||
},
|
||||
};
|
||||
const completion_key = @ptrToInt(&resume_node.base);
|
||||
// TODO support concurrent async ops on the file handle
|
||||
// we can do this by ignoring completion key and using @fieldParentPtr with the *Overlapped
|
||||
_ = try os.windowsCreateIoCompletionPort(fd, loop.os_data.io_port, completion_key, undefined);
|
||||
var overlapped = windows.OVERLAPPED{
|
||||
.Internal = 0,
|
||||
.InternalHigh = 0,
|
||||
.Offset = @truncate(u32, offset),
|
||||
.OffsetHigh = @truncate(u32, offset >> 32),
|
||||
.hEvent = null,
|
||||
};
|
||||
// TODO only call create io completion port once per fd
|
||||
_ = windows.CreateIoCompletionPort(fd, loop.os_data.io_port, undefined, undefined);
|
||||
loop.beginOneEvent();
|
||||
errdefer loop.finishOneEvent();
|
||||
|
||||
errdefer {
|
||||
_ = windows.CancelIoEx(fd, &overlapped);
|
||||
_ = windows.CancelIoEx(fd, &resume_node.base.overlapped);
|
||||
}
|
||||
suspend {
|
||||
_ = windows.ReadFile(fd, data.ptr, @intCast(windows.DWORD, data.len), null, &overlapped);
|
||||
_ = windows.ReadFile(fd, data.ptr, @intCast(windows.DWORD, data.len), null, &resume_node.base.overlapped);
|
||||
}
|
||||
var bytes_transferred: windows.DWORD = undefined;
|
||||
if (windows.GetOverlappedResult(fd, &overlapped, &bytes_transferred, windows.FALSE) == 0) {
|
||||
if (windows.GetOverlappedResult(fd, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {
|
||||
const err = windows.GetLastError();
|
||||
return switch (err) {
|
||||
switch (err) {
|
||||
windows.ERROR.IO_PENDING => unreachable,
|
||||
windows.ERROR.OPERATION_ABORTED => error.OperationAborted,
|
||||
windows.ERROR.BROKEN_PIPE => error.BrokenPipe,
|
||||
else => os.unexpectedErrorWindows(err),
|
||||
};
|
||||
windows.ERROR.OPERATION_ABORTED => return error.OperationAborted,
|
||||
windows.ERROR.BROKEN_PIPE => return error.BrokenPipe,
|
||||
windows.ERROR.HANDLE_EOF => return usize(bytes_transferred),
|
||||
else => return os.unexpectedErrorWindows(err),
|
||||
}
|
||||
}
|
||||
return usize(bytes_transferred);
|
||||
}
|
||||
@@ -727,7 +724,7 @@ pub fn Watch(comptime V: type) type {
|
||||
|
||||
const FileToHandle = std.AutoHashMap([]const u8, promise);
|
||||
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
|
||||
pub const Event = struct {
|
||||
id: Id,
|
||||
@@ -1074,23 +1071,22 @@ pub fn Watch(comptime V: type) type {
|
||||
.base = Loop.ResumeNode{
|
||||
.id = Loop.ResumeNode.Id.Basic,
|
||||
.handle = @handle(),
|
||||
.overlapped = windows.OVERLAPPED{
|
||||
.Internal = 0,
|
||||
.InternalHigh = 0,
|
||||
.Offset = 0,
|
||||
.OffsetHigh = 0,
|
||||
.hEvent = null,
|
||||
},
|
||||
},
|
||||
};
|
||||
const completion_key = @ptrToInt(&resume_node.base);
|
||||
var overlapped = windows.OVERLAPPED{
|
||||
.Internal = 0,
|
||||
.InternalHigh = 0,
|
||||
.Offset = 0,
|
||||
.OffsetHigh = 0,
|
||||
.hEvent = null,
|
||||
};
|
||||
var event_buf: [4096]u8 align(@alignOf(windows.FILE_NOTIFY_INFORMATION)) = undefined;
|
||||
|
||||
// TODO handle this error not in the channel but in the setup
|
||||
_ = os.windowsCreateIoCompletionPort(
|
||||
dir_handle,
|
||||
self.channel.loop.os_data.io_port,
|
||||
completion_key,
|
||||
undefined,
|
||||
undefined,
|
||||
) catch |err| {
|
||||
await (async self.channel.put(err) catch unreachable);
|
||||
@@ -1103,7 +1099,7 @@ pub fn Watch(comptime V: type) type {
|
||||
self.channel.loop.beginOneEvent();
|
||||
errdefer self.channel.loop.finishOneEvent();
|
||||
errdefer {
|
||||
_ = windows.CancelIoEx(dir_handle, &overlapped);
|
||||
_ = windows.CancelIoEx(dir_handle, &resume_node.base.overlapped);
|
||||
}
|
||||
suspend {
|
||||
_ = windows.ReadDirectoryChangesW(
|
||||
@@ -1116,13 +1112,13 @@ pub fn Watch(comptime V: type) type {
|
||||
windows.FILE_NOTIFY_CHANGE_LAST_WRITE | windows.FILE_NOTIFY_CHANGE_LAST_ACCESS |
|
||||
windows.FILE_NOTIFY_CHANGE_CREATION | windows.FILE_NOTIFY_CHANGE_SECURITY,
|
||||
null, // number of bytes transferred (unused for async)
|
||||
&overlapped,
|
||||
&resume_node.base.overlapped,
|
||||
null, // completion routine - unused because we use IOCP
|
||||
);
|
||||
}
|
||||
}
|
||||
var bytes_transferred: windows.DWORD = undefined;
|
||||
if (windows.GetOverlappedResult(dir_handle, &overlapped, &bytes_transferred, windows.FALSE) == 0) {
|
||||
if (windows.GetOverlappedResult(dir_handle, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {
|
||||
const errno = windows.GetLastError();
|
||||
const err = switch (errno) {
|
||||
else => os.unexpectedErrorWindows(errno),
|
||||
|
||||
@@ -21,7 +21,7 @@ pub fn Future(comptime T: type) type {
|
||||
/// 2 - finished
|
||||
available: u8,
|
||||
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
const Queue = std.atomic.Queue(promise);
|
||||
|
||||
pub fn init(loop: *Loop) Self {
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ pub fn Group(comptime ReturnType: type) type {
|
||||
alloc_stack: Stack,
|
||||
lock: Lock,
|
||||
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
|
||||
const Error = switch (@typeInfo(ReturnType)) {
|
||||
builtin.TypeId.ErrorUnion => |payload| payload.error_set,
|
||||
|
||||
@@ -10,7 +10,7 @@ pub fn Locked(comptime T: type) type {
|
||||
lock: Lock,
|
||||
private_data: T,
|
||||
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
|
||||
pub const HeldLock = struct {
|
||||
value: *T,
|
||||
|
||||
+30
-14
@@ -27,6 +27,19 @@ pub const Loop = struct {
|
||||
pub const ResumeNode = struct {
|
||||
id: Id,
|
||||
handle: promise,
|
||||
overlapped: Overlapped,
|
||||
|
||||
pub const overlapped_init = switch (builtin.os) {
|
||||
builtin.Os.windows => windows.OVERLAPPED{
|
||||
.Internal = 0,
|
||||
.InternalHigh = 0,
|
||||
.Offset = 0,
|
||||
.OffsetHigh = 0,
|
||||
.hEvent = null,
|
||||
},
|
||||
else => {},
|
||||
};
|
||||
pub const Overlapped = @typeOf(overlapped_init);
|
||||
|
||||
pub const Id = enum {
|
||||
Basic,
|
||||
@@ -101,6 +114,7 @@ pub const Loop = struct {
|
||||
.final_resume_node = ResumeNode{
|
||||
.id = ResumeNode.Id.Stop,
|
||||
.handle = undefined,
|
||||
.overlapped = ResumeNode.overlapped_init,
|
||||
},
|
||||
};
|
||||
const extra_thread_count = thread_count - 1;
|
||||
@@ -153,6 +167,7 @@ pub const Loop = struct {
|
||||
.base = ResumeNode{
|
||||
.id = ResumeNode.Id.EventFd,
|
||||
.handle = undefined,
|
||||
.overlapped = ResumeNode.overlapped_init,
|
||||
},
|
||||
.eventfd = try os.linuxEventFd(1, posix.EFD_CLOEXEC | posix.EFD_NONBLOCK),
|
||||
.epoll_op = posix.EPOLL_CTL_ADD,
|
||||
@@ -225,6 +240,7 @@ pub const Loop = struct {
|
||||
.base = ResumeNode{
|
||||
.id = ResumeNode.Id.EventFd,
|
||||
.handle = undefined,
|
||||
.overlapped = ResumeNode.overlapped_init,
|
||||
},
|
||||
// this one is for sending events
|
||||
.kevent = posix.Kevent{
|
||||
@@ -311,6 +327,7 @@ pub const Loop = struct {
|
||||
.base = ResumeNode{
|
||||
.id = ResumeNode.Id.EventFd,
|
||||
.handle = undefined,
|
||||
.overlapped = ResumeNode.overlapped_init,
|
||||
},
|
||||
// this one is for sending events
|
||||
.completion_key = @ptrToInt(&eventfd_node.data.base),
|
||||
@@ -325,8 +342,8 @@ pub const Loop = struct {
|
||||
var i: usize = 0;
|
||||
while (i < extra_thread_index) : (i += 1) {
|
||||
while (true) {
|
||||
const overlapped = @intToPtr(?*windows.OVERLAPPED, 0x1);
|
||||
os.windowsPostQueuedCompletionStatus(self.os_data.io_port, undefined, @ptrToInt(&self.final_resume_node), overlapped) catch continue;
|
||||
const overlapped = &self.final_resume_node.overlapped;
|
||||
os.windowsPostQueuedCompletionStatus(self.os_data.io_port, undefined, undefined, overlapped) catch continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -398,6 +415,7 @@ pub const Loop = struct {
|
||||
.base = ResumeNode{
|
||||
.id = ResumeNode.Id.Basic,
|
||||
.handle = @handle(),
|
||||
.overlapped = ResumeNode.overlapped_init,
|
||||
},
|
||||
};
|
||||
try self.linuxAddFd(fd, &resume_node.base, flags);
|
||||
@@ -413,6 +431,7 @@ pub const Loop = struct {
|
||||
.base = ResumeNode{
|
||||
.id = ResumeNode.Id.Basic,
|
||||
.handle = @handle(),
|
||||
.overlapped = ResumeNode.overlapped_init,
|
||||
},
|
||||
.kev = undefined,
|
||||
};
|
||||
@@ -489,15 +508,11 @@ pub const Loop = struct {
|
||||
};
|
||||
},
|
||||
builtin.Os.windows => {
|
||||
// this value is never dereferenced but we need it to be non-null so that
|
||||
// the consumer code can decide whether to read the completion key.
|
||||
// it has to do this for normal I/O, so we match that behavior here.
|
||||
const overlapped = @intToPtr(?*windows.OVERLAPPED, 0x1);
|
||||
os.windowsPostQueuedCompletionStatus(
|
||||
self.os_data.io_port,
|
||||
undefined,
|
||||
eventfd_node.completion_key,
|
||||
overlapped,
|
||||
undefined,
|
||||
&eventfd_node.base.overlapped,
|
||||
) catch {
|
||||
self.next_tick_queue.unget(next_tick_node);
|
||||
self.available_eventfd_resume_nodes.push(resume_stack_node);
|
||||
@@ -606,8 +621,8 @@ pub const Loop = struct {
|
||||
var i: usize = 0;
|
||||
while (i < self.extra_threads.len + 1) : (i += 1) {
|
||||
while (true) {
|
||||
const overlapped = @intToPtr(?*windows.OVERLAPPED, 0x1);
|
||||
os.windowsPostQueuedCompletionStatus(self.os_data.io_port, undefined, @ptrToInt(&self.final_resume_node), overlapped) catch continue;
|
||||
const overlapped = &self.final_resume_node.overlapped;
|
||||
os.windowsPostQueuedCompletionStatus(self.os_data.io_port, undefined, undefined, overlapped) catch continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -680,17 +695,18 @@ pub const Loop = struct {
|
||||
},
|
||||
builtin.Os.windows => {
|
||||
var completion_key: usize = undefined;
|
||||
while (true) {
|
||||
const overlapped = while (true) {
|
||||
var nbytes: windows.DWORD = undefined;
|
||||
var overlapped: ?*windows.OVERLAPPED = undefined;
|
||||
switch (os.windowsGetQueuedCompletionStatus(self.os_data.io_port, &nbytes, &completion_key, &overlapped, windows.INFINITE)) {
|
||||
os.WindowsWaitResult.Aborted => return,
|
||||
os.WindowsWaitResult.Normal => {},
|
||||
os.WindowsWaitResult.EOF => {},
|
||||
os.WindowsWaitResult.Cancelled => continue,
|
||||
}
|
||||
if (overlapped != null) break;
|
||||
}
|
||||
const resume_node = @intToPtr(*ResumeNode, completion_key);
|
||||
if (overlapped) |o| break o;
|
||||
} else unreachable; // TODO else unreachable should not be necessary
|
||||
const resume_node = @fieldParentPtr(ResumeNode, "overlapped", overlapped);
|
||||
const handle = resume_node.handle;
|
||||
const resume_node_id = resume_node.id;
|
||||
switch (resume_node_id) {
|
||||
|
||||
@@ -10,7 +10,7 @@ pub fn RwLocked(comptime T: type) type {
|
||||
lock: RwLock,
|
||||
locked_data: T,
|
||||
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
|
||||
pub const HeldReadLock = struct {
|
||||
value: *const T,
|
||||
|
||||
+2
-1
@@ -32,6 +32,7 @@ pub const Server = struct {
|
||||
.listen_resume_node = event.Loop.ResumeNode{
|
||||
.id = event.Loop.ResumeNode.Id.Basic,
|
||||
.handle = undefined,
|
||||
.overlapped = event.Loop.ResumeNode.overlapped_init,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -131,7 +132,7 @@ test "listen on a port, send bytes, receive bytes" {
|
||||
const MyServer = struct {
|
||||
tcp_server: Server,
|
||||
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
async<*mem.Allocator> fn handler(tcp_server: *Server, _addr: *const std.net.Address, _socket: *const std.os.File) void {
|
||||
const self = @fieldParentPtr(Self, "tcp_server", tcp_server);
|
||||
var socket = _socket.*; // TODO https://github.com/ziglang/zig/issues/733
|
||||
|
||||
+1
-1
@@ -1183,7 +1183,7 @@ test "fmt.format" {
|
||||
//custom type format
|
||||
{
|
||||
const Vec2 = struct {
|
||||
const SelfType = this;
|
||||
const SelfType = @This();
|
||||
x: f32,
|
||||
y: f32,
|
||||
|
||||
|
||||
+2
-2
@@ -20,7 +20,7 @@ pub const Crc32 = Crc32WithPoly(Polynomial.IEEE);
|
||||
// slicing-by-8 crc32 implementation.
|
||||
pub fn Crc32WithPoly(comptime poly: u32) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
const lookup_tables = comptime block: {
|
||||
@setEvalBranchQuota(20000);
|
||||
var tables: [8][256]u32 = undefined;
|
||||
@@ -117,7 +117,7 @@ test "crc32 castagnoli" {
|
||||
// half-byte lookup table implementation.
|
||||
pub fn Crc32SmallWithPoly(comptime poly: u32) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
const lookup_table = comptime block: {
|
||||
var table: [16]u32 = undefined;
|
||||
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ pub const Fnv1a_128 = Fnv1a(u128, 0x1000000000000000000013b, 0x6c62272e07bb01426
|
||||
|
||||
fn Fnv1a(comptime T: type, comptime prime: T, comptime offset: T) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
|
||||
value: T,
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
|
||||
debug.assert(c_rounds > 0 and d_rounds > 0);
|
||||
|
||||
return struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
const digest_size = 64;
|
||||
const block_size = 64;
|
||||
|
||||
|
||||
+1
-3
@@ -22,7 +22,7 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3
|
||||
// this is used to detect bugs where a hashtable is edited while an iterator is running.
|
||||
modification_count: debug_u32,
|
||||
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
|
||||
pub const KV = struct {
|
||||
key: K,
|
||||
@@ -472,7 +472,6 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type
|
||||
builtin.TypeId.Promise, builtin.TypeId.Fn => return autoHash(@ptrToInt(key), rng),
|
||||
|
||||
builtin.TypeId.Namespace,
|
||||
builtin.TypeId.Block,
|
||||
builtin.TypeId.BoundFn,
|
||||
builtin.TypeId.ComptimeFloat,
|
||||
builtin.TypeId.ComptimeInt,
|
||||
@@ -517,7 +516,6 @@ pub fn autoEql(a: var, b: @typeOf(a)) bool {
|
||||
builtin.TypeId.ComptimeFloat,
|
||||
builtin.TypeId.ComptimeInt,
|
||||
builtin.TypeId.Namespace,
|
||||
builtin.TypeId.Block,
|
||||
builtin.TypeId.Promise,
|
||||
builtin.TypeId.Enum,
|
||||
builtin.TypeId.BoundFn,
|
||||
|
||||
+1
-1
@@ -385,7 +385,7 @@ pub fn stackFallback(comptime size: usize, fallback_allocator: *Allocator) Stack
|
||||
|
||||
pub fn StackFallbackAllocator(comptime size: usize) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
|
||||
buffer: [size]u8,
|
||||
allocator: Allocator,
|
||||
|
||||
+6
-6
@@ -76,7 +76,7 @@ pub const FileOutStream = struct {
|
||||
|
||||
pub fn InStream(comptime ReadError: type) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
pub const Error = ReadError;
|
||||
|
||||
/// Return the number of bytes read. If the number read is smaller than buf.len, it
|
||||
@@ -218,7 +218,7 @@ pub fn InStream(comptime ReadError: type) type {
|
||||
|
||||
pub fn OutStream(comptime WriteError: type) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
pub const Error = WriteError;
|
||||
|
||||
writeFn: fn (self: *Self, bytes: []const u8) Error!void,
|
||||
@@ -291,7 +291,7 @@ pub fn BufferedInStream(comptime Error: type) type {
|
||||
|
||||
pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
const Stream = InStream(Error);
|
||||
|
||||
pub stream: Stream,
|
||||
@@ -361,7 +361,7 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type)
|
||||
/// This makes look-ahead style parsing much easier.
|
||||
pub fn PeekStream(comptime buffer_size: usize, comptime InStreamError: type) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
pub const Error = InStreamError;
|
||||
pub const Stream = InStream(Error);
|
||||
|
||||
@@ -424,7 +424,7 @@ pub fn PeekStream(comptime buffer_size: usize, comptime InStreamError: type) typ
|
||||
}
|
||||
|
||||
pub const SliceInStream = struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
pub const Error = error{};
|
||||
pub const Stream = InStream(Error);
|
||||
|
||||
@@ -505,7 +505,7 @@ pub fn BufferedOutStream(comptime Error: type) type {
|
||||
|
||||
pub fn BufferedOutStreamCustom(comptime buffer_size: usize, comptime OutStreamError: type) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
pub const Stream = OutStream(Error);
|
||||
pub const Error = OutStreamError;
|
||||
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ fn LazyInit(comptime T: type) type {
|
||||
state: u8, // TODO make this an enum
|
||||
data: Data,
|
||||
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
|
||||
// TODO this isn't working for void, investigate and then remove this special case
|
||||
const Data = if (@sizeOf(T) == 0) u8 else T;
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ const Allocator = mem.Allocator;
|
||||
/// Generic doubly linked list.
|
||||
pub fn LinkedList(comptime T: type) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
|
||||
/// Node inside the linked list wrapping the actual data.
|
||||
pub const Node = struct {
|
||||
|
||||
@@ -44,7 +44,7 @@ fn cosh32(z: *const Complex(f32)) Complex(f32) {
|
||||
else if (ix < 0x4340b1e7) {
|
||||
const v = Complex(f32).new(math.fabs(x), y);
|
||||
const r = ldexp_cexp(v, -1);
|
||||
return Complex(f32).new(x, y * math.copysign(f32, 1, x));
|
||||
return Complex(f32).new(r.re, r.im * math.copysign(f32, 1, x));
|
||||
}
|
||||
// x >= 192.7: result always overflows
|
||||
else {
|
||||
@@ -112,7 +112,7 @@ fn cosh64(z: *const Complex(f64)) Complex(f64) {
|
||||
else if (ix < 0x4096bbaa) {
|
||||
const v = Complex(f64).new(math.fabs(x), y);
|
||||
const r = ldexp_cexp(v, -1);
|
||||
return Complex(f64).new(x, y * math.copysign(f64, 1, x));
|
||||
return Complex(f64).new(r.re, r.im * math.copysign(f64, 1, x));
|
||||
}
|
||||
// x >= 1455: result always overflows
|
||||
else {
|
||||
|
||||
@@ -69,7 +69,7 @@ fn exp64(z: Complex(f64)) Complex(f64) {
|
||||
const y = z.im;
|
||||
|
||||
const fy = @bitCast(u64, y);
|
||||
const hy = u32(fy >> 32) & 0x7fffffff;
|
||||
const hy = @intCast(u32, (fy >> 32) & 0x7fffffff);
|
||||
const ly = @truncate(u32, fy);
|
||||
|
||||
// cexp(x + i0) = exp(x) + i0
|
||||
@@ -78,7 +78,7 @@ fn exp64(z: Complex(f64)) Complex(f64) {
|
||||
}
|
||||
|
||||
const fx = @bitCast(u64, x);
|
||||
const hx = u32(fx >> 32);
|
||||
const hx = @intCast(u32, fx >> 32);
|
||||
const lx = @truncate(u32, fx);
|
||||
|
||||
// cexp(0 + iy) = cos(y) + isin(y)
|
||||
@@ -101,8 +101,7 @@ fn exp64(z: Complex(f64)) Complex(f64) {
|
||||
|
||||
// 709.7 <= x <= 1454.3 so must scale
|
||||
if (hx >= exp_overflow and hx <= cexp_overflow) {
|
||||
const r = ldexp_cexp(z, 0);
|
||||
return r.*;
|
||||
return ldexp_cexp(z, 0);
|
||||
} // - x < exp_overflow => exp(x) won't overflow (common)
|
||||
// - x > cexp_overflow, so exp(x) * s overflows for s > 0
|
||||
// - x = +-inf
|
||||
@@ -124,7 +123,7 @@ test "complex.cexp32" {
|
||||
}
|
||||
|
||||
test "complex.cexp64" {
|
||||
const a = Complex(f32).new(5, 3);
|
||||
const a = Complex(f64).new(5, 3);
|
||||
const c = exp(a);
|
||||
|
||||
debug.assert(math.approxEq(f64, c.re, -146.927917, epsilon));
|
||||
|
||||
@@ -25,7 +25,7 @@ pub const tan = @import("tan.zig").tan;
|
||||
|
||||
pub fn Complex(comptime T: type) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
|
||||
re: T,
|
||||
im: T,
|
||||
|
||||
@@ -44,7 +44,7 @@ fn sinh32(z: Complex(f32)) Complex(f32) {
|
||||
else if (ix < 0x4340b1e7) {
|
||||
const v = Complex(f32).new(math.fabs(x), y);
|
||||
const r = ldexp_cexp(v, -1);
|
||||
return Complex(f32).new(x * math.copysign(f32, 1, x), y);
|
||||
return Complex(f32).new(r.re * math.copysign(f32, 1, x), r.im);
|
||||
}
|
||||
// x >= 192.7: result always overflows
|
||||
else {
|
||||
@@ -111,7 +111,7 @@ fn sinh64(z: Complex(f64)) Complex(f64) {
|
||||
else if (ix < 0x4096bbaa) {
|
||||
const v = Complex(f64).new(math.fabs(x), y);
|
||||
const r = ldexp_cexp(v, -1);
|
||||
return Complex(f64).new(x * math.copysign(f64, 1, x), y);
|
||||
return Complex(f64).new(r.re * math.copysign(f64, 1, x), r.im);
|
||||
}
|
||||
// x >= 1455: result always overflows
|
||||
else {
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ const debug = std.debug;
|
||||
const assert = debug.assert;
|
||||
const math = std.math;
|
||||
const builtin = @import("builtin");
|
||||
const mem = this;
|
||||
const mem = @This();
|
||||
|
||||
pub const Allocator = struct {
|
||||
pub const Error = error{OutOfMemory};
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
const std = @import("index.zig");
|
||||
const builtin = @import("builtin");
|
||||
const assert = std.debug.assert;
|
||||
const net = this;
|
||||
const net = @This();
|
||||
const posix = std.os.posix;
|
||||
const mem = std.mem;
|
||||
|
||||
|
||||
@@ -658,8 +658,16 @@ fn windowsCreateProcess(app_name: [*]u16, cmd_line: [*]u16, envp_ptr: ?[*]u16, c
|
||||
// environment variables to programs that were not, which seems unlikely.
|
||||
// More investigation is needed.
|
||||
if (windows.CreateProcessW(
|
||||
app_name, cmd_line, null, null, windows.TRUE, windows.CREATE_UNICODE_ENVIRONMENT,
|
||||
@ptrCast(?*c_void, envp_ptr), cwd_ptr, lpStartupInfo, lpProcessInformation,
|
||||
app_name,
|
||||
cmd_line,
|
||||
null,
|
||||
null,
|
||||
windows.TRUE,
|
||||
windows.CREATE_UNICODE_ENVIRONMENT,
|
||||
@ptrCast(?*c_void, envp_ptr),
|
||||
cwd_ptr,
|
||||
lpStartupInfo,
|
||||
lpProcessInformation,
|
||||
) == 0) {
|
||||
const err = windows.GetLastError();
|
||||
switch (err) {
|
||||
|
||||
+20
-18
@@ -6,7 +6,7 @@ const is_posix = switch (builtin.os) {
|
||||
builtin.Os.linux, builtin.Os.macosx => true,
|
||||
else => false,
|
||||
};
|
||||
const os = this;
|
||||
const os = @This();
|
||||
|
||||
test "std.os" {
|
||||
_ = @import("child_process.zig");
|
||||
@@ -343,23 +343,25 @@ pub fn posixWrite(fd: i32, bytes: []const u8) !void {
|
||||
const amt_to_write = math.min(bytes.len - index, usize(max_bytes_len));
|
||||
const rc = posix.write(fd, bytes.ptr + index, amt_to_write);
|
||||
const write_err = posix.getErrno(rc);
|
||||
if (write_err > 0) {
|
||||
return switch (write_err) {
|
||||
posix.EINTR => continue,
|
||||
posix.EINVAL, posix.EFAULT => unreachable,
|
||||
posix.EAGAIN => PosixWriteError.WouldBlock,
|
||||
posix.EBADF => PosixWriteError.FileClosed,
|
||||
posix.EDESTADDRREQ => PosixWriteError.DestinationAddressRequired,
|
||||
posix.EDQUOT => PosixWriteError.DiskQuota,
|
||||
posix.EFBIG => PosixWriteError.FileTooBig,
|
||||
posix.EIO => PosixWriteError.InputOutput,
|
||||
posix.ENOSPC => PosixWriteError.NoSpaceLeft,
|
||||
posix.EPERM => PosixWriteError.AccessDenied,
|
||||
posix.EPIPE => PosixWriteError.BrokenPipe,
|
||||
else => unexpectedErrorPosix(write_err),
|
||||
};
|
||||
switch (write_err) {
|
||||
0 => {
|
||||
index += rc;
|
||||
continue;
|
||||
},
|
||||
posix.EINTR => continue,
|
||||
posix.EINVAL => unreachable,
|
||||
posix.EFAULT => unreachable,
|
||||
posix.EAGAIN => return PosixWriteError.WouldBlock,
|
||||
posix.EBADF => return PosixWriteError.FileClosed,
|
||||
posix.EDESTADDRREQ => return PosixWriteError.DestinationAddressRequired,
|
||||
posix.EDQUOT => return PosixWriteError.DiskQuota,
|
||||
posix.EFBIG => return PosixWriteError.FileTooBig,
|
||||
posix.EIO => return PosixWriteError.InputOutput,
|
||||
posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
|
||||
posix.EPERM => return PosixWriteError.AccessDenied,
|
||||
posix.EPIPE => return PosixWriteError.BrokenPipe,
|
||||
else => return unexpectedErrorPosix(write_err),
|
||||
}
|
||||
index += rc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1614,7 +1616,7 @@ pub const Dir = struct {
|
||||
return null;
|
||||
}
|
||||
const name_utf16le = mem.toSlice(u16, self.handle.find_file_data.cFileName[0..].ptr);
|
||||
if (mem.eql(u16, name_utf16le, []u16{'.'}) or mem.eql(u16, name_utf16le, []u16{'.', '.'}))
|
||||
if (mem.eql(u16, name_utf16le, []u16{'.'}) or mem.eql(u16, name_utf16le, []u16{ '.', '.' }))
|
||||
continue;
|
||||
// Trust that Windows gives us valid UTF-16LE
|
||||
const name_utf8_len = std.unicode.utf16leToUtf8(self.handle.name_data[0..], name_utf16le) catch unreachable;
|
||||
|
||||
@@ -206,7 +206,6 @@ pub const FILE_NOTIFY_CHANGE_DIR_NAME = 2;
|
||||
pub const FILE_NOTIFY_CHANGE_FILE_NAME = 1;
|
||||
pub const FILE_NOTIFY_CHANGE_ATTRIBUTES = 4;
|
||||
|
||||
|
||||
pub const CONSOLE_SCREEN_BUFFER_INFO = extern struct {
|
||||
dwSize: COORD,
|
||||
dwCursorPosition: COORD,
|
||||
|
||||
@@ -52,7 +52,8 @@ pub const WriteError = error{
|
||||
};
|
||||
|
||||
pub fn windowsWrite(handle: windows.HANDLE, bytes: []const u8) WriteError!void {
|
||||
if (windows.WriteFile(handle, bytes.ptr, @intCast(u32, bytes.len), null, null) == 0) {
|
||||
var bytes_written: windows.DWORD = undefined;
|
||||
if (windows.WriteFile(handle, bytes.ptr, @intCast(u32, bytes.len), &bytes_written, null) == 0) {
|
||||
const err = windows.GetLastError();
|
||||
return switch (err) {
|
||||
windows.ERROR.INVALID_USER_BUFFER => WriteError.SystemResources,
|
||||
@@ -222,7 +223,7 @@ pub fn windowsFindFirstFile(
|
||||
dir_path: []const u8,
|
||||
find_file_data: *windows.WIN32_FIND_DATAW,
|
||||
) !windows.HANDLE {
|
||||
const dir_path_w = try sliceToPrefixedSuffixedFileW(dir_path, []u16{'\\', '*', 0});
|
||||
const dir_path_w = try sliceToPrefixedSuffixedFileW(dir_path, []u16{ '\\', '*', 0 });
|
||||
const handle = windows.FindFirstFileW(&dir_path_w, find_file_data);
|
||||
|
||||
if (handle == windows.INVALID_HANDLE_VALUE) {
|
||||
@@ -277,6 +278,7 @@ pub const WindowsWaitResult = enum {
|
||||
Normal,
|
||||
Aborted,
|
||||
Cancelled,
|
||||
EOF,
|
||||
};
|
||||
|
||||
pub fn windowsGetQueuedCompletionStatus(completion_port: windows.HANDLE, bytes_transferred_count: *windows.DWORD, lpCompletionKey: *usize, lpOverlapped: *?*windows.OVERLAPPED, dwMilliseconds: windows.DWORD) WindowsWaitResult {
|
||||
@@ -285,6 +287,7 @@ pub fn windowsGetQueuedCompletionStatus(completion_port: windows.HANDLE, bytes_t
|
||||
switch (err) {
|
||||
windows.ERROR.ABANDONED_WAIT_0 => return WindowsWaitResult.Aborted,
|
||||
windows.ERROR.OPERATION_ABORTED => return WindowsWaitResult.Cancelled,
|
||||
windows.ERROR.HANDLE_EOF => return WindowsWaitResult.EOF,
|
||||
else => {
|
||||
if (std.debug.runtime_safety) {
|
||||
std.debug.panic("unexpected error: {}\n", err);
|
||||
|
||||
+96
-61
@@ -64,19 +64,35 @@ pub const ModInfo = packed struct {
|
||||
};
|
||||
|
||||
pub const SectionMapHeader = packed struct {
|
||||
Count: u16, /// Number of segment descriptors
|
||||
LogCount: u16, /// Number of logical segment descriptors
|
||||
/// Number of segment descriptors
|
||||
Count: u16,
|
||||
|
||||
/// Number of logical segment descriptors
|
||||
LogCount: u16,
|
||||
};
|
||||
|
||||
pub const SectionMapEntry = packed struct {
|
||||
Flags: u16 , /// See the SectionMapEntryFlags enum below.
|
||||
Ovl: u16 , /// Logical overlay number
|
||||
Group: u16 , /// Group index into descriptor array.
|
||||
Frame: u16 ,
|
||||
SectionName: u16 , /// Byte index of segment / group name in string table, or 0xFFFF.
|
||||
ClassName: u16 , /// Byte index of class in string table, or 0xFFFF.
|
||||
Offset: u32 , /// Byte offset of the logical segment within physical segment. If group is set in flags, this is the offset of the group.
|
||||
SectionLength: u32 , /// Byte count of the segment or group.
|
||||
/// See the SectionMapEntryFlags enum below.
|
||||
Flags: u16,
|
||||
|
||||
/// Logical overlay number
|
||||
Ovl: u16,
|
||||
|
||||
/// Group index into descriptor array.
|
||||
Group: u16,
|
||||
Frame: u16,
|
||||
|
||||
/// Byte index of segment / group name in string table, or 0xFFFF.
|
||||
SectionName: u16,
|
||||
|
||||
/// Byte index of class in string table, or 0xFFFF.
|
||||
ClassName: u16,
|
||||
|
||||
/// Byte offset of the logical segment within physical segment. If group is set in flags, this is the offset of the group.
|
||||
Offset: u32,
|
||||
|
||||
/// Byte count of the segment or group.
|
||||
SectionLength: u32,
|
||||
};
|
||||
|
||||
pub const StreamType = enum(u16) {
|
||||
@@ -290,13 +306,13 @@ pub const SymbolKind = packed enum(u16) {
|
||||
pub const TypeIndex = u32;
|
||||
|
||||
pub const ProcSym = packed struct {
|
||||
Parent: u32 ,
|
||||
End: u32 ,
|
||||
Next: u32 ,
|
||||
CodeSize: u32 ,
|
||||
DbgStart: u32 ,
|
||||
DbgEnd: u32 ,
|
||||
FunctionType: TypeIndex ,
|
||||
Parent: u32,
|
||||
End: u32,
|
||||
Next: u32,
|
||||
CodeSize: u32,
|
||||
DbgStart: u32,
|
||||
DbgEnd: u32,
|
||||
FunctionType: TypeIndex,
|
||||
CodeOffset: u32,
|
||||
Segment: u16,
|
||||
Flags: ProcSymFlags,
|
||||
@@ -315,25 +331,34 @@ pub const ProcSymFlags = packed struct {
|
||||
HasOptimizedDebugInfo: bool,
|
||||
};
|
||||
|
||||
pub const SectionContrSubstreamVersion = enum(u32) {
|
||||
Ver60 = 0xeffe0000 + 19970605,
|
||||
V2 = 0xeffe0000 + 20140516
|
||||
pub const SectionContrSubstreamVersion = enum(u32) {
|
||||
Ver60 = 0xeffe0000 + 19970605,
|
||||
V2 = 0xeffe0000 + 20140516,
|
||||
};
|
||||
|
||||
pub const RecordPrefix = packed struct {
|
||||
RecordLen: u16, /// Record length, starting from &RecordKind.
|
||||
RecordKind: SymbolKind, /// Record kind enum (SymRecordKind or TypeRecordKind)
|
||||
/// Record length, starting from &RecordKind.
|
||||
RecordLen: u16,
|
||||
|
||||
/// Record kind enum (SymRecordKind or TypeRecordKind)
|
||||
RecordKind: SymbolKind,
|
||||
};
|
||||
|
||||
pub const LineFragmentHeader = packed struct {
|
||||
RelocOffset: u32, /// Code offset of line contribution.
|
||||
RelocSegment: u16, /// Code segment of line contribution.
|
||||
/// Code offset of line contribution.
|
||||
RelocOffset: u32,
|
||||
|
||||
/// Code segment of line contribution.
|
||||
RelocSegment: u16,
|
||||
Flags: LineFlags,
|
||||
CodeSize: u32, /// Code size of this line contribution.
|
||||
|
||||
/// Code size of this line contribution.
|
||||
CodeSize: u32,
|
||||
};
|
||||
|
||||
pub const LineFlags = packed struct {
|
||||
LF_HaveColumns: bool, /// CV_LINES_HAVE_COLUMNS
|
||||
/// CV_LINES_HAVE_COLUMNS
|
||||
LF_HaveColumns: bool,
|
||||
unused: u15,
|
||||
};
|
||||
|
||||
@@ -348,12 +373,14 @@ pub const LineBlockFragmentHeader = packed struct {
|
||||
/// table of the actual name.
|
||||
NameIndex: u32,
|
||||
NumLines: u32,
|
||||
BlockSize: u32, /// code size of block, in bytes
|
||||
|
||||
/// code size of block, in bytes
|
||||
BlockSize: u32,
|
||||
};
|
||||
|
||||
|
||||
pub const LineNumberEntry = packed struct {
|
||||
Offset: u32, /// Offset to start of code bytes for line number
|
||||
/// Offset to start of code bytes for line number
|
||||
Offset: u32,
|
||||
Flags: u32,
|
||||
|
||||
/// TODO runtime crash when I make the actual type of Flags this
|
||||
@@ -371,42 +398,53 @@ pub const ColumnNumberEntry = packed struct {
|
||||
|
||||
/// Checksum bytes follow.
|
||||
pub const FileChecksumEntryHeader = packed struct {
|
||||
FileNameOffset: u32, /// Byte offset of filename in global string table.
|
||||
ChecksumSize: u8, /// Number of bytes of checksum.
|
||||
ChecksumKind: u8, /// FileChecksumKind
|
||||
/// Byte offset of filename in global string table.
|
||||
FileNameOffset: u32,
|
||||
|
||||
/// Number of bytes of checksum.
|
||||
ChecksumSize: u8,
|
||||
|
||||
/// FileChecksumKind
|
||||
ChecksumKind: u8,
|
||||
};
|
||||
|
||||
pub const DebugSubsectionKind = packed enum(u32) {
|
||||
None = 0,
|
||||
Symbols = 0xf1,
|
||||
Lines = 0xf2,
|
||||
StringTable = 0xf3,
|
||||
FileChecksums = 0xf4,
|
||||
FrameData = 0xf5,
|
||||
InlineeLines = 0xf6,
|
||||
CrossScopeImports = 0xf7,
|
||||
CrossScopeExports = 0xf8,
|
||||
None = 0,
|
||||
Symbols = 0xf1,
|
||||
Lines = 0xf2,
|
||||
StringTable = 0xf3,
|
||||
FileChecksums = 0xf4,
|
||||
FrameData = 0xf5,
|
||||
InlineeLines = 0xf6,
|
||||
CrossScopeImports = 0xf7,
|
||||
CrossScopeExports = 0xf8,
|
||||
|
||||
// These appear to relate to .Net assembly info.
|
||||
ILLines = 0xf9,
|
||||
FuncMDTokenMap = 0xfa,
|
||||
TypeMDTokenMap = 0xfb,
|
||||
MergedAssemblyInput = 0xfc,
|
||||
// These appear to relate to .Net assembly info.
|
||||
ILLines = 0xf9,
|
||||
FuncMDTokenMap = 0xfa,
|
||||
TypeMDTokenMap = 0xfb,
|
||||
MergedAssemblyInput = 0xfc,
|
||||
|
||||
CoffSymbolRVA = 0xfd,
|
||||
CoffSymbolRVA = 0xfd,
|
||||
};
|
||||
|
||||
|
||||
pub const DebugSubsectionHeader = packed struct {
|
||||
Kind: DebugSubsectionKind, /// codeview::DebugSubsectionKind enum
|
||||
Length: u32, /// number of bytes occupied by this record.
|
||||
/// codeview::DebugSubsectionKind enum
|
||||
Kind: DebugSubsectionKind,
|
||||
|
||||
/// number of bytes occupied by this record.
|
||||
Length: u32,
|
||||
};
|
||||
|
||||
|
||||
pub const PDBStringTableHeader = packed struct {
|
||||
Signature: u32, /// PDBStringTableSignature
|
||||
HashVersion: u32, /// 1 or 2
|
||||
ByteSize: u32, /// Number of bytes of names buffer.
|
||||
/// PDBStringTableSignature
|
||||
Signature: u32,
|
||||
|
||||
/// 1 or 2
|
||||
HashVersion: u32,
|
||||
|
||||
/// Number of bytes of names buffer.
|
||||
ByteSize: u32,
|
||||
};
|
||||
|
||||
pub const Pdb = struct {
|
||||
@@ -456,7 +494,7 @@ const Msf = struct {
|
||||
switch (superblock.BlockSize) {
|
||||
// llvm only supports 4096 but we can handle any of these values
|
||||
512, 1024, 2048, 4096 => {},
|
||||
else => return error.InvalidDebugInfo
|
||||
else => return error.InvalidDebugInfo,
|
||||
}
|
||||
|
||||
if (superblock.NumBlocks * superblock.BlockSize != try file.getEndPos())
|
||||
@@ -536,7 +574,6 @@ const SuperBlock = packed struct {
|
||||
/// The number of ulittle32_t’s in this array is given by
|
||||
/// ceil(NumDirectoryBytes / BlockSize).
|
||||
BlockMapAddr: u32,
|
||||
|
||||
};
|
||||
|
||||
const MsfStream = struct {
|
||||
@@ -552,14 +589,12 @@ const MsfStream = struct {
|
||||
pub const Stream = io.InStream(Error);
|
||||
|
||||
fn init(block_size: u32, block_count: u32, pos: usize, file: os.File, allocator: *mem.Allocator) !MsfStream {
|
||||
var stream = MsfStream {
|
||||
var stream = MsfStream{
|
||||
.in_file = file,
|
||||
.pos = 0,
|
||||
.blocks = try allocator.alloc(u32, block_count),
|
||||
.block_size = block_size,
|
||||
.stream = Stream {
|
||||
.readFn = readFn,
|
||||
},
|
||||
.stream = Stream{ .readFn = readFn },
|
||||
};
|
||||
|
||||
var file_stream = io.FileInStream.init(file);
|
||||
@@ -597,7 +632,7 @@ const MsfStream = struct {
|
||||
|
||||
var size: usize = 0;
|
||||
for (buffer) |*byte| {
|
||||
byte.* = try in.readByte();
|
||||
byte.* = try in.readByte();
|
||||
|
||||
offset += 1;
|
||||
size += 1;
|
||||
|
||||
@@ -75,7 +75,7 @@ const Allocator = std.mem.Allocator;
|
||||
/// size is small. `prealloc_item_count` must be 0, or a power of 2.
|
||||
pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
const prealloc_exp = blk: {
|
||||
// we don't use the prealloc_exp constant when prealloc_item_count is 0.
|
||||
assert(prealloc_item_count != 0);
|
||||
|
||||
+2
-2
@@ -231,7 +231,7 @@ pub const Error = union(enum) {
|
||||
|
||||
fn SingleTokenError(comptime msg: []const u8) type {
|
||||
return struct {
|
||||
const ThisError = this;
|
||||
const ThisError = @This();
|
||||
|
||||
token: TokenIndex,
|
||||
|
||||
@@ -244,7 +244,7 @@ pub const Error = union(enum) {
|
||||
|
||||
fn SimpleError(comptime msg: []const u8) type {
|
||||
return struct {
|
||||
const ThisError = this;
|
||||
const ThisError = @This();
|
||||
|
||||
token: TokenIndex,
|
||||
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ pub fn main() !void {
|
||||
const mb_per_sec = bytes_per_sec / (1024 * 1024);
|
||||
|
||||
var stdout_file = try std.io.getStdOut();
|
||||
const stdout = &std.io.FileOutStream.init(&stdout_file).stream;
|
||||
const stdout = &std.io.FileOutStream.init(stdout_file).stream;
|
||||
try stdout.print("{.3} MiB/s, {} KiB used \n", mb_per_sec, memory_used / 1024);
|
||||
}
|
||||
|
||||
|
||||
@@ -1354,7 +1354,7 @@ test "zig fmt: indexing" {
|
||||
test "zig fmt: struct declaration" {
|
||||
try testCanonical(
|
||||
\\const S = struct {
|
||||
\\ const Self = this;
|
||||
\\ const Self = @This();
|
||||
\\ f1: u8,
|
||||
\\ pub f3: u8,
|
||||
\\
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ pub fn render(allocator: *mem.Allocator, stream: var, tree: *ast.Tree) (@typeOf(
|
||||
|
||||
// make a passthrough stream that checks whether something changed
|
||||
const MyStream = struct {
|
||||
const MyStream = this;
|
||||
const MyStream = @This();
|
||||
const StreamError = @typeOf(stream).Child.Error;
|
||||
const Stream = std.io.OutStream(StreamError);
|
||||
|
||||
|
||||
@@ -10,7 +10,10 @@ comptime {
|
||||
_ = @import("cases/bool.zig");
|
||||
_ = @import("cases/bugs/1111.zig");
|
||||
_ = @import("cases/bugs/1277.zig");
|
||||
_ = @import("cases/bugs/1322.zig");
|
||||
_ = @import("cases/bugs/1381.zig");
|
||||
_ = @import("cases/bugs/1421.zig");
|
||||
_ = @import("cases/bugs/1442.zig");
|
||||
_ = @import("cases/bugs/394.zig");
|
||||
_ = @import("cases/bugs/655.zig");
|
||||
_ = @import("cases/bugs/656.zig");
|
||||
|
||||
@@ -212,3 +212,10 @@ fn fnWithAlignedStack() i32 {
|
||||
@setAlignStack(256);
|
||||
return 1234;
|
||||
}
|
||||
|
||||
test "alignment of structs" {
|
||||
assert(@alignOf(struct {
|
||||
a: i32,
|
||||
b: *i32,
|
||||
}) == @alignOf(usize));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
const std = @import("std");
|
||||
|
||||
const B = union(enum) {
|
||||
c: C,
|
||||
None,
|
||||
};
|
||||
|
||||
const A = struct {
|
||||
b: B,
|
||||
};
|
||||
|
||||
const C = struct {};
|
||||
|
||||
test "tagged union with all void fields but a meaningful tag" {
|
||||
var a: A = A{ .b = B{ .c = C{} } };
|
||||
std.debug.assert(@TagType(B)(a.b) == @TagType(B).c);
|
||||
a = A{ .b = B.None };
|
||||
std.debug.assert(@TagType(B)(a.b) == @TagType(B).None);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
const std = @import("std");
|
||||
|
||||
const B = union(enum) {
|
||||
D: u8,
|
||||
E: u16,
|
||||
};
|
||||
|
||||
const A = union(enum) {
|
||||
B: B,
|
||||
C: u8,
|
||||
};
|
||||
|
||||
test "union that needs padding bytes inside an array" {
|
||||
var as = []A{
|
||||
A{ .B = B{ .D = 1 } },
|
||||
A{ .B = B{ .D = 1 } },
|
||||
};
|
||||
|
||||
const a = as[0].B;
|
||||
std.debug.assertOrPanic(a.D == 1);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
const std = @import("std");
|
||||
|
||||
const Union = union(enum) {
|
||||
Text: []const u8,
|
||||
Color: u32,
|
||||
};
|
||||
|
||||
test "const error union field alignment" {
|
||||
var union_or_err: error!Union = Union{ .Color = 1234 };
|
||||
std.debug.assertOrPanic((union_or_err catch unreachable).Color == 1234);
|
||||
}
|
||||
+13
-2
@@ -64,7 +64,7 @@ test "implicitly cast a container to a const pointer of it" {
|
||||
|
||||
fn Struct(comptime T: type) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
x: T,
|
||||
|
||||
fn pointer(self: *const Self) Self {
|
||||
@@ -106,7 +106,7 @@ const Enum = enum {
|
||||
|
||||
test "implicitly cast indirect pointer to maybe-indirect pointer" {
|
||||
const S = struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
x: u8,
|
||||
fn constConst(p: *const *const Self) u8 {
|
||||
return p.*.x;
|
||||
@@ -526,3 +526,14 @@ test "*usize to *void" {
|
||||
var v = @ptrCast(*void, &i);
|
||||
v.* = {};
|
||||
}
|
||||
|
||||
test "compile time int to ptr of function" {
|
||||
foobar(FUNCTION_CONSTANT);
|
||||
}
|
||||
|
||||
pub const FUNCTION_CONSTANT = @intToPtr(PFN_void, @maxValue(usize));
|
||||
pub const PFN_void = extern fn (*c_void) void;
|
||||
|
||||
fn foobar(func: PFN_void) void {
|
||||
std.debug.assert(@ptrToInt(func) == @maxValue(usize));
|
||||
}
|
||||
|
||||
+2
-2
@@ -275,7 +275,7 @@ test "eval @setFloatMode at compile-time" {
|
||||
}
|
||||
|
||||
fn fnWithFloatMode() f32 {
|
||||
@setFloatMode(this, builtin.FloatMode.Strict);
|
||||
@setFloatMode(builtin.FloatMode.Strict);
|
||||
return 1234.0;
|
||||
}
|
||||
|
||||
@@ -628,7 +628,7 @@ test "call method with comptime pass-by-non-copying-value self parameter" {
|
||||
const S = struct {
|
||||
a: u8,
|
||||
|
||||
fn b(comptime s: this) u8 {
|
||||
fn b(comptime s: @This()) u8 {
|
||||
return s.a;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -510,9 +510,6 @@ test "@typeId" {
|
||||
assert(@typeId(AUnion) == Tid.Union);
|
||||
assert(@typeId(fn () void) == Tid.Fn);
|
||||
assert(@typeId(@typeOf(builtin)) == Tid.Namespace);
|
||||
assert(@typeId(@typeOf(x: {
|
||||
break :x this;
|
||||
})) == Tid.Block);
|
||||
// TODO bound fn
|
||||
// TODO arg tuple
|
||||
// TODO opaque
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const assert = @import("std").debug.assert;
|
||||
const mem = @import("std").mem;
|
||||
const reflection = this;
|
||||
const reflection = @This();
|
||||
|
||||
test "reflection: array, pointer, optional, error union type child" {
|
||||
comptime {
|
||||
|
||||
@@ -423,10 +423,10 @@ fn alloc(comptime T: type) []T {
|
||||
|
||||
test "call method with mutable reference to struct with no fields" {
|
||||
const S = struct {
|
||||
fn doC(s: *const this) bool {
|
||||
fn doC(s: *const @This()) bool {
|
||||
return true;
|
||||
}
|
||||
fn do(s: *this) bool {
|
||||
fn do(s: *@This()) bool {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
+2
-11
@@ -1,10 +1,10 @@
|
||||
const assert = @import("std").debug.assert;
|
||||
|
||||
const module = this;
|
||||
const module = @This();
|
||||
|
||||
fn Point(comptime T: type) type {
|
||||
return struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
x: T,
|
||||
y: T,
|
||||
|
||||
@@ -19,11 +19,6 @@ fn add(x: i32, y: i32) i32 {
|
||||
return x + y;
|
||||
}
|
||||
|
||||
fn factorial(x: i32) i32 {
|
||||
const selfFn = this;
|
||||
return if (x == 0) 1 else x * selfFn(x - 1);
|
||||
}
|
||||
|
||||
test "this refer to module call private fn" {
|
||||
assert(module.add(1, 2) == 3);
|
||||
}
|
||||
@@ -37,7 +32,3 @@ test "this refer to container" {
|
||||
assert(pt.x == 13);
|
||||
assert(pt.y == 35);
|
||||
}
|
||||
|
||||
test "this refer to fn" {
|
||||
assert(factorial(5) == 120);
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ fn testUnion() void {
|
||||
assert(TypeId(typeinfo_info) == TypeId.Union);
|
||||
assert(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
|
||||
assert(typeinfo_info.Union.tag_type.? == TypeId);
|
||||
assert(typeinfo_info.Union.fields.len == 25);
|
||||
assert(typeinfo_info.Union.fields.len == 24);
|
||||
assert(typeinfo_info.Union.fields[4].enum_field != null);
|
||||
assert(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
|
||||
assert(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));
|
||||
@@ -217,7 +217,7 @@ fn testStruct() void {
|
||||
}
|
||||
|
||||
const TestStruct = packed struct {
|
||||
const Self = this;
|
||||
const Self = @This();
|
||||
|
||||
fieldA: usize,
|
||||
fieldB: void,
|
||||
|
||||
@@ -324,3 +324,42 @@ test "tagged union with no payloads" {
|
||||
@TagType(UnionEnumNoPayloads).B => {},
|
||||
}
|
||||
}
|
||||
|
||||
test "union with only 1 field casted to its enum type" {
|
||||
const Literal = union(enum) {
|
||||
Number: f64,
|
||||
Bool: bool,
|
||||
};
|
||||
|
||||
const Expr = union(enum) {
|
||||
Literal: Literal,
|
||||
};
|
||||
|
||||
var e = Expr{ .Literal = Literal{ .Bool = true } };
|
||||
const Tag = @TagType(Expr);
|
||||
comptime assert(@TagType(Tag) == comptime_int);
|
||||
var t = Tag(e);
|
||||
assert(t == Expr.Literal);
|
||||
}
|
||||
|
||||
test "union with only 1 field casted to its enum type which has enum value specified" {
|
||||
const Literal = union(enum) {
|
||||
Number: f64,
|
||||
Bool: bool,
|
||||
};
|
||||
|
||||
const Tag = enum {
|
||||
Literal = 33,
|
||||
};
|
||||
|
||||
const Expr = union(Tag) {
|
||||
Literal: Literal,
|
||||
};
|
||||
|
||||
var e = Expr{ .Literal = Literal{ .Bool = true } };
|
||||
comptime assert(@TagType(Tag) == comptime_int);
|
||||
var t = Tag(e);
|
||||
assert(t == Expr.Literal);
|
||||
assert(@enumToInt(t) == 33);
|
||||
comptime assert(@enumToInt(t) == 33);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user