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

master
Andrew Kelley 2018-09-16 10:51:58 -04:00
commit a2abdb185f
No known key found for this signature in database
GPG Key ID: 4E7CD66038A4D47C
102 changed files with 4886 additions and 2288 deletions

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}

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));

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

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

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

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 => {},

File diff suppressed because one or more lines are too long

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();

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,

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 {

File diff suppressed because it is too large Load Diff

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);

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
src/blake2.h Normal file
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
src/blake2b.c Normal file
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

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
src/cache_hash.cpp Normal file
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
src/cache_hash.hpp Normal file
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

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) {

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
src/compiler.cpp Normal file
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
src/compiler.hpp Normal file
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

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)";
}

View File

@ -27,6 +27,11 @@ enum Error {
ErrorNegativeDenominator,
ErrorShiftedOutOneBits,
ErrorCCompileErrors,
ErrorEndOfFile,
ErrorIsDir,
ErrorUnsupportedOperatingSystem,
ErrorSharingViolation,
ErrorPipeBusy,
};
const char *err_str(int err);

File diff suppressed because it is too large Load Diff

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");
}

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

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 {

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
}

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

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);

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,

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);

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";

View File

@ -87,7 +87,6 @@ enum TokenId {
TokenIdKeywordSuspend,
TokenIdKeywordSwitch,
TokenIdKeywordTest,
TokenIdKeywordThis,
TokenIdKeywordTrue,
TokenIdKeywordTry,
TokenIdKeywordUndefined,

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};
}

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

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;
}

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);

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

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 };

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);

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,

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) {

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,

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;

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;

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;

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;

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;

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;

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;

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);
}

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)

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,

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),

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 {

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,

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,

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) {

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,

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

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,

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;

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,

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;

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,

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,

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;

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;

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 {

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 {

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));

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,

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 {

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};

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;

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) {

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;

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,

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);

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;

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);

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,

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);
}

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,
\\

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);

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");

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
test/cases/bugs/1322.zig Normal file
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
test/cases/bugs/1381.zig Normal file
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
test/cases/bugs/1442.zig Normal file
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);
}

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));
}

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;
}
};

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

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 {

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;
}
};

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);
}

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,

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