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

This commit is contained in:
Andrew Kelley
2018-09-16 10:51:58 -04:00
102 changed files with 4886 additions and 2288 deletions
+13 -1
View File
@@ -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}
+27 -9
View File
@@ -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));
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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
+2 -2
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -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();
-12
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
-7
View File
@@ -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
View File
@@ -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
View File
@@ -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
+4
View File
@@ -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));
}
+469
View File
@@ -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);
}
+71
View 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
View File
@@ -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
View File
@@ -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);
+66
View File
@@ -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;
}
+17
View File
@@ -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
+5
View File
@@ -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)";
}
+5
View File
@@ -27,6 +27,11 @@ enum Error {
ErrorNegativeDenominator,
ErrorShiftedOutOneBits,
ErrorCCompileErrors,
ErrorEndOfFile,
ErrorIsDir,
ErrorUnsupportedOperatingSystem,
ErrorSharingViolation,
ErrorPipeBusy,
};
const char *err_str(int err);
+353 -234
View File
@@ -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
View File
@@ -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");
}
-17
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+16
View File
@@ -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,
+1
View File
@@ -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);
-2
View File
@@ -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";
-1
View File
@@ -87,7 +87,6 @@ enum TokenId {
TokenIdKeywordSuspend,
TokenIdKeywordSwitch,
TokenIdKeywordTest,
TokenIdKeywordThis,
TokenIdKeywordTrue,
TokenIdKeywordTry,
TokenIdKeywordUndefined,
+49
View File
@@ -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};
}
+13
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 };
+2 -2
View File
@@ -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);
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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,
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+1 -1
View File
@@ -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
View File
@@ -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)
+1 -1
View File
@@ -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
View File
@@ -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),
+1 -1
View File
@@ -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
View File
@@ -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,
+1 -1
View File
@@ -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
View File
@@ -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) {
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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,
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 {
+2 -2
View File
@@ -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 {
+4 -5
View File
@@ -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));
+1 -1
View File
@@ -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,
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+10 -2
View File
@@ -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
View File
@@ -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;
-1
View File
@@ -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,
+5 -2
View File
@@ -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
View File
@@ -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_ts 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;
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
+1 -1
View File
@@ -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
View File
@@ -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);
+3
View File
@@ -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");
+7
View File
@@ -212,3 +212,10 @@ fn fnWithAlignedStack() i32 {
@setAlignStack(256);
return 1234;
}
test "alignment of structs" {
assert(@alignOf(struct {
a: i32,
b: *i32,
}) == @alignOf(usize));
}
+19
View File
@@ -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);
}
+21
View File
@@ -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);
}
+11
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
};
-3
View File
@@ -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 -1
View File
@@ -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 {
+2 -2
View File
@@ -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
View File
@@ -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);
}
+2 -2
View File
@@ -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,
+39
View File
@@ -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