From 97c9f61db47ddba43a0db562e13773514875fa6a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 5 Sep 2018 00:34:46 -0400 Subject: start creating a hash of input parameters See #1416 --- src/codegen.cpp | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 162 insertions(+), 13 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 0300ccca99..e258f8d609 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -19,6 +19,7 @@ #include "target.hpp" #include "util.hpp" #include "zig_llvm.h" +#include "blake2.h" #include #include @@ -183,10 +184,6 @@ 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; } @@ -7112,23 +7109,30 @@ 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; - - codegen_add_time_event(g, "Semantic Analysis"); + return nullptr; - 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)); + 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); } @@ -7671,10 +7675,155 @@ void codegen_add_time_event(CodeGen *g, const char *name) { g->timing_events.append({os_get_time(), name}); } +static void add_cache_str(blake2b_state *blake, const char *ptr) { + assert(ptr != nullptr); + // + 1 to include the null byte + blake2b_update(blake, ptr, strlen(ptr) + 1); +} + +static void add_cache_int(blake2b_state *blake, int x) { + // + 1 to include the null byte + uint8_t buf[sizeof(int) + 1]; + memcpy(buf, &x, sizeof(int)); + buf[sizeof(int)] = 0; + blake2b_update(blake, buf, sizeof(int) + 1); +} + +static void add_cache_buf(blake2b_state *blake, Buf *buf) { + assert(buf != nullptr); + // + 1 to include the null byte + blake2b_update(blake, buf_ptr(buf), buf_len(buf) + 1); +} + +static void add_cache_buf_opt(blake2b_state *blake, Buf *buf) { + if (buf == nullptr) { + add_cache_str(blake, ""); + add_cache_str(blake, ""); + } else { + add_cache_buf(blake, buf); + } +} + +static void add_cache_list_of_link_lib(blake2b_state *blake, LinkLib **ptr, size_t len) { + for (size_t i = 0; i < len; i += 1) { + LinkLib *lib = ptr[i]; + if (lib->provided_explicitly) { + add_cache_buf(blake, lib->name); + } + } + add_cache_str(blake, ""); +} + +static void add_cache_list_of_buf(blake2b_state *blake, Buf **ptr, size_t len) { + for (size_t i = 0; i < len; i += 1) { + Buf *buf = ptr[i]; + add_cache_buf(blake, buf); + } + add_cache_str(blake, ""); +} + +//static void add_cache_file(CodeGen *g, blake2b_state *blake, Buf *resolved_path) { +// assert(file_name != nullptr); +// g->cache_files.append(resolved_path); +//} +// +//static void add_cache_file_opt(CodeGen *g, blake2b_state *blake, Buf *resolved_path) { +// if (resolved_path == nullptr) { +// add_cache_str(blake, ""); +// add_cache_str(blake, ""); +// } else { +// add_cache_file(g, blake, resolved_path); +// } +//} + +// Ported from std/base64.zig +static uint8_t base64_fs_alphabet[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"; +static void base64_encode(Slice dest, Slice 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); + //if (i < source.len) { + // dest.ptr[out_index] = base64_fs_alphabet[(source.ptr[i] >> 2) & 0x3f]; + // out_index += 1; + + // if (i + 1 == source.len) { + // dest.ptr[out_index] = base64_fs_alphabet[(source.ptr[i] & 0x3) << 4]; + // out_index += 1; + + // dest.ptr[out_index] = encoder.pad_char; + // out_index += 1; + // } else { + // 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]; + // out_index += 1; + // } + + // dest.ptr[out_index] = encoder.pad_char; + // out_index += 1; + //} +} + +// Called before init() +static bool build_with_cache(CodeGen *g) { + blake2b_state blake; + int rc = blake2b_init(&blake, 48); + assert(rc == 0); + + // TODO zig exe & dynamic libraries + + add_cache_buf(&blake, g->root_out_name); + add_cache_buf_opt(&blake, get_resolved_root_src_path(g)); // Root source file + add_cache_list_of_link_lib(&blake, g->link_libs_list.items, g->link_libs_list.length); + add_cache_list_of_buf(&blake, g->darwin_frameworks.items, g->darwin_frameworks.length); + add_cache_list_of_buf(&blake, g->rpath_list.items, g->rpath_list.length); + add_cache_int(&blake, g->emit_file_type); + add_cache_int(&blake, g->build_mode); + add_cache_int(&blake, g->out_type); + // TODO the rest of the struct CodeGen fields + + uint8_t bin_digest[48]; + rc = blake2b_final(&blake, bin_digest, 48); + assert(rc == 0); + + Buf b64_digest = BUF_INIT; + buf_resize(&b64_digest, 64); + base64_encode(buf_to_slice(&b64_digest), {bin_digest, 48}); + + fprintf(stderr, "input params hash: %s\n", buf_ptr(&b64_digest)); + // TODO next look for a manifest file that has all the files from the input parameters + // use that to construct the real hash, which looks up the output directory and another manifest file + + return false; +} + void codegen_build(CodeGen *g) { assert(g->out_type != OutTypeUnknown); + if (build_with_cache(g)) + return; init(g); + codegen_add_time_event(g, "Semantic Analysis"); + gen_global_asm(g); gen_root_source(g); do_code_gen(g); -- cgit v1.2.3 From b4d5d4d1748d25efa6197914a36e276e93509f57 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 5 Sep 2018 23:39:14 -0400 Subject: assume evenly divided base64 --- src/codegen.cpp | 21 --------------------- 1 file changed, 21 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index e258f8d609..f4823f1048 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -7760,27 +7760,6 @@ static void base64_encode(Slice dest, Slice source) { // Assert that we never need pad characters. assert(i == source.len); - //if (i < source.len) { - // dest.ptr[out_index] = base64_fs_alphabet[(source.ptr[i] >> 2) & 0x3f]; - // out_index += 1; - - // if (i + 1 == source.len) { - // dest.ptr[out_index] = base64_fs_alphabet[(source.ptr[i] & 0x3) << 4]; - // out_index += 1; - - // dest.ptr[out_index] = encoder.pad_char; - // out_index += 1; - // } else { - // 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]; - // out_index += 1; - // } - - // dest.ptr[out_index] = encoder.pad_char; - // out_index += 1; - //} } // Called before init() -- cgit v1.2.3 From 173fc842c4eb1da6ca07a4ab6026c4c62bc8c09b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 9 Sep 2018 18:07:11 -0400 Subject: basic compiler id hash working --- CMakeLists.txt | 1 + src/buffer.hpp | 4 + src/cache_hash.cpp | 407 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/cache_hash.hpp | 56 ++++++++ src/codegen.cpp | 152 +++++--------------- src/error.cpp | 2 + src/error.hpp | 2 + src/main.cpp | 61 ++++++++ src/os.cpp | 314 +++++++++++++++++++++++++++++++---------- src/os.hpp | 92 +++++++----- src/util.cpp | 39 +++++ src/util.hpp | 12 ++ 12 files changed, 918 insertions(+), 224 deletions(-) create mode 100644 src/cache_hash.cpp create mode 100644 src/cache_hash.hpp (limited to 'src/codegen.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index fbf5b03eac..615128159f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -409,6 +409,7 @@ set(ZIG_SOURCES "${CMAKE_SOURCE_DIR}/src/bigint.cpp" "${CMAKE_SOURCE_DIR}/src/blake2b.cpp" "${CMAKE_SOURCE_DIR}/src/buffer.cpp" + "${CMAKE_SOURCE_DIR}/src/cache_hash.cpp" "${CMAKE_SOURCE_DIR}/src/c_tokenizer.cpp" "${CMAKE_SOURCE_DIR}/src/codegen.cpp" "${CMAKE_SOURCE_DIR}/src/errmsg.cpp" diff --git a/src/buffer.hpp b/src/buffer.hpp index 501e44b5ac..8155df87a1 100644 --- a/src/buffer.hpp +++ b/src/buffer.hpp @@ -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 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)); } diff --git a/src/cache_hash.cpp b/src/cache_hash.cpp new file mode 100644 index 0000000000..5447a5f3f2 --- /dev/null +++ b/src/cache_hash.cpp @@ -0,0 +1,407 @@ +/* + * 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 "buffer.hpp" +#include "os.hpp" + +#include + +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_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_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 dest, Slice 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 dest, Slice 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) { + Error err; + + 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); + } +} + +static Error populate_file_hash(CacheHash *ch, CacheHashFile *chf) { + 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))) { + 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); + + 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_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> 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> 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> 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> 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; + } + + Optional> opt_file_path = SplitIterator_next(&it); + if (!opt_file_path.is_some) { + os_file_close(ch->manifest_file); + return ErrorInvalidFormat; + } + Buf *this_path = buf_create_from_slice(opt_file_path.value); + 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))) { + 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))) { + os_file_close(ch->manifest_file); + return err; + } + } + return ErrorNone; + } + // Cache Hit + return cache_final(ch, out_digest); +} + +Error cache_add_file(CacheHash *ch, Buf *path) { + Error err; + + assert(ch->manifest_file_path != nullptr); + CacheHashFile *chf = ch->files.add_one(); + chf->path = path; + if ((err = populate_file_hash(ch, chf))) { + os_file_close(ch->manifest_file); + return err; + } + + return ErrorNone; +} + +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)); + } + fprintf(stderr, "overwrite with\n%s\n", buf_ptr(&contents)); + 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)); + } + } + os_file_close(ch->manifest_file); + + 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; +} diff --git a/src/cache_hash.hpp b/src/cache_hash.hpp new file mode 100644 index 0000000000..77b22a1e41 --- /dev/null +++ b/src/cache_hash.hpp @@ -0,0 +1,56 @@ +/* + * 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 "all_types.hpp" +#include "blake2.h" +#include "os.hpp" + +struct CacheHashFile { + Buf *path; + OsTimeStamp mtime; + uint8_t bin_digest[48]; +}; + +struct CacheHash { + blake2b_state blake; + ZigList 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_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_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 +Error ATTRIBUTE_MUST_USE cache_hit(CacheHash *ch, Buf *out_b64_digest); + +// If you got a cache hit, the flow is done. No more functions to call. +// Next call this function for every file that is depended on. +Error ATTRIBUTE_MUST_USE cache_add_file(CacheHash *ch, Buf *path); + +// If you did not get a cache hit, use the hash population functions again +// and do all the actual work. When done use cache_final to save the cache +// for next time. +Error ATTRIBUTE_MUST_USE cache_final(CacheHash *ch, Buf *out_digest); + +#endif diff --git a/src/codegen.cpp b/src/codegen.cpp index f4823f1048..6c5648f626 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -19,7 +19,6 @@ #include "target.hpp" #include "util.hpp" #include "zig_llvm.h" -#include "blake2.h" #include #include @@ -7675,130 +7674,45 @@ void codegen_add_time_event(CodeGen *g, const char *name) { g->timing_events.append({os_get_time(), name}); } -static void add_cache_str(blake2b_state *blake, const char *ptr) { - assert(ptr != nullptr); - // + 1 to include the null byte - blake2b_update(blake, ptr, strlen(ptr) + 1); -} - -static void add_cache_int(blake2b_state *blake, int x) { - // + 1 to include the null byte - uint8_t buf[sizeof(int) + 1]; - memcpy(buf, &x, sizeof(int)); - buf[sizeof(int)] = 0; - blake2b_update(blake, buf, sizeof(int) + 1); -} -static void add_cache_buf(blake2b_state *blake, Buf *buf) { - assert(buf != nullptr); - // + 1 to include the null byte - blake2b_update(blake, buf_ptr(buf), buf_len(buf) + 1); -} - -static void add_cache_buf_opt(blake2b_state *blake, Buf *buf) { - if (buf == nullptr) { - add_cache_str(blake, ""); - add_cache_str(blake, ""); - } else { - add_cache_buf(blake, buf); - } -} - -static void add_cache_list_of_link_lib(blake2b_state *blake, LinkLib **ptr, size_t len) { - for (size_t i = 0; i < len; i += 1) { - LinkLib *lib = ptr[i]; - if (lib->provided_explicitly) { - add_cache_buf(blake, lib->name); - } - } - add_cache_str(blake, ""); -} - -static void add_cache_list_of_buf(blake2b_state *blake, Buf **ptr, size_t len) { - for (size_t i = 0; i < len; i += 1) { - Buf *buf = ptr[i]; - add_cache_buf(blake, buf); - } - add_cache_str(blake, ""); -} - -//static void add_cache_file(CodeGen *g, blake2b_state *blake, Buf *resolved_path) { -// assert(file_name != nullptr); -// g->cache_files.append(resolved_path); -//} +//// Called before init() +//static bool build_with_cache(CodeGen *g) { +// // TODO zig exe & dynamic libraries +// // should be in main.cpp I think. only needs to happen +// // once on startup. +// +// CacheHash comp; +// cache_init(&comp); +// +// add_cache_buf(&blake, g->root_out_name); +// add_cache_buf_opt(&blake, get_resolved_root_src_path(g)); // Root source file +// add_cache_list_of_link_lib(&blake, g->link_libs_list.items, g->link_libs_list.length); +// add_cache_list_of_buf(&blake, g->darwin_frameworks.items, g->darwin_frameworks.length); +// add_cache_list_of_buf(&blake, g->rpath_list.items, g->rpath_list.length); +// add_cache_int(&blake, g->emit_file_type); +// add_cache_int(&blake, g->build_mode); +// add_cache_int(&blake, g->out_type); +// // TODO the rest of the struct CodeGen fields +// +// uint8_t bin_digest[48]; +// rc = blake2b_final(&blake, bin_digest, 48); +// assert(rc == 0); +// +// Buf b64_digest = BUF_INIT; +// buf_resize(&b64_digest, 64); +// base64_encode(buf_to_slice(&b64_digest), {bin_digest, 48}); // -//static void add_cache_file_opt(CodeGen *g, blake2b_state *blake, Buf *resolved_path) { -// if (resolved_path == nullptr) { -// add_cache_str(blake, ""); -// add_cache_str(blake, ""); -// } else { -// add_cache_file(g, blake, resolved_path); -// } +// fprintf(stderr, "input params hash: %s\n", buf_ptr(&b64_digest)); +// // TODO next look for a manifest file that has all the files from the input parameters +// // use that to construct the real hash, which looks up the output directory and another manifest file +// +// return false; //} -// Ported from std/base64.zig -static uint8_t base64_fs_alphabet[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"; -static void base64_encode(Slice dest, Slice 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); -} - -// Called before init() -static bool build_with_cache(CodeGen *g) { - blake2b_state blake; - int rc = blake2b_init(&blake, 48); - assert(rc == 0); - - // TODO zig exe & dynamic libraries - - add_cache_buf(&blake, g->root_out_name); - add_cache_buf_opt(&blake, get_resolved_root_src_path(g)); // Root source file - add_cache_list_of_link_lib(&blake, g->link_libs_list.items, g->link_libs_list.length); - add_cache_list_of_buf(&blake, g->darwin_frameworks.items, g->darwin_frameworks.length); - add_cache_list_of_buf(&blake, g->rpath_list.items, g->rpath_list.length); - add_cache_int(&blake, g->emit_file_type); - add_cache_int(&blake, g->build_mode); - add_cache_int(&blake, g->out_type); - // TODO the rest of the struct CodeGen fields - - uint8_t bin_digest[48]; - rc = blake2b_final(&blake, bin_digest, 48); - assert(rc == 0); - - Buf b64_digest = BUF_INIT; - buf_resize(&b64_digest, 64); - base64_encode(buf_to_slice(&b64_digest), {bin_digest, 48}); - - fprintf(stderr, "input params hash: %s\n", buf_ptr(&b64_digest)); - // TODO next look for a manifest file that has all the files from the input parameters - // use that to construct the real hash, which looks up the output directory and another manifest file - - return false; -} - void codegen_build(CodeGen *g) { assert(g->out_type != OutTypeUnknown); - if (build_with_cache(g)) - return; + //if (build_with_cache(g)) + // return; init(g); codegen_add_time_event(g, "Semantic Analysis"); diff --git a/src/error.cpp b/src/error.cpp index 8303a80a1d..d9da6e6c52 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -27,6 +27,8 @@ 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"; } return "(invalid error)"; } diff --git a/src/error.hpp b/src/error.hpp index e3b87fc6b8..c99c6e6b12 100644 --- a/src/error.hpp +++ b/src/error.hpp @@ -27,6 +27,8 @@ enum Error { ErrorNegativeDenominator, ErrorShiftedOutOneBits, ErrorCCompileErrors, + ErrorEndOfFile, + ErrorIsDir, }; const char *err_str(int err); diff --git a/src/main.cpp b/src/main.cpp index eed31438d9..172fe04da9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,6 +13,7 @@ #include "link.hpp" #include "os.hpp" #include "target.hpp" +#include "cache_hash.hpp" #include @@ -270,6 +271,66 @@ int main(int argc, char **argv) { return 0; } + if (argc == 2 && strcmp(argv[1], "TEST") == 0) { + Error err; + Buf app_data_dir = BUF_INIT; + if ((err = os_get_app_data_dir(&app_data_dir, "zig"))) { + fprintf(stderr, "get app dir: %s\n", err_str(err)); + return 1; + } + Buf *stage1_dir = buf_alloc(); + os_path_join(&app_data_dir, buf_create_from_str("stage1"), stage1_dir); + Buf *manifest_dir = buf_alloc(); + os_path_join(stage1_dir, buf_create_from_str("exe"), manifest_dir); + + if ((err = os_make_path(manifest_dir))) { + fprintf(stderr, "make path: %s\n", err_str(err)); + return 1; + } + 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))) { + fprintf(stderr, "self exe path: %s\n", err_str(err)); + return 1; + } + + cache_file(ch, &self_exe_path); + + Buf exe_digest = BUF_INIT; + buf_resize(&exe_digest, 0); + if ((err = cache_hit(ch, &exe_digest))) { + fprintf(stderr, "cache hit error: %s\n", err_str(err)); + return 1; + } + if (buf_len(&exe_digest) != 0) { + fprintf(stderr, "cache hit: %s\n", buf_ptr(&exe_digest)); + return 0; + } + fprintf(stderr, "cache miss\n"); + ZigList lib_paths = {}; + if ((err = os_self_exe_shared_libs(lib_paths))) { + fprintf(stderr, "finding out shared libs: %s\n", err_str(err)); + return 1; + } + 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))) { + fprintf(stderr, "cache add file %s: %s", buf_ptr(lib_path), err_str(err)); + return 1; + } + } + if ((err = cache_final(ch, &exe_digest))) { + fprintf(stderr, "final: %s\n", err_str(err)); + return 1; + } + + + fprintf(stderr, "computed2: %s\n", buf_ptr(&exe_digest)); + return 0; + } + os_init(); char *arg0 = argv[0]; diff --git a/src/os.cpp b/src/os.cpp index 0e62d84a48..d6e17ca5a1 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -40,6 +40,10 @@ typedef SSIZE_T ssize_t; #endif +#if defined(ZIG_OS_LINUX) +#include +#endif + #if defined(__MACH__) #include @@ -57,54 +61,6 @@ static clock_serv_t cclock; #include #include -// Ported from std/mem.zig. -// Coordinate struct fields with memSplit function -struct SplitIterator { - size_t index; - Slice buffer; - Slice 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> 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>::some(self->buffer.slice(start, end)); -} - -// Ported from std/mem.zig -static SplitIterator memSplit(Slice buffer, Slice split_bytes) { - return SplitIterator{0, buffer, split_bytes}; -} - - #if defined(ZIG_OS_POSIX) static void populate_termination(Termination *term, int status) { if (WIFEXITED(status)) { @@ -1368,16 +1324,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 +1347,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 +1355,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 +1369,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 +1380,7 @@ int os_make_dir(Buf *path) { return ErrorAccess; return ErrorUnexpected; } - return 0; + return ErrorNone; #endif } @@ -1447,7 +1403,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 (;;) { @@ -1480,27 +1436,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 +1635,225 @@ int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchTy return ErrorFileNotFound; #endif } + +// Ported from std/os/get_app_data_dir.zig +Error os_get_app_data_dir(Buf *out_path, const char *appname) { +#if defined(ZIG_OS_WINDOWS) +#error "Unimplemented" +#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 *libs = reinterpret_cast< ZigList *>(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 &paths) { +#if defined(ZIG_OS_LINUX) + paths.resize(0); + dl_iterate_phdr(self_exe_shared_libs_callback, &paths); + return ErrorNone; +#else +#error "unimplemented" +#endif +} + +Error os_file_open_r(Buf *full_path, OsFile *out_file) { +#if defined(ZIG_OS_WINDOWS) +#error "unimplemented" +#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) +#error "unimplemented" +#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) +#error unimplemented +#else + 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; +#endif +} + +Error os_file_read(OsFile file, void *ptr, size_t *len) { +#if defined(ZIG_OS_WINDOWS) +#error unimplemented +#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 < 512) { + buf_resize(contents, buf_len(contents) + 512); + amt += 512; + } + + 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) +#error unimplemented +#else + if (lseek(file, 0, SEEK_SET) == -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) { + close(file); +} diff --git a/src/os.hpp b/src/os.hpp index a44fa8160e..c64eccf8d4 100644 --- a/src/os.hpp +++ b/src/os.hpp @@ -13,10 +13,43 @@ #include "error.hpp" #include "zig_llvm.h" #include "windows_sdk.h" +#include "result.hpp" #include #include +#if defined(__APPLE__) +#define ZIG_OS_DARWIN +#elif defined(_WIN32) +#define ZIG_OS_WINDOWS +#elif defined(__linux__) +#define ZIG_OS_LINUX +#else +#define ZIG_OS_UNKNOWN +#endif + +#if defined(__x86_64__) +#define ZIG_ARCH_X86_64 +#else +#define ZIG_ARCH_UNKNOWN +#endif + +#if defined(ZIG_OS_WINDOWS) +#define ZIG_PRI_usize "I64u" +#define ZIG_PRI_u64 "I64u" +#define ZIG_PRI_llu "I64u" +#define ZIG_PRI_x64 "I64x" +#define OS_SEP "\\" +#define ZIG_OS_SEP_CHAR '\\' +#else +#define ZIG_PRI_usize "zu" +#define ZIG_PRI_u64 PRIu64 +#define ZIG_PRI_llu "llu" +#define ZIG_PRI_x64 PRIx64 +#define OS_SEP "/" +#define ZIG_OS_SEP_CHAR '/' +#endif + enum TermColor { TermColorRed, TermColorGreen, @@ -38,6 +71,17 @@ struct Termination { 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 &args, Termination *term); @@ -54,8 +98,16 @@ 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); +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); @@ -78,42 +130,14 @@ double os_get_time(void); bool os_is_sep(uint8_t c); -int os_self_exe_path(Buf *out_path); +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); -#if defined(__APPLE__) -#define ZIG_OS_DARWIN -#elif defined(_WIN32) -#define ZIG_OS_WINDOWS -#elif defined(__linux__) -#define ZIG_OS_LINUX -#else -#define ZIG_OS_UNKNOWN -#endif - -#if defined(__x86_64__) -#define ZIG_ARCH_X86_64 -#else -#define ZIG_ARCH_UNKNOWN -#endif - -#if defined(ZIG_OS_WINDOWS) -#define ZIG_PRI_usize "I64u" -#define ZIG_PRI_u64 "I64u" -#define ZIG_PRI_llu "I64u" -#define ZIG_PRI_x64 "I64x" -#define OS_SEP "\\" -#define ZIG_OS_SEP_CHAR '\\' -#else -#define ZIG_PRI_usize "zu" -#define ZIG_PRI_u64 PRIu64 -#define ZIG_PRI_llu "llu" -#define ZIG_PRI_x64 PRIx64 -#define OS_SEP "/" -#define ZIG_OS_SEP_CHAR '/' -#endif +Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList &paths); #endif diff --git a/src/util.cpp b/src/util.cpp index cafd2c3d85..060d7f8fb5 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -43,3 +43,42 @@ 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> 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>::some(self->buffer.slice(start, end)); +} + +// Ported from std/mem.zig +SplitIterator memSplit(Slice buffer, Slice split_bytes) { + return SplitIterator{0, buffer, split_bytes}; +} diff --git a/src/util.hpp b/src/util.hpp index 1e02e3043c..f18c369fb5 100644 --- a/src/util.hpp +++ b/src/util.hpp @@ -254,4 +254,16 @@ static inline void memCopy(Slice dest, Slice 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 buffer; + Slice split_bytes; +}; + +bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte); +Optional> SplitIterator_next(SplitIterator *self); +SplitIterator memSplit(Slice buffer, Slice split_bytes); + #endif -- cgit v1.2.3 From fbe5737c84c783cd31e6e2d595fc47eb782c5e3c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Sep 2018 09:46:15 -0400 Subject: stage1: always optimize blake and softfloat even in debug mode --- CMakeLists.txt | 14 +++++++-- src/all_types.hpp | 4 +++ src/cache_hash.cpp | 4 +++ src/cache_hash.hpp | 3 +- src/codegen.cpp | 91 +++++++++++++++++++++++++++++++++--------------------- src/codegen.hpp | 2 +- src/link.cpp | 2 +- src/main.cpp | 21 ++++++++++--- 8 files changed, 94 insertions(+), 47 deletions(-) (limited to 'src/codegen.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index 615128159f..8339be71b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -390,7 +390,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 @@ -407,10 +407,9 @@ set(ZIG_SOURCES "${CMAKE_SOURCE_DIR}/src/ast_render.cpp" "${CMAKE_SOURCE_DIR}/src/bigfloat.cpp" "${CMAKE_SOURCE_DIR}/src/bigint.cpp" - "${CMAKE_SOURCE_DIR}/src/blake2b.cpp" "${CMAKE_SOURCE_DIR}/src/buffer.cpp" - "${CMAKE_SOURCE_DIR}/src/cache_hash.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/errmsg.cpp" "${CMAKE_SOURCE_DIR}/src/error.cpp" @@ -426,6 +425,9 @@ set(ZIG_SOURCES "${CMAKE_SOURCE_DIR}/src/util.cpp" "${CMAKE_SOURCE_DIR}/src/translate_c.cpp" ) +set(ZIG_SOURCES_O3 + "${CMAKE_SOURCE_DIR}/src/blake2b.cpp" +) set(ZIG_CPP_SOURCES "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" "${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp" @@ -813,6 +815,11 @@ set_target_properties(zig_cpp PROPERTIES COMPILE_FLAGS ${EXE_CFLAGS} ) +add_library(zig_O3 STATIC ${ZIG_SOURCES_O3}) +set_target_properties(zig_O3 PROPERTIES + COMPILE_FLAGS "${EXE_CFLAGS} -O3" +) + add_executable(zig ${ZIG_SOURCES}) set_target_properties(zig PROPERTIES COMPILE_FLAGS ${EXE_CFLAGS} @@ -821,6 +828,7 @@ set_target_properties(zig PROPERTIES target_link_libraries(zig LINK_PUBLIC zig_cpp + zig_O3 ${SOFTFLOAT_LIBRARIES} ${CLANG_LIBRARIES} ${LLD_LIBRARIES} diff --git a/src/all_types.hpp b/src/all_types.hpp index 0b0de58791..2dfbcaaa62 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -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" @@ -1613,7 +1614,10 @@ struct CodeGen { ZigType *entry_promise; } builtin_types; + CacheHash cache_hash; + //////////////////////////// Participates in Input Parameter Cache Hash + Buf *compiler_id; ZigList link_libs_list; // add -framework [name] args to linker ZigList darwin_frameworks; diff --git a/src/cache_hash.cpp b/src/cache_hash.cpp index ff530ca65c..a0c43bc810 100644 --- a/src/cache_hash.cpp +++ b/src/cache_hash.cpp @@ -6,6 +6,7 @@ */ #include "cache_hash.hpp" +#include "all_types.hpp" #include "buffer.hpp" #include "os.hpp" @@ -219,6 +220,9 @@ Error cache_hit(CacheHash *ch, Buf *out_digest) { 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; diff --git a/src/cache_hash.hpp b/src/cache_hash.hpp index 77b22a1e41..3c2d77abc0 100644 --- a/src/cache_hash.hpp +++ b/src/cache_hash.hpp @@ -8,10 +8,11 @@ #ifndef ZIG_CACHE_HASH_HPP #define ZIG_CACHE_HASH_HPP -#include "all_types.hpp" #include "blake2.h" #include "os.hpp" +struct LinkLib; + struct CacheHashFile { Buf *path; OsTimeStamp mtime; diff --git a/src/codegen.cpp b/src/codegen.cpp index 6c5648f626..a18b26bb18 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -88,12 +88,13 @@ static const char *symbols_that_llvm_depends_on[] = { }; CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode, - Buf *zig_lib_dir) + Buf *zig_lib_dir, Buf *compiler_id) { CodeGen *g = allocate(1); codegen_add_time_event(g, "Initialize"); + g->compiler_id = compiler_id; g->zig_lib_dir = zig_lib_dir; g->zig_std_dir = buf_alloc(); @@ -7675,44 +7676,62 @@ void codegen_add_time_event(CodeGen *g, const char *name) { } -//// Called before init() -//static bool build_with_cache(CodeGen *g) { -// // TODO zig exe & dynamic libraries -// // should be in main.cpp I think. only needs to happen -// // once on startup. -// -// CacheHash comp; -// cache_init(&comp); -// -// add_cache_buf(&blake, g->root_out_name); -// add_cache_buf_opt(&blake, get_resolved_root_src_path(g)); // Root source file -// add_cache_list_of_link_lib(&blake, g->link_libs_list.items, g->link_libs_list.length); -// add_cache_list_of_buf(&blake, g->darwin_frameworks.items, g->darwin_frameworks.length); -// add_cache_list_of_buf(&blake, g->rpath_list.items, g->rpath_list.length); -// add_cache_int(&blake, g->emit_file_type); -// add_cache_int(&blake, g->build_mode); -// add_cache_int(&blake, g->out_type); -// // TODO the rest of the struct CodeGen fields -// -// uint8_t bin_digest[48]; -// rc = blake2b_final(&blake, bin_digest, 48); -// assert(rc == 0); -// -// Buf b64_digest = BUF_INIT; -// buf_resize(&b64_digest, 64); -// base64_encode(buf_to_slice(&b64_digest), {bin_digest, 48}); -// -// fprintf(stderr, "input params hash: %s\n", buf_ptr(&b64_digest)); -// // TODO next look for a manifest file that has all the files from the input parameters -// // use that to construct the real hash, which looks up the output directory and another manifest file -// -// return false; -//} +// Called before init() +static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { + Error err; + + CacheHash *ch = &g->cache_hash; + cache_init(ch, manifest_dir); + + cache_buf(ch, g->compiler_id); + cache_buf(ch, g->root_out_name); + cache_file(ch, get_resolved_root_src_path(g)); // Root source file + 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_int(ch, g->emit_file_type); + cache_int(ch, g->build_mode); + cache_int(ch, g->out_type); + // TODO the rest of the struct CodeGen fields + + buf_resize(digest, 0); + if ((err = cache_hit(ch, digest))) + return err; + + return ErrorNone; +} void codegen_build(CodeGen *g) { + Error err; assert(g->out_type != OutTypeUnknown); - //if (build_with_cache(g)) - // return; + + Buf app_data_dir = BUF_INIT; + if ((err = os_get_app_data_dir(&app_data_dir, "zig"))) { + fprintf(stderr, "Unable to get app data dir: %s\n", err_str(err)); + exit(1); + } + Buf *stage1_dir = buf_alloc(); + os_path_join(&app_data_dir, buf_create_from_str("stage1"), stage1_dir); + + Buf *manifest_dir = buf_alloc(); + os_path_join(stage1_dir, buf_create_from_str("build"), manifest_dir); + + Buf digest = BUF_INIT; + if ((err = check_cache(g, manifest_dir, &digest))) { + fprintf(stderr, "Unable to check cache: %s\n", err_str(err)); + exit(1); + } + if (buf_len(&digest) != 0) { + Buf *artifact_dir = buf_alloc(); + os_path_join(stage1_dir, buf_create_from_str("artifact"), artifact_dir); + + Buf *this_artifact_dir = buf_alloc(); + os_path_join(artifact_dir, &digest, this_artifact_dir); + + fprintf(stderr, "copy artifacts from %s\n", buf_ptr(this_artifact_dir)); + return; + } + init(g); codegen_add_time_event(g, "Semantic Analysis"); diff --git a/src/codegen.hpp b/src/codegen.hpp index 55b38a0050..649cf06856 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -15,7 +15,7 @@ #include CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode, - Buf *zig_lib_dir); + Buf *zig_lib_dir, Buf *compiler_id); 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); diff --git a/src/link.cpp b/src/link.cpp index 78ad204fe9..c0eb25bd55 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -34,7 +34,7 @@ static const char *get_libc_static_file(CodeGen *g, const char *file) { static Buf *build_o_raw(CodeGen *parent_gen, const char *oname, Buf *full_path) { ZigTarget *child_target = parent_gen->is_native_target ? nullptr : &parent_gen->zig_target; CodeGen *child_gen = codegen_create(full_path, child_target, OutTypeObj, parent_gen->build_mode, - parent_gen->zig_lib_dir); + parent_gen->zig_lib_dir, parent_gen->compiler_id); child_gen->want_h_file = false; child_gen->verbose_tokenize = parent_gen->verbose_tokenize; diff --git a/src/main.cpp b/src/main.cpp index c385a1c88e..1520ae7d67 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -274,8 +274,6 @@ static Error get_compiler_id(Buf **result) { Buf *manifest_dir = buf_alloc(); os_path_join(stage1_dir, buf_create_from_str("exe"), manifest_dir); - if ((err = os_make_path(manifest_dir))) - return err; CacheHash cache_hash; CacheHash *ch = &cache_hash; cache_init(ch, manifest_dir); @@ -432,8 +430,14 @@ 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); + 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; + } - CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, zig_lib_dir_buf); + CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, zig_lib_dir_buf, + compiler_id); codegen_set_out_name(g, buf_create_from_str("build")); Buf *build_file_buf = buf_create_from_str(build_file); @@ -796,7 +800,7 @@ int main(int argc, char **argv) { switch (cmd) { case CmdBuiltin: { Buf *zig_lib_dir_buf = resolve_zig_lib_dir(); - CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, zig_lib_dir_buf); + CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, zig_lib_dir_buf, nullptr); Buf *builtin_source = codegen_generate_builtin_source(g); if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) { fprintf(stderr, "unable to write to stdout: %s\n", strerror(ferror(stdout))); @@ -871,7 +875,14 @@ int main(int argc, char **argv) { 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); + 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; + } + + CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, zig_lib_dir_buf, + compiler_id); 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); -- cgit v1.2.3 From 32be6e9b2a9e6de501aadbe271c554a4682a10f8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Sep 2018 13:46:23 -0400 Subject: caching is working * add almost all the input parameter state to the hash - missing items are the detected MSVC installation on Windows and detected libc installation on POSIX - also missing are C files and .h files that libclang finds * artifacts are created in global cache directory instead of zig-cache. - exception: builtin.zig is still in zig-cache * zig run uses the new cache correctly * zig run uses execv on posix systems --- src/all_types.hpp | 265 ++++++++++++++++++++++++++--------------------------- src/cache_hash.cpp | 70 ++++++++++++-- src/cache_hash.hpp | 27 ++++-- src/codegen.cpp | 197 +++++++++++++++++++++++++++------------ src/codegen.hpp | 4 +- src/error.cpp | 1 + src/error.hpp | 1 + src/ir.cpp | 11 +-- src/link.cpp | 74 ++++----------- src/link.hpp | 17 ---- src/main.cpp | 64 ++++++------- src/os.cpp | 54 ++++------- src/os.hpp | 3 +- 13 files changed, 418 insertions(+), 370 deletions(-) delete mode 100644 src/link.hpp (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 2dfbcaaa62..6d11244a25 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1554,6 +1554,40 @@ struct CodeGen { ZigLLVMDICompileUnit *compile_unit; ZigLLVMDIFile *compile_unit_file; LinkLib *libc_link_lib; + 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 import_table; @@ -1576,8 +1610,23 @@ struct CodeGen { size_t resolve_queue_index; ZigList use_queue; size_t use_queue_index; + ZigList timing_events; + ZigList error_di_types; + ZigList tld_ref_source_node_stack; + ZigList inline_fns; + ZigList test_fns; + ZigList err_enumerators; + ZigList 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; @@ -1613,30 +1662,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; - CacheHash cache_hash; + Buf triple_str; + Buf global_asm; + Buf *out_h_path; + Buf cache_dir; + Buf artifact_dir; + Buf output_file_path; + Buf o_file_output_path; + Buf *wanted_output_file_path; - //////////////////////////// Participates in Input Parameter Cache Hash - Buf *compiler_id; - ZigList link_libs_list; - // add -framework [name] args to linker - ZigList darwin_frameworks; - // add -rpath [name] args to linker - ZigList rpath_list; + IrInstruction *invalid_instruction; - EmitFileType emit_file_type; - BuildMode build_mode; - OutType out_type; + ConstExprValue const_void_val; + ConstExprValue panic_msg_vals[PanicMsgIdCount]; + // The function definitions this module includes. + ZigList fn_defs; + size_t fn_defs_index; + ZigList global_vars; - //////////////////////////// Unsorted + ZigFn *cur_fn; + ZigFn *main_fn; + ZigFn *panic_fn; + AstNode *root_export_decl; - ZigTarget zig_target; - LLVMTargetDataRef target_data_ref; + 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; @@ -1644,148 +1708,75 @@ struct CodeGen { bool have_winmain_crt_startup; bool have_dllmain_crt_startup; bool have_pub_panic; - Buf *libc_lib_dir; - Buf *libc_static_lib_dir; - Buf *libc_include_dir; - Buf *msvc_lib_dir; - Buf *kernel32_lib_dir; - Buf *zig_lib_dir; - Buf *zig_std_dir; - Buf *zig_c_headers_dir; - Buf *zig_std_special_dir; - Buf *dynamic_linker; - Buf *ar_path; - ZigWindowsSDK *win_sdk; - Buf triple_str; - 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; // participates in cache hash - PackageTableEntry *std_package; - PackageTableEntry *panic_package; - PackageTableEntry *test_runner_package; - PackageTableEntry *compile_var_package; - ImportTableEntry *compile_var_import; - Buf *root_out_name; // participates in cache hash - 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 fn_defs; - size_t fn_defs_index; - ZigList global_vars; - - 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 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; bool error_during_imports; + bool generate_error_name_table; - LLVMValueRef sp_md_node; - - const char **clang_argv; - size_t clang_argv_len; + //////////////////////////// Participates in Input Parameter Cache Hash + ZigList link_libs_list; + // add -framework [name] args to linker + ZigList darwin_frameworks; + // add -rpath [name] args to linker + ZigList rpath_list; + ZigList forbidden_libs; + ZigList link_objects; + ZigList assembly_files; ZigList lib_dirs; - const char **llvm_argv; - size_t llvm_argv_len; - - ZigList test_fns; - ZigType *test_fn_type; + Buf *compiler_id; + 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; - ZigType *err_tag_type; - ZigList err_enumerators; - ZigList 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 link_objects; - ZigList assembly_files; - + Buf *mmacosx_version_min; + Buf *mios_version_min; + Buf *root_out_name; Buf *test_filter; Buf *test_name_prefix; + PackageTableEntry *root_package; - ZigList timing_events; - - Buf cache_dir; - Buf *out_h_path; - - ZigList inline_fns; - ZigList tld_ref_source_node_stack; - - ZigType *align_amt_type; - ZigType *stack_trace_type; - ZigType *ptr_to_stack_trace_type; + const char **llvm_argv; + size_t llvm_argv_len; - ZigList error_di_types; + const char **clang_argv; + size_t clang_argv_len; - ZigList forbidden_libs; + //////////////////////////// Unsorted - bool no_rosegment_workaround; + Buf *libc_lib_dir; + Buf *libc_static_lib_dir; + Buf *libc_include_dir; + Buf *msvc_lib_dir; + Buf *kernel32_lib_dir; + Buf *zig_lib_dir; + Buf *zig_std_dir; + Buf *zig_c_headers_dir; + Buf *zig_std_special_dir; + Buf *dynamic_linker; + ZigWindowsSDK *win_sdk; }; enum VarLinkage { diff --git a/src/cache_hash.cpp b/src/cache_hash.cpp index a0c43bc810..b6aebdac67 100644 --- a/src/cache_hash.cpp +++ b/src/cache_hash.cpp @@ -37,6 +37,20 @@ void cache_int(CacheHash *ch, int x) { 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); @@ -74,6 +88,26 @@ void cache_list_of_buf(CacheHash *ch, Buf **ptr, size_t len) { 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); @@ -154,9 +188,13 @@ static Error base64_decode(Slice dest, Slice source) { return ErrorNone; } -static Error hash_file(uint8_t *digest, OsFile handle) { +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); @@ -172,10 +210,13 @@ static Error hash_file(uint8_t *digest, OsFile handle) { 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) { +static Error populate_file_hash(CacheHash *ch, CacheHashFile *chf, Buf *contents) { Error err; assert(chf->path != nullptr); @@ -189,7 +230,7 @@ static Error populate_file_hash(CacheHash *ch, CacheHashFile *chf) { return err; } - if ((err = hash_file(chf->bin_digest, this_file))) { + if ((err = hash_file(chf->bin_digest, this_file, contents))) { os_file_close(this_file); return err; } @@ -323,7 +364,7 @@ Error cache_hit(CacheHash *ch, Buf *out_digest) { chf->mtime = actual_mtime; uint8_t actual_digest[48]; - if ((err = hash_file(actual_digest, this_file))) { + if ((err = hash_file(actual_digest, this_file, nullptr))) { os_file_close(this_file); os_file_close(ch->manifest_file); return err; @@ -344,7 +385,7 @@ Error cache_hit(CacheHash *ch, Buf *out_digest) { 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))) { + if ((err = populate_file_hash(ch, chf, nullptr))) { os_file_close(ch->manifest_file); return err; } @@ -355,13 +396,13 @@ Error cache_hit(CacheHash *ch, Buf *out_digest) { return cache_final(ch, out_digest); } -Error cache_add_file(CacheHash *ch, Buf *path) { +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 = path; - if ((err = populate_file_hash(ch, chf))) { + chf->path = resolved_path; + if ((err = populate_file_hash(ch, chf, contents))) { os_file_close(ch->manifest_file); return err; } @@ -369,6 +410,12 @@ Error cache_add_file(CacheHash *ch, Buf *path) { 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; @@ -398,7 +445,8 @@ Error cache_final(CacheHash *ch, Buf *out_digest) { buf_ptr(ch->manifest_file_path), err_str(err)); } } - os_file_close(ch->manifest_file); + // 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); @@ -408,3 +456,7 @@ Error cache_final(CacheHash *ch, Buf *out_digest) { return ErrorNone; } + +void cache_release(CacheHash *ch) { + os_file_close(ch->manifest_file); +} diff --git a/src/cache_hash.hpp b/src/cache_hash.hpp index 3c2d77abc0..ede7344c75 100644 --- a/src/cache_hash.hpp +++ b/src/cache_hash.hpp @@ -17,6 +17,7 @@ struct CacheHashFile { Buf *path; OsTimeStamp mtime; uint8_t bin_digest[48]; + Buf *contents; }; struct CacheHash { @@ -34,24 +35,36 @@ 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 +// 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 got a cache hit, the flow is done. No more functions to call. -// Next call this function for every file that is depended on. +// 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); -// If you did not get a cache hit, use the hash population functions again -// and do all the actual work. When done use cache_final to save the cache -// for next time. -Error ATTRIBUTE_MUST_USE cache_final(CacheHash *ch, Buf *out_digest); +// 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 diff --git a/src/codegen.cpp b/src/codegen.cpp index a18b26bb18..1f53bb4c9d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -13,7 +13,6 @@ #include "error.hpp" #include "hash_map.hpp" #include "ir.hpp" -#include "link.hpp" #include "os.hpp" #include "translate_c.hpp" #include "target.hpp" @@ -188,6 +187,10 @@ 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; @@ -5756,8 +5759,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); @@ -6068,38 +6069,10 @@ static void do_code_gen(CodeGen *g) { 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); - 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), @@ -6118,7 +6091,6 @@ static void do_code_gen(CodeGen *g) { 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: @@ -6128,7 +6100,6 @@ static void do_code_gen(CodeGen *g) { 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: @@ -7035,8 +7006,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 = cache_add_file_fetch(&g->cache_hash, resolved_path, import_code))) { zig_panic("unable to open '%s': %s\n", buf_ptr(&path_to_code_src), err_str(err)); } @@ -7131,6 +7102,8 @@ static void gen_root_source(CodeGen *g) { Buf *source_code = buf_alloc(); int 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); @@ -7197,6 +7170,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)); } @@ -7460,14 +7435,9 @@ 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) { @@ -7675,6 +7645,24 @@ void codegen_add_time_event(CodeGen *g, const char *name) { g->timing_events.append({os_get_time(), name}); } +static void add_cache_pkg(CodeGen *g, CacheHash *ch, PackageTableEntry *pkg) { + if (buf_len(&pkg->root_src_path) == 0) + return; + + 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) { @@ -7683,16 +7671,46 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { 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, g->compiler_id); cache_buf(ch, g->root_out_name); - cache_file(ch, get_resolved_root_src_path(g)); // Root source file 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); - // TODO the rest of the struct CodeGen fields + 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))) @@ -7701,10 +7719,53 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { return ErrorNone; } -void codegen_build(CodeGen *g) { +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(); + } + + os_path_join(&g->artifact_dir, o_basename, &g->o_file_output_path); + + if (g->out_type == OutTypeObj) { + buf_init_from_buf(&g->output_file_path, &g->o_file_output_path); + } else if (g->out_type == OutTypeExe) { + 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)); + os_path_join(&g->artifact_dir, &basename, &g->output_file_path); + } +} + + +void codegen_build_and_link(CodeGen *g) { Error err; assert(g->out_type != OutTypeUnknown); + codegen_add_time_event(g, "Check Cache"); + Buf app_data_dir = BUF_INIT; if ((err = os_get_app_data_dir(&app_data_dir, "zig"))) { fprintf(stderr, "Unable to get app data dir: %s\n", err_str(err)); @@ -7721,25 +7782,45 @@ void codegen_build(CodeGen *g) { fprintf(stderr, "Unable to check cache: %s\n", err_str(err)); exit(1); } + + Buf *artifact_dir = buf_alloc(); + os_path_join(stage1_dir, buf_create_from_str("artifact"), artifact_dir); + if (buf_len(&digest) != 0) { - Buf *artifact_dir = buf_alloc(); - os_path_join(stage1_dir, buf_create_from_str("artifact"), artifact_dir); + os_path_join(artifact_dir, &digest, &g->artifact_dir); + resolve_out_paths(g); + } else { + init(g); - Buf *this_artifact_dir = buf_alloc(); - os_path_join(artifact_dir, &digest, this_artifact_dir); + codegen_add_time_event(g, "Semantic Analysis"); - fprintf(stderr, "copy artifacts from %s\n", buf_ptr(this_artifact_dir)); - return; - } + gen_global_asm(g); + gen_root_source(g); - init(g); + 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); + 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, "Semantic Analysis"); + codegen_add_time_event(g, "Code Generation"); + do_code_gen(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); + } + } + // TODO hard link output_file_path to wanted_output_file_path - gen_global_asm(g); - gen_root_source(g); - do_code_gen(g); - gen_h_file(g); + codegen_add_time_event(g, "Done"); } PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path) { diff --git a/src/codegen.hpp b/src/codegen.hpp index 649cf06856..1e7fafa28a 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -48,9 +48,11 @@ 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); diff --git a/src/error.cpp b/src/error.cpp index d9da6e6c52..d503eaa18b 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -29,6 +29,7 @@ const char *err_str(int err) { case ErrorCCompileErrors: return "C compile errors"; case ErrorEndOfFile: return "end of file"; case ErrorIsDir: return "is directory"; + case ErrorUnsupportedOperatingSystem: return "unsupported operating system"; } return "(invalid error)"; } diff --git a/src/error.hpp b/src/error.hpp index c99c6e6b12..8c1f8b9aa5 100644 --- a/src/error.hpp +++ b/src/error.hpp @@ -29,6 +29,7 @@ enum Error { ErrorCCompileErrors, ErrorEndOfFile, ErrorIsDir, + ErrorUnsupportedOperatingSystem, }; const char *err_str(int err); diff --git a/src/ir.cpp b/src/ir.cpp index 0269c29b1a..22d9a9bc49 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -16232,6 +16232,8 @@ static ZigType *ir_analyze_instruction_union_tag(IrAnalyze *ira, IrInstructionUn } static ZigType *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructionImport *import_instruction) { + Error err; + IrInstruction *name_value = import_instruction->name->other; Buf *import_target_str = ir_resolve_str(ira, name_value); if (!import_target_str) @@ -16275,8 +16277,7 @@ static ZigType *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructionImpor return ira->codegen->builtin_types.entry_namespace; } - int err; - if ((err = os_fetch_file_path(resolved_path, import_code, true))) { + if ((err = cache_add_file_fetch(&ira->codegen->cache_hash, resolved_path, import_code))) { if (err == ErrorFileNotFound) { ir_add_error_node(ira, source_node, buf_sprintf("unable to find '%s'", buf_ptr(import_target_path))); @@ -16287,6 +16288,7 @@ static ZigType *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructionImpor return ira->codegen->builtin_types.entry_invalid; } } + ImportTableEntry *target_import = add_source_file(ira->codegen, target_package, resolved_path, import_code); scan_import(ira->codegen, target_import); @@ -18106,7 +18108,7 @@ static ZigType *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstructionE // load from file system into const expr Buf *file_contents = buf_alloc(); int err; - if ((err = os_fetch_file_path(&file_path, file_contents, false))) { + if ((err = cache_add_file_fetch(&ira->codegen->cache_hash, &file_path, file_contents))) { if (err == ErrorFileNotFound) { ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path))); return ira->codegen->builtin_types.entry_invalid; @@ -18116,9 +18118,6 @@ static ZigType *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstructionE } } - // TODO add dependency on the file we embedded so that we know if it changes - // we'll have to invalidate the cache - ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); init_const_str_lit(ira->codegen, out_val, file_contents); diff --git a/src/link.cpp b/src/link.cpp index c0eb25bd55..8c250fbbe1 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -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 args; bool link_in_crt; HashMap rpath_table; @@ -62,14 +60,8 @@ 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)); - - return output_path; + codegen_build_and_link(child_gen); + return &child_gen->output_file_path; } static Buf *build_o(CodeGen *parent_gen, const char *oname) { @@ -237,15 +229,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; @@ -397,7 +389,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) { @@ -478,7 +470,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)))); @@ -585,11 +577,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"); @@ -797,8 +789,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); } } @@ -832,13 +824,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"); @@ -942,7 +934,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}; @@ -953,11 +946,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"); @@ -966,35 +954,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); @@ -1017,6 +979,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"); } diff --git a/src/link.hpp b/src/link.hpp deleted file mode 100644 index 9f978c28d9..0000000000 --- a/src/link.hpp +++ /dev/null @@ -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 - diff --git a/src/main.cpp b/src/main.cpp index 1520ae7d67..ff2c061a83 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,7 +10,6 @@ #include "codegen.hpp" #include "config.h" #include "error.hpp" -#include "link.hpp" #include "os.hpp" #include "target.hpp" #include "cache_hash.hpp" @@ -385,8 +384,7 @@ int main(int argc, char **argv) { CliPkg *cur_pkg = allocate(1); BuildMode build_mode = BuildModeDebug; ZigList 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) { @@ -454,8 +452,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); @@ -525,14 +521,13 @@ 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_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)); } @@ -541,15 +536,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; @@ -746,6 +737,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); @@ -856,19 +851,10 @@ 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 { + if (cmd == CmdRun && buf_out_name == nullptr) { + buf_out_name = buf_create_from_str("run"); + } + { 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); } @@ -957,6 +943,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)); @@ -976,8 +964,7 @@ 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); + codegen_build_and_link(g); if (timing_info) codegen_print_timing_report(g, stdout); @@ -987,8 +974,14 @@ int main(int argc, char **argv) { args.append(argv[i]); } + const char *exec_path = buf_ptr(&g->output_file_path); + args.append(nullptr); + + os_execv(exec_path, args.items); + + args.pop(); Termination term; - os_spawn_process(buf_ptr(run_exec_path), args, &term); + os_spawn_process(exec_path, args, &term); return term.code; } @@ -1005,11 +998,8 @@ int main(int argc, char **argv) { ZigTarget native; get_native_target(&native); - ZigTarget *non_null_target = target ? target : &native; - - Buf *test_exe_name = buf_sprintf("test%s", target_exe_file_ext(non_null_target)); - Buf *test_exe_path = buf_alloc(); - os_path_join(&full_cache_dir, test_exe_name, test_exe_path); + codegen_build_and_link(g); + Buf *test_exe_path = &g->output_file_path; for (size_t i = 0; i < test_exec_args.length; i += 1) { if (test_exec_args.items[i] == nullptr) { @@ -1017,8 +1007,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", diff --git a/src/os.cpp b/src/os.cpp index 4ee4618184..8502e72715 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -972,6 +972,22 @@ static int os_exec_process_windows(const char *exe, ZigList &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 &args, Termination *term, Buf *out_stderr, Buf *out_stdout) { @@ -1238,44 +1254,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; diff --git a/src/os.hpp b/src/os.hpp index c64eccf8d4..fc2a34326f 100644 --- a/src/os.hpp +++ b/src/os.hpp @@ -87,6 +87,7 @@ int os_init(void); void os_spawn_process(const char *exe, ZigList &args, Termination *term); int os_exec_process(const char *exe, ZigList &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); @@ -96,8 +97,6 @@ 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); - Error ATTRIBUTE_MUST_USE os_make_path(Buf *path); Error ATTRIBUTE_MUST_USE os_make_dir(Buf *path); -- cgit v1.2.3 From 5ee5933ade09c535bd1806d91cb606f49d07acea Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Sep 2018 17:30:45 -0400 Subject: stage1 caching: zig no longer uses zig-cache --- CMakeLists.txt | 1 + src/all_types.hpp | 2 - src/cache_hash.cpp | 7 ++++ src/codegen.cpp | 110 ++++++++++++++++++++++++++++++++++++----------------- src/codegen.hpp | 3 +- src/compiler.cpp | 66 ++++++++++++++++++++++++++++++++ src/compiler.hpp | 17 +++++++++ src/link.cpp | 4 +- src/main.cpp | 78 ++----------------------------------- src/os.cpp | 22 ++++++----- src/os.hpp | 6 +-- 11 files changed, 187 insertions(+), 129 deletions(-) create mode 100644 src/compiler.cpp create mode 100644 src/compiler.hpp (limited to 'src/codegen.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index 8339be71b9..11bb31892c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -411,6 +411,7 @@ set(ZIG_SOURCES "${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" diff --git a/src/all_types.hpp b/src/all_types.hpp index 6d11244a25..4a15162076 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1671,7 +1671,6 @@ struct CodeGen { Buf triple_str; Buf global_asm; Buf *out_h_path; - Buf cache_dir; Buf artifact_dir; Buf output_file_path; Buf o_file_output_path; @@ -1731,7 +1730,6 @@ struct CodeGen { ZigList assembly_files; ZigList lib_dirs; - Buf *compiler_id; size_t version_major; size_t version_minor; size_t version_patch; diff --git a/src/cache_hash.cpp b/src/cache_hash.cpp index b6aebdac67..b302946310 100644 --- a/src/cache_hash.cpp +++ b/src/cache_hash.cpp @@ -248,6 +248,12 @@ Error cache_hit(CacheHash *ch, Buf *out_digest) { 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}); @@ -458,5 +464,6 @@ Error cache_final(CacheHash *ch, Buf *out_digest) { } void cache_release(CacheHash *ch) { + assert(ch->manifest_file_path != nullptr); os_file_close(ch->manifest_file); } diff --git a/src/codegen.cpp b/src/codegen.cpp index 1f53bb4c9d..578fb314a8 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8,6 +8,7 @@ #include "analyze.hpp" #include "ast_render.hpp" #include "codegen.hpp" +#include "compiler.hpp" #include "config.h" #include "errmsg.hpp" #include "error.hpp" @@ -87,13 +88,12 @@ static const char *symbols_that_llvm_depends_on[] = { }; CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode, - Buf *zig_lib_dir, Buf *compiler_id) + Buf *zig_lib_dir) { CodeGen *g = allocate(1); codegen_add_time_event(g, "Initialize"); - g->compiler_id = compiler_id; g->zig_lib_dir = zig_lib_dir; g->zig_std_dir = buf_alloc(); @@ -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; } @@ -5728,13 +5724,6 @@ static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *na return result; } -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 report_errors_and_maybe_exit(CodeGen *g) { if (g->errors.length != 0) { for (size_t i = 0; i < g->errors.length; i += 1) { @@ -6824,36 +6813,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); - - Buf *contents = codegen_generate_builtin_source(g); - ensure_cache_dir(g); - os_write_file(builtin_zig_path, contents); + os_path_join(this_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path); - 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(g->llvm_argv_len + 2); args[0] = "zig (LLVM option parsing)"; @@ -6960,7 +6997,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) { @@ -7668,6 +7709,10 @@ static void add_cache_pkg(CodeGen *g, CacheHash *ch, PackageTableEntry *pkg) { 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); @@ -7675,7 +7720,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { if (g->linker_script != nullptr) { cache_file(ch, buf_create_from_str(g->linker_script)); } - cache_buf(ch, g->compiler_id); + 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); @@ -7766,13 +7811,7 @@ void codegen_build_and_link(CodeGen *g) { codegen_add_time_event(g, "Check Cache"); - Buf app_data_dir = BUF_INIT; - if ((err = os_get_app_data_dir(&app_data_dir, "zig"))) { - fprintf(stderr, "Unable to get app data dir: %s\n", err_str(err)); - exit(1); - } - Buf *stage1_dir = buf_alloc(); - os_path_join(&app_data_dir, buf_create_from_str("stage1"), stage1_dir); + Buf *stage1_dir = get_stage1_cache_path(); Buf *manifest_dir = buf_alloc(); os_path_join(stage1_dir, buf_create_from_str("build"), manifest_dir); @@ -7820,6 +7859,7 @@ void codegen_build_and_link(CodeGen *g) { } // TODO hard link output_file_path to wanted_output_file_path + cache_release(&g->cache_hash); codegen_add_time_event(g, "Done"); } diff --git a/src/codegen.hpp b/src/codegen.hpp index 1e7fafa28a..203e2d2b94 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -15,7 +15,7 @@ #include CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode, - Buf *zig_lib_dir, Buf *compiler_id); + Buf *zig_lib_dir); 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); @@ -46,7 +46,6 @@ 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); diff --git a/src/compiler.cpp b/src/compiler.cpp new file mode 100644 index 0000000000..dd02b541dd --- /dev/null +++ b/src/compiler.cpp @@ -0,0 +1,66 @@ +#include "cache_hash.hpp" + +#include + +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 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; +} + diff --git a/src/compiler.hpp b/src/compiler.hpp new file mode 100644 index 0000000000..b95e4ceda7 --- /dev/null +++ b/src/compiler.hpp @@ -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 diff --git a/src/link.cpp b/src/link.cpp index 8c250fbbe1..8d7b8b4d5f 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -32,7 +32,7 @@ static const char *get_libc_static_file(CodeGen *g, const char *file) { static Buf *build_o_raw(CodeGen *parent_gen, const char *oname, Buf *full_path) { ZigTarget *child_target = parent_gen->is_native_target ? nullptr : &parent_gen->zig_target; CodeGen *child_gen = codegen_create(full_path, child_target, OutTypeObj, parent_gen->build_mode, - parent_gen->zig_lib_dir, parent_gen->compiler_id); + parent_gen->zig_lib_dir); child_gen->want_h_file = false; child_gen->verbose_tokenize = parent_gen->verbose_tokenize; @@ -42,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); diff --git a/src/main.cpp b/src/main.cpp index ff2c061a83..10b789a6e1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,11 +8,11 @@ #include "ast_render.hpp" #include "buffer.hpp" #include "codegen.hpp" +#include "compiler.hpp" #include "config.h" #include "error.hpp" #include "os.hpp" #include "target.hpp" -#include "cache_hash.hpp" #include @@ -257,53 +257,6 @@ static void add_package(CodeGen *g, CliPkg *cli_pkg, PackageTableEntry *pkg) { } } -static Buf saved_compiler_id = BUF_INIT; -static Error get_compiler_id(Buf **result) { - if (saved_compiler_id.list.length != 0) { - *result = &saved_compiler_id; - return ErrorNone; - } - - Error err; - Buf app_data_dir = BUF_INIT; - if ((err = os_get_app_data_dir(&app_data_dir, "zig"))) - return err; - Buf *stage1_dir = buf_alloc(); - os_path_join(&app_data_dir, buf_create_from_str("stage1"), stage1_dir); - 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) { - *result = &saved_compiler_id; - return ErrorNone; - } - ZigList 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; - - *result = &saved_compiler_id; - return ErrorNone; -} - 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", @@ -428,14 +381,7 @@ 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); - 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; - } - - CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, zig_lib_dir_buf, - compiler_id); + CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, zig_lib_dir_buf); codegen_set_out_name(g, buf_create_from_str("build")); Buf *build_file_buf = buf_create_from_str(build_file); @@ -452,8 +398,6 @@ int main(int argc, char **argv) { full_cache_dir = os_path_resolve(&cache_dir_buf, 1); } - codegen_set_cache_dir(g, full_cache_dir); - args.items[1] = buf_ptr(&build_file_dirname); args.items[2] = buf_ptr(&full_cache_dir); @@ -795,7 +739,7 @@ int main(int argc, char **argv) { switch (cmd) { case CmdBuiltin: { Buf *zig_lib_dir_buf = resolve_zig_lib_dir(); - CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, zig_lib_dir_buf, nullptr); + CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, zig_lib_dir_buf); Buf *builtin_source = codegen_generate_builtin_source(g); if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) { fprintf(stderr, "unable to write to stdout: %s\n", strerror(ferror(stdout))); @@ -850,30 +794,16 @@ int main(int argc, char **argv) { Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf; - Buf full_cache_dir = BUF_INIT; if (cmd == CmdRun && buf_out_name == nullptr) { buf_out_name = buf_create_from_str("run"); } - { - 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); - } - Buf *zig_lib_dir_buf = resolve_zig_lib_dir(); - 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; - } - - CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, zig_lib_dir_buf, - compiler_id); + CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, zig_lib_dir_buf); 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); diff --git a/src/os.cpp b/src/os.cpp index 8502e72715..3950711c56 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -721,7 +721,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; @@ -757,7 +757,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; } @@ -769,13 +769,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 } @@ -834,13 +834,15 @@ static int os_exec_process_posix(const char *exe, ZigList &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 @@ -1064,7 +1066,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) { @@ -1083,7 +1085,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; } diff --git a/src/os.hpp b/src/os.hpp index fc2a34326f..ac422fbd21 100644 --- a/src/os.hpp +++ b/src/os.hpp @@ -111,8 +111,8 @@ 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); -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); +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); @@ -122,7 +122,7 @@ 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); +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); -- cgit v1.2.3 From 67735c6f1557092efe6e8c1712445c30655fe283 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 11 Sep 2018 00:32:40 -0400 Subject: ability to disable cache. off by default except for... ...zig run, zig build, compiler_rt.a, and builtin.a --- src/all_types.hpp | 1 + src/analyze.cpp | 8 +++++ src/analyze.hpp | 3 ++ src/cache_hash.cpp | 8 +++++ src/cache_hash.hpp | 5 +++ src/codegen.cpp | 103 ++++++++++++++++++++++++++++++++++++++--------------- src/ir.cpp | 4 +-- src/link.cpp | 1 + src/main.cpp | 50 ++++++++++++++++++++++++-- src/target.cpp | 16 +++++++++ src/target.hpp | 1 + 11 files changed, 166 insertions(+), 34 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 4a15162076..cdc290268a 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1718,6 +1718,7 @@ struct CodeGen { bool verbose_cimport; bool error_during_imports; bool generate_error_name_table; + bool enable_cache; //////////////////////////// Participates in Input Parameter Cache Hash ZigList link_libs_list; diff --git a/src/analyze.cpp b/src/analyze.cpp index aa4fda7624..7fe7a48245 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -6367,3 +6367,11 @@ not_integer: } return nullptr; } + +Error file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents) { + if (g->enable_cache) { + return cache_add_file_fetch(&g->cache_hash, resolved_path, contents); + } else { + return os_fetch_file_path(resolved_path, contents, false); + } +} diff --git a/src/analyze.hpp b/src/analyze.hpp index 41cc50916e..9f036c409d 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -210,4 +210,7 @@ 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); + #endif diff --git a/src/cache_hash.cpp b/src/cache_hash.cpp index b302946310..65e3e62ae0 100644 --- a/src/cache_hash.cpp +++ b/src/cache_hash.cpp @@ -467,3 +467,11 @@ void cache_release(CacheHash *ch) { assert(ch->manifest_file_path != nullptr); os_file_close(ch->manifest_file); } + +Buf *get_random_basename() { + Buf *result = buf_alloc(); + for (size_t i = 0; i < 16; i += 1) { + buf_append_char(result, base64_fs_alphabet[rand() % 64]); + } + return result; +} diff --git a/src/cache_hash.hpp b/src/cache_hash.hpp index ede7344c75..6acd805be6 100644 --- a/src/cache_hash.hpp +++ b/src/cache_hash.hpp @@ -67,4 +67,9 @@ 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); + + +// Completely independent function. Just returns a random filename safe basename. +Buf *get_random_basename(); + #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index 578fb314a8..1e0fd7fec3 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -7048,7 +7048,7 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package *resolved_path = os_path_resolve(resolve_paths, 1); Buf *import_code = buf_alloc(); Error err; - if ((err = cache_add_file_fetch(&g->cache_hash, resolved_path, import_code))) { + 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)); } @@ -7480,10 +7480,7 @@ static void gen_h_file(CodeGen *g) { GenH *gen_h = &gen_h_data; 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) @@ -7790,17 +7787,56 @@ static void resolve_out_paths(CodeGen *g) { zig_unreachable(); } - os_path_join(&g->artifact_dir, o_basename, &g->o_file_output_path); + if (g->enable_cache || g->out_type != OutTypeObj) { + os_path_join(&g->artifact_dir, o_basename, &g->o_file_output_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) { - assert(g->root_out_name); + 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)); - os_path_join(&g->artifact_dir, &basename, &g->output_file_path); + 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) { + 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; + } } } @@ -7809,23 +7845,26 @@ void codegen_build_and_link(CodeGen *g) { Error err; assert(g->out_type != OutTypeUnknown); - codegen_add_time_event(g, "Check Cache"); - 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); + Buf *manifest_dir = buf_alloc(); + os_path_join(stage1_dir, buf_create_from_str("build"), manifest_dir); - Buf digest = BUF_INIT; - if ((err = check_cache(g, manifest_dir, &digest))) { - fprintf(stderr, "Unable to check cache: %s\n", err_str(err)); - exit(1); - } + if ((err = check_cache(g, manifest_dir, &digest))) { + fprintf(stderr, "Unable to check cache: %s\n", err_str(err)); + exit(1); + } - Buf *artifact_dir = buf_alloc(); - os_path_join(stage1_dir, buf_create_from_str("artifact"), artifact_dir); + os_path_join(stage1_dir, buf_create_from_str("artifact"), artifact_dir); + } else { + os_path_join(stage1_dir, buf_create_from_str("tmp"), artifact_dir); + } - if (buf_len(&digest) != 0) { + if (g->enable_cache && buf_len(&digest) != 0) { os_path_join(artifact_dir, &digest, &g->artifact_dir); resolve_out_paths(g); } else { @@ -7836,11 +7875,16 @@ void codegen_build_and_link(CodeGen *g) { gen_global_asm(g); gen_root_source(g); - if ((err = cache_final(&g->cache_hash, &digest))) { - fprintf(stderr, "Unable to finalize cache hash: %s\n", err_str(err)); - exit(1); + 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 *tmp_basename = get_random_basename(); + os_path_join(artifact_dir, tmp_basename, &g->artifact_dir); } - os_path_join(artifact_dir, &digest, &g->artifact_dir); if ((err = os_make_path(&g->artifact_dir))) { fprintf(stderr, "Unable to create artifact directory: %s\n", err_str(err)); exit(1); @@ -7857,9 +7901,10 @@ void codegen_build_and_link(CodeGen *g) { codegen_link(g); } } - // TODO hard link output_file_path to wanted_output_file_path - cache_release(&g->cache_hash); + if (g->enable_cache) { + cache_release(&g->cache_hash); + } codegen_add_time_event(g, "Done"); } diff --git a/src/ir.cpp b/src/ir.cpp index 22d9a9bc49..bfe21f974d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -16277,7 +16277,7 @@ static ZigType *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructionImpor return ira->codegen->builtin_types.entry_namespace; } - if ((err = cache_add_file_fetch(&ira->codegen->cache_hash, resolved_path, import_code))) { + if ((err = file_fetch(ira->codegen, resolved_path, import_code))) { if (err == ErrorFileNotFound) { ir_add_error_node(ira, source_node, buf_sprintf("unable to find '%s'", buf_ptr(import_target_path))); @@ -18108,7 +18108,7 @@ static ZigType *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstructionE // load from file system into const expr Buf *file_contents = buf_alloc(); int err; - if ((err = cache_add_file_fetch(&ira->codegen->cache_hash, &file_path, file_contents))) { + if ((err = file_fetch(ira->codegen, &file_path, file_contents))) { if (err == ErrorFileNotFound) { ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path))); return ira->codegen->builtin_types.entry_invalid; diff --git a/src/link.cpp b/src/link.cpp index 8d7b8b4d5f..aa0edde61b 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -58,6 +58,7 @@ static Buf *build_o_raw(CodeGen *parent_gen, const char *oname, Buf *full_path) new_link_lib->provided_explicitly = link_lib->provided_explicitly; } + child_gen->enable_cache = true; codegen_build_and_link(child_gen); return &child_gen->output_file_path; } diff --git a/src/main.cpp b/src/main.cpp index 10b789a6e1..e4019f10df 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -34,6 +34,7 @@ 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" @@ -257,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", @@ -301,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; @@ -465,6 +485,7 @@ 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); + g->enable_cache = get_cache_opt(enable_cache, true); codegen_build_and_link(g); Termination term; @@ -562,6 +583,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; @@ -894,6 +926,7 @@ int main(int argc, char **argv) { if (cmd == CmdBuild || cmd == CmdRun) { codegen_set_emit_file_type(g, emit_file_type); + g->enable_cache = get_cache_opt(enable_cache, cmd == CmdRun); codegen_build_and_link(g); if (timing_info) codegen_print_timing_report(g, stdout); @@ -913,9 +946,17 @@ int main(int argc, char **argv) { 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(); } - - return EXIT_SUCCESS; } else if (cmd == CmdTranslateC) { codegen_translate_c(g, in_file_buf); ast_render(g, stdout, g->root_import->root, 4); @@ -928,8 +969,11 @@ int main(int argc, char **argv) { ZigTarget native; get_native_target(&native); + g->enable_cache = get_cache_opt(enable_cache, false); codegen_build_and_link(g); - Buf *test_exe_path = &g->output_file_path; + Buf *test_exe_path_unresolved = &g->output_file_path; + Buf *test_exe_path = buf_alloc(); + *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) { diff --git a/src/target.cpp b/src/target.cpp index 91d36c5109..f657af8af3 100644 --- a/src/target.cpp +++ b/src/target.cpp @@ -813,6 +813,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, diff --git a/src/target.hpp b/src/target.hpp index 5a118f6d8d..c8658bf352 100644 --- a/src/target.hpp +++ b/src/target.hpp @@ -113,6 +113,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); -- cgit v1.2.3 From dd1338b0e6280b10b9b62ca73bf9ece34bd8524e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 11 Sep 2018 12:57:53 -0400 Subject: fix incorrect union const value generation closes #1381 The union was generated as a 3 byte struct when it needed to be 4 bytes so that the packed struct bitcast could work correctly. Now it recognizes this situation and adds padding bytes to become the correct size so that it can fit into an array. --- src/codegen.cpp | 15 ++++++++++++--- test/behavior.zig | 1 + test/cases/bugs/1381.zig | 21 +++++++++++++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 test/cases/bugs/1381.zig (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 71caf18e28..2548b3fa8c 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3218,7 +3218,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) { @@ -5863,12 +5864,20 @@ 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); + size_t expected_sz = LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref); + size_t actual_sz = LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(result)); + if (actual_sz < expected_sz) { + unsigned pad_sz = expected_sz - actual_sz; + fields[2] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), pad_sz)); + result = LLVMConstStruct(fields, 3, false); + } + return result; } else { return LLVMConstNamedStruct(type_entry->type_ref, fields, 2); } diff --git a/test/behavior.zig b/test/behavior.zig index 25997a2a4b..cae8c4b0f3 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -10,6 +10,7 @@ comptime { _ = @import("cases/bool.zig"); _ = @import("cases/bugs/1111.zig"); _ = @import("cases/bugs/1277.zig"); + _ = @import("cases/bugs/1381.zig"); _ = @import("cases/bugs/1421.zig"); _ = @import("cases/bugs/394.zig"); _ = @import("cases/bugs/655.zig"); diff --git a/test/cases/bugs/1381.zig b/test/cases/bugs/1381.zig new file mode 100644 index 0000000000..2d452da156 --- /dev/null +++ b/test/cases/bugs/1381.zig @@ -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); +} -- cgit v1.2.3 From 7dd3c3814de0caf808bc112aa07044cdd8bba135 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 11 Sep 2018 15:16:50 -0400 Subject: fix incorrect error union const value generation closes #1442 zig needed to insert explicit padding into this structure before it got bitcasted. --- src/analyze.cpp | 15 +++++++++++++-- src/codegen.cpp | 38 +++++++++++++++++++++++++++++--------- std/os/index.zig | 36 +++++++++++++++++++----------------- test/behavior.zig | 1 + test/cases/bugs/1442.zig | 11 +++++++++++ 5 files changed, 73 insertions(+), 28 deletions(-) create mode 100644 test/cases/bugs/1442.zig (limited to 'src/codegen.cpp') diff --git a/src/analyze.cpp b/src/analyze.cpp index e0539df10b..07c7b94e25 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -5882,12 +5882,23 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { } case ZigTypeIdErrorUnion: { - buf_appendf(buf, "(error union %s constant)", buf_ptr(&type_entry->name)); + buf_appendf(buf, "%s(", buf_ptr(&type_entry->name)); + if (const_val->data.x_err_union.err == nullptr) { + render_const_value(g, buf, const_val->data.x_err_union.payload); + } else { + buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->data.error_union.err_set_type->name), + buf_ptr(&const_val->data.x_err_union.err->name)); + } + buf_appendf(buf, ")"); return; } case ZigTypeIdUnion: { - buf_appendf(buf, "(union %s constant)", buf_ptr(&type_entry->name)); + uint64_t tag = bigint_as_unsigned(&const_val->data.x_union.tag); + TypeUnionField *field = &type_entry->data.unionation.fields[tag]; + buf_appendf(buf, "%s { .%s = ", buf_ptr(&type_entry->name), buf_ptr(field->name)); + render_const_value(g, buf, const_val->data.x_union.payload); + buf_append_str(buf, "}"); return; } case ZigTypeIdErrorSet: diff --git a/src/codegen.cpp b/src/codegen.cpp index 2548b3fa8c..5b6c53e8f8 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5870,13 +5870,17 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c if (make_unnamed_struct) { LLVMValueRef result = LLVMConstStruct(fields, 2, false); - size_t expected_sz = LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref); - size_t actual_sz = LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(result)); - if (actual_sz < expected_sz) { - unsigned pad_sz = expected_sz - actual_sz; + 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); @@ -5917,13 +5921,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); } } diff --git a/std/os/index.zig b/std/os/index.zig index 3ab73a79ac..8e92fc23c5 100644 --- a/std/os/index.zig +++ b/std/os/index.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; diff --git a/test/behavior.zig b/test/behavior.zig index cae8c4b0f3..869024f296 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -12,6 +12,7 @@ comptime { _ = @import("cases/bugs/1277.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"); diff --git a/test/cases/bugs/1442.zig b/test/cases/bugs/1442.zig new file mode 100644 index 0000000000..d7057d9ed1 --- /dev/null +++ b/test/cases/bugs/1442.zig @@ -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); +} -- cgit v1.2.3 From 15c67d2d50aae11dd425ad2629ebc9770fb95f30 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 11 Sep 2018 16:52:50 -0400 Subject: fix docgen tests --- doc/docgen.zig | 7 +++++++ src/codegen.cpp | 2 ++ 2 files changed, 9 insertions(+) (limited to 'src/codegen.cpp') diff --git a/doc/docgen.zig b/doc/docgen.zig index c1158dc03f..5d77a1ea14 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -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(); @@ -821,6 +822,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("
$ zig test {}.zig", code.name);
                         switch (code.mode) {
@@ -863,6 +866,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("
$ zig test {}.zig", code.name);
                         switch (code.mode) {
@@ -918,6 +923,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 => {},
diff --git a/src/codegen.cpp b/src/codegen.cpp
index d1239eb23f..af42f324b4 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -8122,6 +8122,8 @@ static void resolve_out_paths(CodeGen *g) {
 
     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);
     }
-- 
cgit v1.2.3


From 7e9f25dd18b7da750e547de94a779e3c14c07d94 Mon Sep 17 00:00:00 2001
From: Andrew Kelley 
Date: Tue, 11 Sep 2018 20:54:39 -0400
Subject: stage1: clean up timing report in test mode

---
 src/codegen.cpp | 7 +++++--
 src/main.cpp    | 8 +++++---
 2 files changed, 10 insertions(+), 5 deletions(-)

(limited to 'src/codegen.cpp')

diff --git a/src/codegen.cpp b/src/codegen.cpp
index af42f324b4..96e979f9d3 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -6388,9 +6388,9 @@ static void do_code_gen(CodeGen *g) {
     char *error = nullptr;
     LLVMVerifyModule(g->module, LLVMAbortProcessAction, &error);
 #endif
+}
 
-    codegen_add_time_event(g, "LLVM Emit Output");
-
+static void zig_llvm_emit_output(CodeGen *g) {
     bool is_small = g->build_mode == BuildModeSmallRelease;
 
     Buf *output_path = &g->o_file_output_path;
@@ -8228,6 +8228,9 @@ void codegen_build_and_link(CodeGen *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);
diff --git a/src/main.cpp b/src/main.cpp
index e4019f10df..1751fabfe5 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -971,6 +971,11 @@ int main(int argc, char **argv) {
 
                 g->enable_cache = get_cache_opt(enable_cache, false);
                 codegen_build_and_link(g);
+
+                if (timing_info) {
+                    codegen_print_timing_report(g, stdout);
+                }
+
                 Buf *test_exe_path_unresolved = &g->output_file_path;
                 Buf *test_exe_path = buf_alloc();
                 *test_exe_path = os_path_resolve(&test_exe_path_unresolved, 1);
@@ -981,7 +986,6 @@ int main(int argc, char **argv) {
                     }
                 }
 
-
                 if (!target_can_exec(&native, target)) {
                     fprintf(stderr, "Created %s but skipping execution because it is non-native.\n",
                             buf_ptr(test_exe_path));
@@ -1003,8 +1007,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 {
-- 
cgit v1.2.3


From ee263a15cc8fb52c2ac6053a29168fb15089839b Mon Sep 17 00:00:00 2001
From: Andrew Kelley 
Date: Tue, 11 Sep 2018 22:25:52 -0400
Subject: bring back zig-cache

we need somewhere to put .o files and leave them while the user
executes their program, so that stack traces on MacOS can find
the .o files and get at the DWARF info.

if we try to clean up old global tmp dir files, first of all that's
a hard and complicated problem, and secondly it's not clear how
that is better than dumping the .o file inside zig-cache locally.
---
 src/all_types.hpp  |  1 +
 src/cache_hash.cpp |  8 --------
 src/cache_hash.hpp |  4 ----
 src/codegen.cpp    |  5 +----
 src/main.cpp       | 13 +++++--------
 5 files changed, 7 insertions(+), 24 deletions(-)

(limited to 'src/codegen.cpp')

diff --git a/src/all_types.hpp b/src/all_types.hpp
index f9c50eeaac..3dfbc6ba7f 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -1682,6 +1682,7 @@ struct CodeGen {
     Buf output_file_path;
     Buf o_file_output_path;
     Buf *wanted_output_file_path;
+    Buf cache_dir;
 
     IrInstruction *invalid_instruction;
 
diff --git a/src/cache_hash.cpp b/src/cache_hash.cpp
index 65e3e62ae0..b302946310 100644
--- a/src/cache_hash.cpp
+++ b/src/cache_hash.cpp
@@ -467,11 +467,3 @@ void cache_release(CacheHash *ch) {
     assert(ch->manifest_file_path != nullptr);
     os_file_close(ch->manifest_file);
 }
-
-Buf *get_random_basename() {
-    Buf *result = buf_alloc();
-    for (size_t i = 0; i < 16; i += 1) {
-        buf_append_char(result, base64_fs_alphabet[rand() % 64]);
-    }
-    return result;
-}
diff --git a/src/cache_hash.hpp b/src/cache_hash.hpp
index 6acd805be6..db1c42ec03 100644
--- a/src/cache_hash.hpp
+++ b/src/cache_hash.hpp
@@ -68,8 +68,4 @@ Error ATTRIBUTE_MUST_USE cache_final(CacheHash *ch, Buf *out_b64_digest);
 void cache_release(CacheHash *ch);
 
 
-
-// Completely independent function. Just returns a random filename safe basename.
-Buf *get_random_basename();
-
 #endif
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 96e979f9d3..aeb2b6edc4 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -8195,8 +8195,6 @@ void codegen_build_and_link(CodeGen *g) {
         }
 
         os_path_join(stage1_dir, buf_create_from_str("artifact"), artifact_dir);
-    } else {
-        os_path_join(stage1_dir, buf_create_from_str("tmp"), artifact_dir);
     }
 
     if (g->enable_cache && buf_len(&digest) != 0) {
@@ -8217,8 +8215,7 @@ void codegen_build_and_link(CodeGen *g) {
             }
             os_path_join(artifact_dir, &digest, &g->artifact_dir);
         } else {
-            Buf *tmp_basename = get_random_basename(); 
-            os_path_join(artifact_dir, tmp_basename, &g->artifact_dir);
+            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));
diff --git a/src/main.cpp b/src/main.cpp
index 1751fabfe5..f18dd949b0 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -353,7 +353,7 @@ int main(int argc, char **argv) {
     size_t ver_minor = 0;
     size_t ver_patch = 0;
     bool timing_info = false;
-    const char *cache_dir = nullptr;
+    const char *cache_dir = default_zig_cache_name;
     CliPkg *cur_pkg = allocate(1);
     BuildMode build_mode = BuildModeDebug;
     ZigList test_exec_args = {0};
@@ -402,6 +402,7 @@ int main(int argc, char **argv) {
         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);
+        buf_init_from_str(&g->cache_dir, cache_dir);
         codegen_set_out_name(g, buf_create_from_str("build"));
 
         Buf *build_file_buf = buf_create_from_str(build_file);
@@ -410,13 +411,8 @@ 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);
-        } else {
-            Buf *cache_dir_buf = buf_create_from_str(cache_dir);
-            full_cache_dir = os_path_resolve(&cache_dir_buf, 1);
-        }
+        Buf *cache_dir_buf = buf_create_from_str(cache_dir);
+        Buf full_cache_dir = os_path_resolve(&cache_dir_buf, 1);
 
         args.items[1] = buf_ptr(&build_file_dirname);
         args.items[2] = buf_ptr(&full_cache_dir);
@@ -832,6 +828,7 @@ int main(int argc, char **argv) {
             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);
+            buf_init_from_str(&g->cache_dir, cache_dir);
             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);
-- 
cgit v1.2.3


From 014cc60a72ac2d64935bf424459b5fa13e281ed9 Mon Sep 17 00:00:00 2001
From: Andrew Kelley 
Date: Tue, 11 Sep 2018 22:46:22 -0400
Subject: rename --enable-timing-info to -ftime-report to match clang

and have it print llvm's internal timing info
---
 src/all_types.hpp | 1 +
 src/codegen.cpp   | 9 ++++++---
 src/main.cpp      | 6 ++++--
 src/zig_llvm.cpp  | 9 ++++++++-
 src/zig_llvm.h    | 3 ++-
 5 files changed, 21 insertions(+), 7 deletions(-)

(limited to 'src/codegen.cpp')

diff --git a/src/all_types.hpp b/src/all_types.hpp
index 3dfbc6ba7f..8aa2718d30 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -1727,6 +1727,7 @@ struct CodeGen {
     bool error_during_imports;
     bool generate_error_name_table;
     bool enable_cache;
+    bool enable_time_report;
 
     //////////////////////////// Participates in Input Parameter Cache Hash
     ZigList link_libs_list;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index aeb2b6edc4..6f21ceecab 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -6398,7 +6398,8 @@ static void zig_llvm_emit_output(CodeGen *g) {
     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);
             }
@@ -6408,7 +6409,8 @@ static void zig_llvm_emit_output(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);
             }
@@ -6417,7 +6419,8 @@ static void zig_llvm_emit_output(CodeGen *g) {
 
         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);
             }
diff --git a/src/main.cpp b/src/main.cpp
index f18dd949b0..fdc34a83ae 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -37,7 +37,7 @@ static int usage(const char *arg0) {
         "  --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"
@@ -402,6 +402,7 @@ int main(int argc, char **argv) {
         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);
         codegen_set_out_name(g, buf_create_from_str("build"));
 
@@ -533,7 +534,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);
@@ -828,6 +829,7 @@ int main(int argc, char **argv) {
             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);
             codegen_set_out_name(g, buf_out_name);
             codegen_set_lib_version(g, ver_major, ver_minor, ver_patch);
diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp
index a43d2d182c..61287f620c 100644
--- a/src/zig_llvm.cpp
+++ b/src/zig_llvm.cpp
@@ -30,6 +30,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -81,8 +82,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) {
@@ -182,6 +186,9 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
         }
     }
 
+    if (time_report) {
+        TimerGroup::printAll(errs());
+    }
     return false;
 }
 
diff --git a/src/zig_llvm.h b/src/zig_llvm.h
index 63d69bd23e..5cdc6cc041 100644
--- a/src/zig_llvm.h
+++ b/src/zig_llvm.h
@@ -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);
 
-- 
cgit v1.2.3


From 9ac9633b105b737f2700f1930768a6ea6d4d75c5 Mon Sep 17 00:00:00 2001
From: Andrew Kelley 
Date: Thu, 13 Sep 2018 14:30:15 -0400
Subject: stage1: put test output artifact back in zig-cache folder

close #1508
---
 src/codegen.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/codegen.cpp')

diff --git a/src/codegen.cpp b/src/codegen.cpp
index 6f21ceecab..4e28613285 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -8142,7 +8142,7 @@ static void resolve_out_paths(CodeGen *g) {
             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) {
+            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);
-- 
cgit v1.2.3


From 7c3636aaa38e8efa77b73ba94362802517ea739e Mon Sep 17 00:00:00 2001
From: Andrew Kelley 
Date: Thu, 13 Sep 2018 15:46:34 -0400
Subject: remove the scope parameter of setFloatMode

also document that scopes inherit this value. See #367
See #1283
---
 doc/langref.html.in     | 18 ++++++++-----
 src/all_types.hpp       |  2 +-
 src/codegen.cpp         | 12 ++++-----
 src/ir.cpp              | 72 ++++++++++++++++++-------------------------------
 test/cases/eval.zig     |  2 +-
 test/compile_errors.zig |  4 +--
 6 files changed, 47 insertions(+), 63 deletions(-)

(limited to 'src/codegen.cpp')

diff --git a/doc/langref.html.in b/doc/langref.html.in
index 6f12f0339f..aefbfc5650 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -734,7 +734,7 @@ export fn foo_strict(x: f64) f64 {
 }
 
 export fn foo_optimized(x: f64) f64 {
-    @setFloatMode(this, builtin.FloatMode.Optimized);
+    @setFloatMode(builtin.FloatMode.Optimized);
     return x + big - big;
 }
       {#code_end#}
@@ -6030,17 +6030,20 @@ test "foo" {
       {#see_also|comptime#}
       {#header_close#}
       {#header_open|@setFloatMode#}
-      
@setFloatMode(scope, mode: @import("builtin").FloatMode)
+
@setFloatMode(mode: @import("builtin").FloatMode)

- Sets the floating point mode for a given scope. Possible values are: + Sets the floating point mode of the current scope. Possible values are:

{#code_begin|syntax#} pub const FloatMode = enum { - Optimized, Strict, + Optimized, }; {#code_end#}
    +
  • + Strict (default) - Floating point operations follow strict IEEE compliance. +
  • Optimized - Floating point operations may do all of the following:
      @@ -6053,10 +6056,11 @@ pub const FloatMode = enum {
    This is equivalent to -ffast-math in GCC.
  • -
  • - Strict (default) - Floating point operations follow strict IEEE compliance. -
+

+ The floating point mode is inherited by child scopes, and can be overridden in any scope. + You can set the floating point mode in a struct or module scope by using a comptime block. +

{#see_also|Floating Point Operations#} {#header_close#} {#header_open|@setGlobalLinkage#} diff --git a/src/all_types.hpp b/src/all_types.hpp index 8aa2718d30..27871156d6 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -3287,8 +3287,8 @@ static const size_t stack_trace_ptr_count = 30; enum FloatMode { - FloatModeOptimized, FloatModeStrict, + FloatModeOptimized, }; enum FnWalkId { diff --git a/src/codegen.cpp b/src/codegen.cpp index 4e28613285..38f31074d0 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -6729,7 +6729,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); @@ -7115,11 +7115,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, @@ -7127,8 +7127,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"; diff --git a/src/ir.cpp b/src/ir.cpp index b432facb36..6f1a7a741a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1577,13 +1577,11 @@ static IrInstruction *ir_build_set_runtime_safety(IrBuilder *irb, Scope *scope, } static IrInstruction *ir_build_set_float_mode(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *scope_value, IrInstruction *mode_value) + IrInstruction *mode_value) { IrInstructionSetFloatMode *instruction = ir_build_instruction(irb, scope, source_node); - instruction->scope_value = scope_value; instruction->mode_value = mode_value; - ir_ref_instruction(scope_value, irb->current_basic_block); ir_ref_instruction(mode_value, irb->current_basic_block); return &instruction->base; @@ -3959,12 +3957,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo if (arg0_value == irb->codegen->invalid_instruction) return arg0_value; - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_instruction) - return arg1_value; - - IrInstruction *set_float_mode = ir_build_set_float_mode(irb, scope, node, arg0_value, arg1_value); + IrInstruction *set_float_mode = ir_build_set_float_mode(irb, scope, node, arg0_value); return ir_lval_wrap(irb, scope, set_float_mode, lval); } case BuiltinFnIdSizeof: @@ -15379,6 +15372,7 @@ static ZigType *ir_analyze_instruction_set_cold(IrAnalyze *ira, IrInstructionSet ir_build_const_from(ira, &instruction->base); return ira->codegen->builtin_types.entry_void; } + static ZigType *ir_analyze_instruction_set_runtime_safety(IrAnalyze *ira, IrInstructionSetRuntimeSafety *set_runtime_safety_instruction) { @@ -15439,14 +15433,6 @@ static ZigType *ir_analyze_instruction_set_runtime_safety(IrAnalyze *ira, static ZigType *ir_analyze_instruction_set_float_mode(IrAnalyze *ira, IrInstructionSetFloatMode *instruction) { - IrInstruction *target_instruction = instruction->scope_value->other; - ZigType *target_type = target_instruction->value.type; - if (type_is_invalid(target_type)) - return ira->codegen->builtin_types.entry_invalid; - ConstExprValue *target_val = ir_resolve_const(ira, target_instruction, UndefBad); - if (!target_val) - return ira->codegen->builtin_types.entry_invalid; - if (ira->new_irb.exec->is_inline) { // ignore setFloatMode when running functions at compile time ir_build_const_from(ira, &instruction->base); @@ -15455,40 +15441,34 @@ static ZigType *ir_analyze_instruction_set_float_mode(IrAnalyze *ira, bool *fast_math_on_ptr; AstNode **fast_math_set_node_ptr; - if (target_type->id == ZigTypeIdBlock) { - ScopeBlock *block_scope = (ScopeBlock *)target_val->data.x_block; - fast_math_on_ptr = &block_scope->fast_math_on; - fast_math_set_node_ptr = &block_scope->fast_math_set_node; - } else if (target_type->id == ZigTypeIdFn) { - assert(target_val->data.x_ptr.special == ConstPtrSpecialFunction); - ZigFn *target_fn = target_val->data.x_ptr.data.fn.fn_entry; - assert(target_fn->def_scope); - fast_math_on_ptr = &target_fn->def_scope->fast_math_on; - fast_math_set_node_ptr = &target_fn->def_scope->fast_math_set_node; - } else if (target_type->id == ZigTypeIdMetaType) { - ScopeDecls *decls_scope; - ZigType *type_arg = target_val->data.x_type; - if (type_arg->id == ZigTypeIdStruct) { - decls_scope = type_arg->data.structure.decls_scope; - } else if (type_arg->id == ZigTypeIdEnum) { - decls_scope = type_arg->data.enumeration.decls_scope; - } else if (type_arg->id == ZigTypeIdUnion) { - decls_scope = type_arg->data.unionation.decls_scope; + + Scope *scope = instruction->base.scope; + while (scope != nullptr) { + if (scope->id == ScopeIdBlock) { + ScopeBlock *block_scope = (ScopeBlock *)scope; + fast_math_on_ptr = &block_scope->fast_math_on; + fast_math_set_node_ptr = &block_scope->fast_math_set_node; + break; + } else if (scope->id == ScopeIdFnDef) { + ScopeFnDef *def_scope = (ScopeFnDef *)scope; + ZigFn *target_fn = def_scope->fn_entry; + assert(target_fn->def_scope != nullptr); + fast_math_on_ptr = &target_fn->def_scope->fast_math_on; + fast_math_set_node_ptr = &target_fn->def_scope->fast_math_set_node; + break; + } else if (scope->id == ScopeIdDecls) { + ScopeDecls *decls_scope = (ScopeDecls *)scope; + fast_math_on_ptr = &decls_scope->fast_math_on; + fast_math_set_node_ptr = &decls_scope->fast_math_set_node; + break; } else { - ir_add_error_node(ira, target_instruction->source_node, - buf_sprintf("expected scope reference, found type '%s'", buf_ptr(&type_arg->name))); - return ira->codegen->builtin_types.entry_invalid; + scope = scope->parent; + continue; } - fast_math_on_ptr = &decls_scope->fast_math_on; - fast_math_set_node_ptr = &decls_scope->fast_math_set_node; - } else { - ir_add_error_node(ira, target_instruction->source_node, - buf_sprintf("expected scope reference, found type '%s'", buf_ptr(&target_type->name))); - return ira->codegen->builtin_types.entry_invalid; } + assert(scope != nullptr); IrInstruction *float_mode_value = instruction->mode_value->other; - FloatMode float_mode_scalar; if (!ir_resolve_float_mode(ira, float_mode_value, &float_mode_scalar)) return ira->codegen->builtin_types.entry_invalid; diff --git a/test/cases/eval.zig b/test/cases/eval.zig index b8d80bda02..4286821183 100644 --- a/test/cases/eval.zig +++ b/test/cases/eval.zig @@ -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; } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 8fb64e21e2..750794c909 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -3996,8 +3996,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add( "@setFloatMode twice for same scope", \\export fn foo() void { - \\ @setFloatMode(this, @import("builtin").FloatMode.Optimized); - \\ @setFloatMode(this, @import("builtin").FloatMode.Optimized); + \\ @setFloatMode(@import("builtin").FloatMode.Optimized); + \\ @setFloatMode(@import("builtin").FloatMode.Optimized); \\} , ".tmp_source.zig:3:5: error: float mode set twice for same scope", -- cgit v1.2.3 From c06a61e9bf93810174255474598cfeae785cfbd6 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 13 Sep 2018 16:34:33 -0400 Subject: remove `this`. add `@This()`. closes #1283 --- doc/langref.html.in | 13 ++------ src-self-hosted/type.zig | 12 ------- src/all_types.hpp | 4 +-- src/analyze.cpp | 68 +++----------------------------------- src/analyze.hpp | 1 - src/ast_render.cpp | 7 ---- src/codegen.cpp | 13 +------- src/ir.cpp | 81 ++++++++++++---------------------------------- src/parser.cpp | 9 +----- src/tokenizer.cpp | 2 -- src/tokenizer.hpp | 1 - std/array_list.zig | 2 +- std/atomic/int.zig | 2 +- std/atomic/queue.zig | 2 +- std/atomic/stack.zig | 2 +- std/build.zig | 2 +- std/crypto/blake2.zig | 4 +-- std/crypto/hmac.zig | 2 +- std/crypto/md5.zig | 2 +- std/crypto/poly1305.zig | 2 +- std/crypto/sha1.zig | 2 +- std/crypto/sha2.zig | 4 +-- std/crypto/sha3.zig | 2 +- std/event/channel.zig | 2 +- std/event/fs.zig | 2 +- std/event/future.zig | 2 +- std/event/group.zig | 2 +- std/event/locked.zig | 2 +- std/event/rwlocked.zig | 2 +- std/event/tcp.zig | 2 +- std/fmt/index.zig | 2 +- std/hash/crc.zig | 4 +-- std/hash/fnv.zig | 2 +- std/hash/siphash.zig | 2 +- std/hash_map.zig | 4 +-- std/heap.zig | 2 +- std/io.zig | 12 +++---- std/lazy_init.zig | 2 +- std/linked_list.zig | 2 +- std/math/complex/index.zig | 2 +- std/mem.zig | 2 +- std/net.zig | 2 +- std/os/index.zig | 2 +- std/segmented_list.zig | 2 +- std/zig/ast.zig | 4 +-- std/zig/parser_test.zig | 2 +- std/zig/render.zig | 2 +- test/cases/cast.zig | 4 +-- test/cases/eval.zig | 2 +- test/cases/misc.zig | 3 -- test/cases/reflection.zig | 2 +- test/cases/struct.zig | 4 +-- test/cases/this.zig | 13 ++------ test/cases/type_info.zig | 4 +-- test/compile_errors.zig | 28 ++++++++-------- 55 files changed, 97 insertions(+), 266 deletions(-) (limited to 'src/codegen.cpp') diff --git a/doc/langref.html.in b/doc/langref.html.in index aefbfc5650..3f2e741e36 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -478,13 +478,9 @@ pub fn main() void { undefined used to leave a value unspecified - - this - refers to the thing in immediate scope - - {#see_also|Optionals|this#} + {#see_also|Optionals#} {#header_close#} {#header_open|String Literals#} {#code_begin|test#} @@ -4186,11 +4182,6 @@ fn foo() void {} {#code_end#} {#header_close#} - {#header_open|this#} -

TODO: example of this referring to Self struct

-

TODO: example of this referring to recursion function

-

TODO: example of this referring to basic block for @setRuntimeSafety

- {#header_close#} {#header_open|comptime#}

Zig places importance on the concept of whether an expression is known at compile-time. @@ -7744,7 +7735,7 @@ ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" GroupedExpression = "(" Expression ")" -KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" | "suspend" +KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "unreachable" | "suspend" ErrorSetDecl = "error" "{" list(Symbol, ",") "}" diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index 47dd3772e5..aa00bb876d 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -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, diff --git a/src/all_types.hpp b/src/all_types.hpp index 27871156d6..fefbae0fe3 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -283,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 @@ -413,7 +412,6 @@ enum NodeType { NodeTypeBoolLiteral, NodeTypeNullLiteral, NodeTypeUndefinedLiteral, - NodeTypeThisLiteral, NodeTypeUnreachable, NodeTypeIfBoolExpr, NodeTypeWhileExpr, @@ -1205,7 +1203,6 @@ enum ZigTypeId { ZigTypeIdUnion, ZigTypeIdFn, ZigTypeIdNamespace, - ZigTypeIdBlock, ZigTypeIdBoundFn, ZigTypeIdArgTuple, ZigTypeIdOpaque, @@ -1413,6 +1410,7 @@ enum BuiltinFnId { BuiltinFnIdSetEvalBranchQuota, BuiltinFnIdAlignCast, BuiltinFnIdOpaqueType, + BuiltinFnIdThis, BuiltinFnIdSetAlignStack, BuiltinFnIdArgType, BuiltinFnIdExport, diff --git a/src/analyze.cpp b/src/analyze.cpp index 9a9e9a0513..9af4f7347c 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -246,7 +246,6 @@ AstNode *type_decl_node(ZigType *type_entry) { case ZigTypeIdErrorSet: case ZigTypeIdFn: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdPromise: @@ -284,7 +283,6 @@ bool type_is_complete(ZigType *type_entry) { case ZigTypeIdErrorSet: case ZigTypeIdFn: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdPromise: @@ -320,7 +318,6 @@ bool type_has_zero_bits_known(ZigType *type_entry) { case ZigTypeIdErrorSet: case ZigTypeIdFn: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdOpaque: @@ -1414,7 +1411,6 @@ static bool type_allowed_in_packed_struct(ZigType *type_entry) { case ZigTypeIdErrorUnion: case ZigTypeIdErrorSet: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdOpaque: @@ -1455,7 +1451,6 @@ static bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) { case ZigTypeIdErrorUnion: case ZigTypeIdErrorSet: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdPromise: @@ -1613,7 +1608,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdBoundFn: case ZigTypeIdMetaType: case ZigTypeIdVoid: @@ -1703,7 +1697,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdBoundFn: case ZigTypeIdMetaType: case ZigTypeIdUnreachable: @@ -3437,7 +3430,6 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { case NodeTypeBoolLiteral: case NodeTypeNullLiteral: case NodeTypeUndefinedLiteral: - case NodeTypeThisLiteral: case NodeTypeSymbol: case NodeTypePrefixOpExpr: case NodeTypePointerType: @@ -3497,7 +3489,6 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry case ZigTypeIdUnreachable: case ZigTypeIdUndefined: case ZigTypeIdNull: - case ZigTypeIdBlock: case ZigTypeIdArgTuple: case ZigTypeIdOpaque: add_node_error(g, source_node, buf_sprintf("variable of type '%s' not allowed", @@ -3798,34 +3789,6 @@ ZigFn *scope_fn_entry(Scope *scope) { return nullptr; } -ZigFn *scope_get_fn_if_root(Scope *scope) { - assert(scope); - scope = scope->parent; - while (scope) { - switch (scope->id) { - case ScopeIdBlock: - return nullptr; - case ScopeIdDecls: - case ScopeIdDefer: - case ScopeIdDeferExpr: - case ScopeIdVarDecl: - case ScopeIdCImport: - case ScopeIdLoop: - case ScopeIdSuspend: - case ScopeIdCompTime: - case ScopeIdCoroPrelude: - case ScopeIdRuntime: - scope = scope->parent; - continue; - case ScopeIdFnDef: - ScopeFnDef *fn_scope = (ScopeFnDef *)scope; - return fn_scope->fn_entry; - } - zig_unreachable(); - } - return nullptr; -} - TypeEnumField *find_enum_type_field(ZigType *enum_type, Buf *name) { assert(enum_type->id == ZigTypeIdEnum); if (enum_type->data.enumeration.src_field_count == 0) @@ -3907,7 +3870,6 @@ static bool is_container(ZigType *type_entry) { case ZigTypeIdErrorSet: case ZigTypeIdFn: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdOpaque: @@ -3966,7 +3928,6 @@ void resolve_container_type(CodeGen *g, ZigType *type_entry) { case ZigTypeIdErrorSet: case ZigTypeIdFn: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdBoundFn: case ZigTypeIdInvalid: case ZigTypeIdArgTuple: @@ -4427,7 +4388,6 @@ bool handle_is_ptr(ZigType *type_entry) { case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdOpaque: @@ -4842,8 +4802,6 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { return const_val->data.x_err_set->value ^ 2630160122; case ZigTypeIdNamespace: return hash_ptr(const_val->data.x_import); - case ZigTypeIdBlock: - return hash_ptr(const_val->data.x_block); case ZigTypeIdBoundFn: case ZigTypeIdInvalid: case ZigTypeIdUnreachable: @@ -4904,7 +4862,6 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) { case ZigTypeIdNamespace: case ZigTypeIdBoundFn: case ZigTypeIdFn: - case ZigTypeIdBlock: case ZigTypeIdOpaque: case ZigTypeIdPromise: case ZigTypeIdErrorSet: @@ -4971,7 +4928,6 @@ static bool return_type_is_cacheable(ZigType *return_type) { case ZigTypeIdNamespace: case ZigTypeIdBoundFn: case ZigTypeIdFn: - case ZigTypeIdBlock: case ZigTypeIdOpaque: case ZigTypeIdPromise: case ZigTypeIdErrorSet: @@ -5083,7 +5039,6 @@ bool type_requires_comptime(ZigType *type_entry) { case ZigTypeIdNull: case ZigTypeIdMetaType: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: return true; @@ -5615,8 +5570,6 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) { zig_panic("TODO"); case ZigTypeIdNamespace: return a->data.x_import == b->data.x_import; - case ZigTypeIdBlock: - return a->data.x_block == b->data.x_block; case ZigTypeIdArgTuple: return a->data.x_arg_tuple.start_index == b->data.x_arg_tuple.start_index && a->data.x_arg_tuple.end_index == b->data.x_arg_tuple.end_index; @@ -5795,12 +5748,6 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { } case ZigTypeIdPointer: return render_const_val_ptr(g, buf, const_val, type_entry); - case ZigTypeIdBlock: - { - AstNode *node = const_val->data.x_block->source_node; - buf_appendf(buf, "(scope:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ")", node->line + 1, node->column + 1); - return; - } case ZigTypeIdArray: { ZigType *child_type = type_entry->data.array.child_type; @@ -5980,7 +5927,6 @@ uint32_t type_id_hash(TypeId x) { case ZigTypeIdUnion: case ZigTypeIdFn: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdPromise: @@ -6027,7 +5973,6 @@ bool type_id_eql(TypeId a, TypeId b) { case ZigTypeIdUnion: case ZigTypeIdFn: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdOpaque: @@ -6153,7 +6098,6 @@ static const ZigTypeId all_type_ids[] = { ZigTypeIdUnion, ZigTypeIdFn, ZigTypeIdNamespace, - ZigTypeIdBlock, ZigTypeIdBoundFn, ZigTypeIdArgTuple, ZigTypeIdOpaque, @@ -6215,16 +6159,14 @@ size_t type_id_index(ZigType *entry) { return 18; case ZigTypeIdNamespace: return 19; - case ZigTypeIdBlock: - return 20; case ZigTypeIdBoundFn: - return 21; + return 20; case ZigTypeIdArgTuple: - return 22; + return 21; case ZigTypeIdOpaque: - return 23; + return 22; case ZigTypeIdPromise: - return 24; + return 23; } zig_unreachable(); } @@ -6273,8 +6215,6 @@ const char *type_id_name(ZigTypeId id) { return "Fn"; case ZigTypeIdNamespace: return "Namespace"; - case ZigTypeIdBlock: - return "Block"; case ZigTypeIdBoundFn: return "BoundFn"; case ZigTypeIdArgTuple: diff --git a/src/analyze.hpp b/src/analyze.hpp index d69265f974..02f3d65800 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -87,7 +87,6 @@ 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); diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 984b4230b1..37d4221eef 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -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"; diff --git a/src/codegen.cpp b/src/codegen.cpp index 38f31074d0..86ede7411d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5479,7 +5479,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: @@ -5954,7 +5953,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: @@ -6477,12 +6475,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"); @@ -6763,6 +6755,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) { @@ -6944,7 +6937,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" @@ -7589,7 +7581,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: @@ -7768,7 +7759,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: @@ -7921,7 +7911,6 @@ static void gen_h_file(CodeGen *g) { case ZigTypeIdErrorUnion: case ZigTypeIdErrorSet: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdOptional: diff --git a/src/ir.cpp b/src/ir.cpp index 6f1a7a741a..7448d3fffe 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1029,12 +1029,6 @@ static IrInstruction *ir_create_const_fn(IrBuilder *irb, Scope *scope, AstNode * return &const_instruction->base; } -static IrInstruction *ir_build_const_fn(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigFn *fn_entry) { - IrInstruction *instruction = ir_create_const_fn(irb, scope, source_node, fn_entry); - ir_instruction_append(irb->current_basic_block, instruction); - return instruction; -} - static IrInstruction *ir_build_const_import(IrBuilder *irb, Scope *scope, AstNode *source_node, ImportTableEntry *import) { IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, source_node); const_instruction->base.value.type = irb->codegen->builtin_types.entry_namespace; @@ -1043,16 +1037,6 @@ static IrInstruction *ir_build_const_import(IrBuilder *irb, Scope *scope, AstNod return &const_instruction->base; } -static IrInstruction *ir_build_const_scope(IrBuilder *irb, Scope *parent_scope, AstNode *source_node, - Scope *target_scope) -{ - IrInstructionConst *const_instruction = ir_build_instruction(irb, parent_scope, source_node); - const_instruction->base.value.type = irb->codegen->builtin_types.entry_block; - const_instruction->base.value.special = ConstValSpecialStatic; - const_instruction->base.value.data.x_block = target_scope; - return &const_instruction->base; -} - static IrInstruction *ir_build_const_bool(IrBuilder *irb, Scope *scope, AstNode *source_node, bool value) { IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, source_node); const_instruction->base.value.type = irb->codegen->builtin_types.entry_bool; @@ -3892,6 +3876,21 @@ static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode * return ir_build_overflow_op(irb, scope, node, op, type_value, op1, op2, result_ptr, nullptr); } +static IrInstruction *ir_gen_this(IrBuilder *irb, Scope *orig_scope, AstNode *node) { + for (Scope *it_scope = orig_scope; it_scope != nullptr; it_scope = it_scope->parent) { + if (it_scope->id == ScopeIdDecls) { + ScopeDecls *decls_scope = (ScopeDecls *)it_scope; + ZigType *container_type = decls_scope->container_type; + if (container_type != nullptr) { + return ir_build_const_type(irb, orig_scope, node, container_type); + } else { + return ir_build_const_import(irb, orig_scope, node, decls_scope->import); + } + } + } + zig_unreachable(); +} + static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) { assert(node->type == NodeTypeFnCallExpr); @@ -4830,6 +4829,11 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *opaque_type = ir_build_opaque_type(irb, scope, node); return ir_lval_wrap(irb, scope, opaque_type, lval); } + case BuiltinFnIdThis: + { + IrInstruction *this_inst = ir_gen_this(irb, scope, node); + return ir_lval_wrap(irb, scope, this_inst, lval); + } case BuiltinFnIdSetAlignStack: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); @@ -5681,33 +5685,6 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo return ir_build_phi(irb, parent_scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items); } -static IrInstruction *ir_gen_this_literal(IrBuilder *irb, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeThisLiteral); - - if (!scope->parent) - return ir_build_const_import(irb, scope, node, node->owner); - - ZigFn *fn_entry = scope_get_fn_if_root(scope); - if (fn_entry) - return ir_build_const_fn(irb, scope, node, fn_entry); - - while (scope->id != ScopeIdBlock && scope->id != ScopeIdDecls) { - scope = scope->parent; - } - - if (scope->id == ScopeIdDecls) { - ScopeDecls *decls_scope = (ScopeDecls *)scope; - ZigType *container_type = decls_scope->container_type; - assert(container_type); - return ir_build_const_type(irb, scope, node, container_type); - } - - if (scope->id == ScopeIdBlock) - return ir_build_const_scope(irb, scope, node, scope); - - zig_unreachable(); -} - static IrInstruction *ir_gen_bool_literal(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeBoolLiteral); return ir_build_const_bool(irb, scope, node, node->data.bool_literal.value); @@ -7285,8 +7262,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop return ir_build_load_ptr(irb, scope, node, unwrapped_ptr); } - case NodeTypeThisLiteral: - return ir_lval_wrap(irb, scope, ir_gen_this_literal(irb, scope, node), lval); case NodeTypeBoolLiteral: return ir_lval_wrap(irb, scope, ir_gen_bool_literal(irb, scope, node), lval); case NodeTypeArrayType: @@ -11621,7 +11596,6 @@ static ZigType *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op case ZigTypeIdFn: case ZigTypeIdOpaque: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdPromise: @@ -12822,7 +12796,6 @@ static ZigType *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructionExpor case ZigTypeIdErrorUnion: case ZigTypeIdErrorSet: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdOpaque: @@ -12847,7 +12820,6 @@ static ZigType *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructionExpor case ZigTypeIdErrorSet: zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name)); case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdOpaque: @@ -13905,7 +13877,6 @@ static ZigType *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_instru case ZigTypeIdUnion: case ZigTypeIdFn: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdPromise: @@ -15263,7 +15234,6 @@ static ZigType *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructionTypeO case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdBoundFn: case ZigTypeIdMetaType: case ZigTypeIdVoid: @@ -15516,7 +15486,6 @@ static ZigType *ir_analyze_instruction_slice_type(IrAnalyze *ira, case ZigTypeIdUnreachable: case ZigTypeIdUndefined: case ZigTypeIdNull: - case ZigTypeIdBlock: case ZigTypeIdArgTuple: case ZigTypeIdOpaque: ir_add_error_node(ira, slice_type_instruction->base.source_node, @@ -15627,7 +15596,6 @@ static ZigType *ir_analyze_instruction_array_type(IrAnalyze *ira, case ZigTypeIdUnreachable: case ZigTypeIdUndefined: case ZigTypeIdNull: - case ZigTypeIdBlock: case ZigTypeIdArgTuple: case ZigTypeIdOpaque: ir_add_error_node(ira, array_type_instruction->base.source_node, @@ -15698,7 +15666,6 @@ static ZigType *ir_analyze_instruction_size_of(IrAnalyze *ira, case ZigTypeIdUnreachable: case ZigTypeIdUndefined: case ZigTypeIdNull: - case ZigTypeIdBlock: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: case ZigTypeIdBoundFn: @@ -16184,7 +16151,6 @@ static ZigType *ir_analyze_instruction_switch_target(IrAnalyze *ira, case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdOptional: - case ZigTypeIdBlock: case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdOpaque: @@ -16705,7 +16671,6 @@ static ZigType *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_instruc case ZigTypeIdUnion: case ZigTypeIdFn: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdOpaque: @@ -17368,7 +17333,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdArgTuple: case ZigTypeIdOpaque: *out = nullptr; @@ -19341,7 +19305,6 @@ static ZigType *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstructionAli case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdVoid: @@ -20102,7 +20065,6 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdUnreachable: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: @@ -20169,7 +20131,6 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdUnreachable: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: @@ -20249,7 +20210,6 @@ static ZigType *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstructionBit case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdUnreachable: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: @@ -20275,7 +20235,6 @@ static ZigType *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstructionBit case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdNamespace: - case ZigTypeIdBlock: case ZigTypeIdUnreachable: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: diff --git a/src/parser.cpp b/src/parser.cpp index 453ab7ce2c..8e6076c5e5 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -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); diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 1d3db5567a..84d1d90518 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -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"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index 75c7feb476..cae6835d0f 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -87,7 +87,6 @@ enum TokenId { TokenIdKeywordSuspend, TokenIdKeywordSwitch, TokenIdKeywordTest, - TokenIdKeywordThis, TokenIdKeywordTrue, TokenIdKeywordTry, TokenIdKeywordUndefined, diff --git a/std/array_list.zig b/std/array_list.zig index dda6f176eb..3ee425fe14 100644 --- a/std/array_list.zig +++ b/std/array_list.zig @@ -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 diff --git a/std/atomic/int.zig b/std/atomic/int.zig index 4103d52719..6e07ef571a 100644 --- a/std/atomic/int.zig +++ b/std/atomic/int.zig @@ -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 }; diff --git a/std/atomic/queue.zig b/std/atomic/queue.zig index 6948af43ba..c1e2a4c98b 100644 --- a/std/atomic/queue.zig +++ b/std/atomic/queue.zig @@ -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 { diff --git a/std/atomic/stack.zig b/std/atomic/stack.zig index 16d5c9503b..71896c66df 100644 --- a/std/atomic/stack.zig +++ b/std/atomic/stack.zig @@ -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, diff --git a/std/build.zig b/std/build.zig index 5800e69c62..f9fed6ad2f 100644 --- a/std/build.zig +++ b/std/build.zig @@ -1890,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) { diff --git a/std/crypto/blake2.zig b/std/crypto/blake2.zig index 467ddde5db..dc68d806d2 100644 --- a/std/crypto/blake2.zig +++ b/std/crypto/blake2.zig @@ -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; diff --git a/std/crypto/hmac.zig b/std/crypto/hmac.zig index 23eeff2a00..996c96062c 100644 --- a/std/crypto/hmac.zig +++ b/std/crypto/hmac.zig @@ -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; diff --git a/std/crypto/md5.zig b/std/crypto/md5.zig index 20334ec7d8..8663fa751f 100644 --- a/std/crypto/md5.zig +++ b/std/crypto/md5.zig @@ -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; diff --git a/std/crypto/poly1305.zig b/std/crypto/poly1305.zig index f5e11fc0a1..a5d9fcdf57 100644 --- a/std/crypto/poly1305.zig +++ b/std/crypto/poly1305.zig @@ -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; diff --git a/std/crypto/sha1.zig b/std/crypto/sha1.zig index 6d6b4dbd3f..1cb0b17434 100644 --- a/std/crypto/sha1.zig +++ b/std/crypto/sha1.zig @@ -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; diff --git a/std/crypto/sha2.zig b/std/crypto/sha2.zig index 8a25fecc43..7e9749364b 100644 --- a/std/crypto/sha2.zig +++ b/std/crypto/sha2.zig @@ -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; diff --git a/std/crypto/sha3.zig b/std/crypto/sha3.zig index 827bbd0680..881370e686 100644 --- a/std/crypto/sha3.zig +++ b/std/crypto/sha3.zig @@ -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; diff --git a/std/event/channel.zig b/std/event/channel.zig index 9ea75a2dd8..133ce1c69c 100644 --- a/std/event/channel.zig +++ b/std/event/channel.zig @@ -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, diff --git a/std/event/fs.zig b/std/event/fs.zig index 5635471212..bde5a306b6 100644 --- a/std/event/fs.zig +++ b/std/event/fs.zig @@ -724,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, diff --git a/std/event/future.zig b/std/event/future.zig index 8abdce7d02..d61768b198 100644 --- a/std/event/future.zig +++ b/std/event/future.zig @@ -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 { diff --git a/std/event/group.zig b/std/event/group.zig index 2b5a517b2f..0bb3298cf8 100644 --- a/std/event/group.zig +++ b/std/event/group.zig @@ -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, diff --git a/std/event/locked.zig b/std/event/locked.zig index 7df56c4571..6718b1bf9c 100644 --- a/std/event/locked.zig +++ b/std/event/locked.zig @@ -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, diff --git a/std/event/rwlocked.zig b/std/event/rwlocked.zig index 1a6e77c27a..d305b1791e 100644 --- a/std/event/rwlocked.zig +++ b/std/event/rwlocked.zig @@ -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, diff --git a/std/event/tcp.zig b/std/event/tcp.zig index 69b143dda0..5715e46a62 100644 --- a/std/event/tcp.zig +++ b/std/event/tcp.zig @@ -132,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 diff --git a/std/fmt/index.zig b/std/fmt/index.zig index 80af750f3d..14c944e9d5 100644 --- a/std/fmt/index.zig +++ b/std/fmt/index.zig @@ -1183,7 +1183,7 @@ test "fmt.format" { //custom type format { const Vec2 = struct { - const SelfType = this; + const SelfType = @This(); x: f32, y: f32, diff --git a/std/hash/crc.zig b/std/hash/crc.zig index c455140785..c4bd92884a 100644 --- a/std/hash/crc.zig +++ b/std/hash/crc.zig @@ -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; diff --git a/std/hash/fnv.zig b/std/hash/fnv.zig index 447c996772..9bb18f14b3 100644 --- a/std/hash/fnv.zig +++ b/std/hash/fnv.zig @@ -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, diff --git a/std/hash/siphash.zig b/std/hash/siphash.zig index cdad77e59e..0fe958c38b 100644 --- a/std/hash/siphash.zig +++ b/std/hash/siphash.zig @@ -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; diff --git a/std/hash_map.zig b/std/hash_map.zig index 9654d612a5..1b299eff78 100644 --- a/std/hash_map.zig +++ b/std/hash_map.zig @@ -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, diff --git a/std/heap.zig b/std/heap.zig index f5e0484b25..58a9961d79 100644 --- a/std/heap.zig +++ b/std/heap.zig @@ -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, diff --git a/std/io.zig b/std/io.zig index 2b31bc0548..c10fdcbbe2 100644 --- a/std/io.zig +++ b/std/io.zig @@ -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; diff --git a/std/lazy_init.zig b/std/lazy_init.zig index c46c067810..f08c01e874 100644 --- a/std/lazy_init.zig +++ b/std/lazy_init.zig @@ -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; diff --git a/std/linked_list.zig b/std/linked_list.zig index 130ddbce5d..46cbeb03c4 100644 --- a/std/linked_list.zig +++ b/std/linked_list.zig @@ -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 { diff --git a/std/math/complex/index.zig b/std/math/complex/index.zig index 63a2616984..171c4c5829 100644 --- a/std/math/complex/index.zig +++ b/std/math/complex/index.zig @@ -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, diff --git a/std/mem.zig b/std/mem.zig index 4390f8ad5b..dd5adc06c2 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -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}; diff --git a/std/net.zig b/std/net.zig index 8c1aeb92d7..c20435893a 100644 --- a/std/net.zig +++ b/std/net.zig @@ -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; diff --git a/std/os/index.zig b/std/os/index.zig index 8e92fc23c5..d4110bd759 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -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"); diff --git a/std/segmented_list.zig b/std/segmented_list.zig index c6d8effdd2..93942dde9b 100644 --- a/std/segmented_list.zig +++ b/std/segmented_list.zig @@ -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); diff --git a/std/zig/ast.zig b/std/zig/ast.zig index 0046dff1a2..9ca77d4950 100644 --- a/std/zig/ast.zig +++ b/std/zig/ast.zig @@ -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, diff --git a/std/zig/parser_test.zig b/std/zig/parser_test.zig index 7f3ce7bd8a..3cee9b98dd 100644 --- a/std/zig/parser_test.zig +++ b/std/zig/parser_test.zig @@ -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, \\ diff --git a/std/zig/render.zig b/std/zig/render.zig index 868902a0d1..050f172ae8 100644 --- a/std/zig/render.zig +++ b/std/zig/render.zig @@ -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); diff --git a/test/cases/cast.zig b/test/cases/cast.zig index 94fbda7899..e2b67f036d 100644 --- a/test/cases/cast.zig +++ b/test/cases/cast.zig @@ -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; diff --git a/test/cases/eval.zig b/test/cases/eval.zig index 4286821183..7e9c9a739d 100644 --- a/test/cases/eval.zig +++ b/test/cases/eval.zig @@ -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; } }; diff --git a/test/cases/misc.zig b/test/cases/misc.zig index 1c0189571b..4343cb3b90 100644 --- a/test/cases/misc.zig +++ b/test/cases/misc.zig @@ -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 diff --git a/test/cases/reflection.zig b/test/cases/reflection.zig index 3d3af3c889..677fd90192 100644 --- a/test/cases/reflection.zig +++ b/test/cases/reflection.zig @@ -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 { diff --git a/test/cases/struct.zig b/test/cases/struct.zig index 20d46999d5..163c69e670 100644 --- a/test/cases/struct.zig +++ b/test/cases/struct.zig @@ -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; } }; diff --git a/test/cases/this.zig b/test/cases/this.zig index ba51d0ac90..c7be074f36 100644 --- a/test/cases/this.zig +++ b/test/cases/this.zig @@ -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); -} diff --git a/test/cases/type_info.zig b/test/cases/type_info.zig index b8fc4cf14e..6f99268c08 100644 --- a/test/cases/type_info.zig +++ b/test/cases/type_info.zig @@ -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, diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 750794c909..6bdbca9ff5 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -3813,11 +3813,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return struct { \\ b: B(), \\ - \\ const Self = this; + \\ const Self = @This(); \\ \\ fn B() type { \\ return struct { - \\ const Self = this; + \\ const Self = @This(); \\ }; \\ } \\ }; @@ -4314,12 +4314,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var a = undefined; \\ var b = 1; \\ var c = 1.0; - \\ var d = this; - \\ var e = null; - \\ var f = opaque.*; - \\ var g = i32; - \\ var h = @import("std",); - \\ var i = (Foo {}).bar; + \\ var d = null; + \\ var e = opaque.*; + \\ var f = i32; + \\ var g = @import("std",); + \\ var h = (Foo {}).bar; \\ \\ var z: noreturn = return; \\} @@ -4332,13 +4331,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { ".tmp_source.zig:7:4: error: variable of type '(undefined)' must be const or comptime", ".tmp_source.zig:8:4: error: variable of type 'comptime_int' must be const or comptime", ".tmp_source.zig:9:4: error: variable of type 'comptime_float' must be const or comptime", - ".tmp_source.zig:10:4: error: variable of type '(block)' must be const or comptime", - ".tmp_source.zig:11:4: error: variable of type '(null)' must be const or comptime", - ".tmp_source.zig:12:4: error: variable of type 'Opaque' not allowed", - ".tmp_source.zig:13:4: error: variable of type 'type' must be const or comptime", - ".tmp_source.zig:14:4: error: variable of type '(namespace)' must be const or comptime", - ".tmp_source.zig:15:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime", - ".tmp_source.zig:17:4: error: unreachable code", + ".tmp_source.zig:10:4: error: variable of type '(null)' must be const or comptime", + ".tmp_source.zig:11:4: error: variable of type 'Opaque' not allowed", + ".tmp_source.zig:12:4: error: variable of type 'type' must be const or comptime", + ".tmp_source.zig:13:4: error: variable of type '(namespace)' must be const or comptime", + ".tmp_source.zig:14:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime", + ".tmp_source.zig:16:4: error: unreachable code", ); cases.add( -- cgit v1.2.3 From 1e03cf1739c9c7407c4b3a56ee5f2705805c6a83 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 13 Sep 2018 19:12:25 -0400 Subject: fix assertion failure on compile-time `@intToPtr` of function --- src/codegen.cpp | 13 ++++++++++--- test/cases/cast.zig | 11 +++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 86ede7411d..d7d7223657 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5886,9 +5886,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: diff --git a/test/cases/cast.zig b/test/cases/cast.zig index e2b67f036d..db482a124a 100644 --- a/test/cases/cast.zig +++ b/test/cases/cast.zig @@ -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)); +} -- cgit v1.2.3 From 3d38feded93cb2ccecf5ecb538c8957a965a891e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 14 Sep 2018 00:37:54 -0400 Subject: fix tagged union with all void payloads but meaningful tag closes #1322 --- src/codegen.cpp | 2 +- test/behavior.zig | 1 + test/cases/bugs/1322.zig | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 test/cases/bugs/1322.zig (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index d7d7223657..98bb06e6ee 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4715,7 +4715,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)) @@ -4725,6 +4724,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); diff --git a/test/behavior.zig b/test/behavior.zig index 869024f296..3223131d08 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -10,6 +10,7 @@ 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"); diff --git a/test/cases/bugs/1322.zig b/test/cases/bugs/1322.zig new file mode 100644 index 0000000000..2de92191ec --- /dev/null +++ b/test/cases/bugs/1322.zig @@ -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); +} -- cgit v1.2.3 From 3f776af3fa58b47d15a81b17c15e5b0e1c5ccf28 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 14 Sep 2018 18:56:30 -0400 Subject: fix alignment of structs closes #1248 closes #1052 closes #1154 --- src/all_types.hpp | 47 +++--- src/analyze.cpp | 387 +++++++++++++++++++++++++++--------------------- src/analyze.hpp | 4 +- src/codegen.cpp | 19 ++- src/ir.cpp | 376 +++++++++++++++++++++++++++++++--------------- std/debug/index.zig | 6 +- test/cases/align.zig | 7 + test/compile_errors.zig | 2 +- 8 files changed, 524 insertions(+), 324 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index fefbae0fe3..ed1dcb1f9b 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1012,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 { @@ -1046,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; - 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 - bool is_slice; ScopeDecls *decls_scope; + uint64_t size_bytes; + HashMap fields_by_name; - // set this flag temporarily to detect infinite loops - bool embedded_in_current; - bool reported_infinite_err; - // whether we've finished resolving it - bool complete; + uint32_t src_field_count; + uint32_t gen_field_count; + + uint32_t abi_alignment; // known after ResolveStatusAlignmentKnown + ContainerLayout layout; + ResolveStatus resolve_status; + bool is_slice; + bool resolve_loop_flag; // set this flag temporarily to detect infinite loops + bool reported_infinite_err; // 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 fields_by_name; }; struct ZigTypeOptional { diff --git a/src/analyze.cpp b/src/analyze.cpp index d403433c5c..c9ae865390 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -23,6 +23,7 @@ static Error resolve_enum_type(CodeGen *g, ZigType *enum_type); static Error resolve_struct_type(CodeGen *g, ZigType *struct_type); static Error ATTRIBUTE_MUST_USE resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type); +static Error ATTRIBUTE_MUST_USE resolve_struct_alignment(CodeGen *g, ZigType *struct_type); static Error ATTRIBUTE_MUST_USE resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type); static Error ATTRIBUTE_MUST_USE resolve_union_zero_bits(CodeGen *g, ZigType *union_type); static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry); @@ -254,18 +255,42 @@ AstNode *type_decl_node(ZigType *type_entry) { zig_unreachable(); } -bool type_is_complete(ZigType *type_entry) { +bool type_is_resolved(ZigType *type_entry, ResolveStatus status) { switch (type_entry->id) { case ZigTypeIdInvalid: zig_unreachable(); case ZigTypeIdStruct: - return type_entry->data.structure.complete; + return type_entry->data.structure.resolve_status >= status; case ZigTypeIdEnum: - return type_entry->data.enumeration.complete; + switch (status) { + case ResolveStatusUnstarted: + return true; + case ResolveStatusInvalid: + zig_unreachable(); + case ResolveStatusZeroBitsKnown: + return type_entry->data.enumeration.zero_bits_known; + case ResolveStatusAlignmentKnown: + return type_entry->data.enumeration.zero_bits_known; + case ResolveStatusSizeKnown: + return type_entry->data.enumeration.complete; + } + zig_unreachable(); case ZigTypeIdUnion: - return type_entry->data.unionation.complete; + switch (status) { + case ResolveStatusUnstarted: + return true; + case ResolveStatusInvalid: + zig_unreachable(); + case ResolveStatusZeroBitsKnown: + return type_entry->data.unionation.zero_bits_known; + case ResolveStatusAlignmentKnown: + return type_entry->data.unionation.zero_bits_known; + case ResolveStatusSizeKnown: + return type_entry->data.unionation.complete; + } + zig_unreachable(); case ZigTypeIdOpaque: - return false; + return status < ResolveStatusSizeKnown; case ZigTypeIdMetaType: case ZigTypeIdVoid: case ZigTypeIdBool: @@ -291,43 +316,10 @@ bool type_is_complete(ZigType *type_entry) { zig_unreachable(); } -bool type_has_zero_bits_known(ZigType *type_entry) { - switch (type_entry->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdStruct: - return type_entry->data.structure.zero_bits_known; - case ZigTypeIdEnum: - return type_entry->data.enumeration.zero_bits_known; - case ZigTypeIdUnion: - return type_entry->data.unionation.zero_bits_known; - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdArray: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdFn: - case ZigTypeIdNamespace: - case ZigTypeIdBoundFn: - case ZigTypeIdArgTuple: - case ZigTypeIdOpaque: - case ZigTypeIdPromise: - return true; - } - zig_unreachable(); +bool type_is_complete(ZigType *type_entry) { + return type_is_resolved(type_entry, ResolveStatusSizeKnown); } - uint64_t type_size(CodeGen *g, ZigType *type_entry) { assert(type_is_complete(type_entry)); @@ -376,7 +368,7 @@ uint64_t type_size_bits(CodeGen *g, ZigType *type_entry) { Result type_is_copyable(CodeGen *g, ZigType *type_entry) { Error err; - if ((err = type_ensure_zero_bits_known(g, type_entry))) + if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) return err; if (!type_has_bits(type_entry)) @@ -431,10 +423,15 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons assert(!type_is_invalid(child_type)); assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque); + if (byte_alignment != 0) { + uint32_t abi_alignment = get_abi_alignment(g, child_type); + if (byte_alignment == abi_alignment) + byte_alignment = 0; + } + TypeId type_id = {}; ZigType **parent_pointer = nullptr; - uint32_t abi_alignment = get_abi_alignment(g, child_type); - if (unaligned_bit_count != 0 || is_volatile || byte_alignment != abi_alignment || ptr_len != PtrLenSingle) { + if (unaligned_bit_count != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle) { type_id.id = ZigTypeIdPointer; type_id.data.pointer.child_type = child_type; type_id.data.pointer.is_const = is_const; @@ -451,12 +448,12 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons assert(bit_offset == 0); parent_pointer = &child_type->pointer_parent[(is_const ? 1 : 0)]; if (*parent_pointer) { - assert((*parent_pointer)->data.pointer.alignment == byte_alignment); + assert((*parent_pointer)->data.pointer.explicit_alignment == 0); return *parent_pointer; } } - assertNoError(type_ensure_zero_bits_known(g, child_type)); + assert(type_is_resolved(child_type, ResolveStatusZeroBitsKnown)); ZigType *entry = new_type_table_entry(ZigTypeIdPointer); entry->is_copyable = true; @@ -465,11 +462,14 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons const char *const_str = is_const ? "const " : ""; const char *volatile_str = is_volatile ? "volatile " : ""; buf_resize(&entry->name, 0); - if (unaligned_bit_count == 0 && byte_alignment == abi_alignment) { + if (unaligned_bit_count == 0 && byte_alignment == 0) { buf_appendf(&entry->name, "%s%s%s%s", star_str, const_str, volatile_str, buf_ptr(&child_type->name)); } else if (unaligned_bit_count == 0) { buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s", star_str, byte_alignment, const_str, volatile_str, buf_ptr(&child_type->name)); + } else if (byte_alignment == 0) { + buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str, + bit_offset, bit_offset + unaligned_bit_count, const_str, volatile_str, buf_ptr(&child_type->name)); } else { buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str, byte_alignment, bit_offset, bit_offset + unaligned_bit_count, const_str, volatile_str, buf_ptr(&child_type->name)); @@ -480,8 +480,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons entry->zero_bits = !type_has_bits(child_type); if (!entry->zero_bits) { - assert(byte_alignment > 0); - if (is_const || is_volatile || unaligned_bit_count != 0 || byte_alignment != abi_alignment || + if (is_const || is_volatile || unaligned_bit_count != 0 || byte_alignment != 0 || ptr_len != PtrLenSingle) { ZigType *peer_type = get_pointer_to_type(g, child_type, false); @@ -505,7 +504,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons entry->data.pointer.child_type = child_type; entry->data.pointer.is_const = is_const; entry->data.pointer.is_volatile = is_volatile; - entry->data.pointer.alignment = byte_alignment; + entry->data.pointer.explicit_alignment = byte_alignment; entry->data.pointer.bit_offset = bit_offset; entry->data.pointer.unaligned_bit_count = unaligned_bit_count; @@ -518,8 +517,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons } ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const) { - return get_pointer_to_type_extra(g, child_type, is_const, false, PtrLenSingle, - get_abi_alignment(g, child_type), 0, 0); + return get_pointer_to_type_extra(g, child_type, is_const, false, PtrLenSingle, 0, 0, 0); } ZigType *get_promise_frame_type(CodeGen *g, ZigType *return_type) { @@ -800,8 +798,7 @@ static void slice_type_common_init(CodeGen *g, ZigType *pointer_type, ZigType *e entry->data.structure.fields_by_name.put(ptr_field_name, &entry->data.structure.fields[slice_ptr_index]); entry->data.structure.fields_by_name.put(len_field_name, &entry->data.structure.fields[slice_len_index]); - assert(type_has_zero_bits_known(pointer_type->data.pointer.child_type)); - if (pointer_type->data.pointer.child_type->zero_bits) { + if (!type_has_bits(pointer_type->data.pointer.child_type)) { entry->data.structure.gen_field_count = 1; entry->data.structure.fields[slice_ptr_index].gen_index = SIZE_MAX; entry->data.structure.fields[slice_len_index].gen_index = 0; @@ -826,20 +823,18 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) { buf_appendf(&entry->name, "[]%s", buf_ptr(&ptr_type->name) + name_offset); ZigType *child_type = ptr_type->data.pointer.child_type; - uint32_t abi_alignment = get_abi_alignment(g, child_type); if (ptr_type->data.pointer.is_const || ptr_type->data.pointer.is_volatile || - ptr_type->data.pointer.alignment != abi_alignment) + ptr_type->data.pointer.explicit_alignment != 0) { ZigType *peer_ptr_type = get_pointer_to_type_extra(g, child_type, false, false, - PtrLenUnknown, abi_alignment, 0, 0); + PtrLenUnknown, 0, 0, 0); ZigType *peer_slice_type = get_slice_type(g, peer_ptr_type); slice_type_common_init(g, ptr_type, entry); entry->type_ref = peer_slice_type->type_ref; entry->di_type = peer_slice_type->di_type; - entry->data.structure.complete = true; - entry->data.structure.zero_bits_known = true; + entry->data.structure.resolve_status = ResolveStatusSizeKnown; entry->data.structure.abi_alignment = peer_slice_type->data.structure.abi_alignment; *parent_pointer = entry; @@ -851,15 +846,15 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) { if (is_slice(child_type)) { ZigType *child_ptr_type = child_type->data.structure.fields[slice_ptr_index].type_entry; assert(child_ptr_type->id == ZigTypeIdPointer); - ZigType *grand_child_type = child_ptr_type->data.pointer.child_type; if (child_ptr_type->data.pointer.is_const || child_ptr_type->data.pointer.is_volatile || - child_ptr_type->data.pointer.alignment != get_abi_alignment(g, grand_child_type)) + child_ptr_type->data.pointer.explicit_alignment != 0) { + ZigType *grand_child_type = child_ptr_type->data.pointer.child_type; ZigType *bland_child_ptr_type = get_pointer_to_type_extra(g, grand_child_type, false, false, - PtrLenUnknown, get_abi_alignment(g, grand_child_type), 0, 0); + PtrLenUnknown, 0, 0, 0); ZigType *bland_child_slice = get_slice_type(g, bland_child_ptr_type); ZigType *peer_ptr_type = get_pointer_to_type_extra(g, bland_child_slice, false, false, - PtrLenUnknown, get_abi_alignment(g, bland_child_slice), 0, 0); + PtrLenUnknown, 0, 0, 0); ZigType *peer_slice_type = get_slice_type(g, peer_ptr_type); entry->type_ref = peer_slice_type->type_ref; @@ -961,8 +956,7 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) { } - entry->data.structure.complete = true; - entry->data.structure.zero_bits_known = true; + entry->data.structure.resolve_status = ResolveStatusSizeKnown; *parent_pointer = entry; return entry; @@ -1367,7 +1361,7 @@ static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf **out_buffer) { ZigType *ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, - PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0); + PtrLenUnknown, 0, 0, 0); ZigType *str_type = get_slice_type(g, ptr_type); IrInstruction *instr = analyze_const_value(g, scope, node, str_type, nullptr); if (type_is_invalid(instr->value.type)) @@ -1576,7 +1570,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc return g->builtin_types.entry_invalid; } if (!calling_convention_allows_zig_types(fn_type_id.cc)) { - if ((err = type_ensure_zero_bits_known(g, type_entry))) + if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) return g->builtin_types.entry_invalid; if (!type_has_bits(type_entry)) { add_node_error(g, param_node->data.param_decl.type, @@ -1624,7 +1618,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc case ZigTypeIdUnion: case ZigTypeIdFn: case ZigTypeIdPromise: - if ((err = type_ensure_zero_bits_known(g, type_entry))) + if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) return g->builtin_types.entry_invalid; if (type_requires_comptime(type_entry)) { add_node_error(g, param_node->data.param_decl.type, @@ -1714,7 +1708,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc case ZigTypeIdUnion: case ZigTypeIdFn: case ZigTypeIdPromise: - if ((err = type_ensure_zero_bits_known(g, fn_type_id.return_type))) + if ((err = type_resolve(g, fn_type_id.return_type, ResolveStatusZeroBitsKnown))) return g->builtin_types.entry_invalid; if (type_requires_comptime(fn_type_id.return_type)) { return get_generic_fn_type(g, &fn_type_id); @@ -1740,7 +1734,7 @@ bool type_is_invalid(ZigType *type_entry) { case ZigTypeIdInvalid: return true; case ZigTypeIdStruct: - return type_entry->data.structure.is_invalid; + return type_entry->data.structure.resolve_status == ResolveStatusInvalid; case ZigTypeIdEnum: return type_entry->data.enumeration.is_invalid; case ZigTypeIdUnion: @@ -1855,8 +1849,7 @@ ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_na struct_type->data.structure.src_field_count = field_count; struct_type->data.structure.gen_field_count = 0; - struct_type->data.structure.zero_bits_known = true; - struct_type->data.structure.complete = true; + struct_type->data.structure.resolve_status = ResolveStatusSizeKnown; struct_type->data.structure.fields = allocate(field_count); struct_type->data.structure.fields_by_name.init(field_count); @@ -1928,26 +1921,29 @@ ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_na static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { assert(struct_type->id == ZigTypeIdStruct); - if (struct_type->data.structure.complete) + Error err; + + if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) + return ErrorSemanticAnalyzeFail; + if (struct_type->data.structure.resolve_status >= ResolveStatusSizeKnown) return ErrorNone; - Error err; - if ((err = resolve_struct_zero_bits(g, struct_type))) + if ((err = resolve_struct_alignment(g, struct_type))) return err; AstNode *decl_node = struct_type->data.structure.decl_node; - if (struct_type->data.structure.embedded_in_current) { - struct_type->data.structure.is_invalid = true; - if (!struct_type->data.structure.reported_infinite_err) { - struct_type->data.structure.reported_infinite_err = true; + if (struct_type->data.structure.resolve_loop_flag) { + if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { + struct_type->data.structure.resolve_status = ResolveStatusInvalid; add_node_error(g, decl_node, - buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name))); + buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name))); } return ErrorSemanticAnalyzeFail; } - assert(!struct_type->data.structure.zero_bits_loop_flag); + struct_type->data.structure.resolve_loop_flag = true; + assert(struct_type->data.structure.fields || struct_type->data.structure.src_field_count == 0); assert(decl_node->type == NodeTypeContainerDecl); @@ -1956,9 +1952,6 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { size_t gen_field_count = struct_type->data.structure.gen_field_count; LLVMTypeRef *element_types = allocate(gen_field_count); - // this field should be set to true only during the recursive calls to resolve_struct_type - struct_type->data.structure.embedded_in_current = true; - Scope *scope = &struct_type->data.structure.decls_scope->base; size_t gen_field_index = 0; @@ -1972,7 +1965,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { ZigType *field_type = type_struct_field->type_entry; if ((err = ensure_complete_type(g, field_type))) { - struct_type->data.structure.is_invalid = true; + struct_type->data.structure.resolve_status = ResolveStatusInvalid; break; } @@ -1982,7 +1975,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { add_node_error(g, field_source_node, buf_sprintf("extern structs cannot contain fields of type '%s'", buf_ptr(&field_type->name))); - struct_type->data.structure.is_invalid = true; + struct_type->data.structure.resolve_status = ResolveStatusInvalid; break; } } @@ -1998,7 +1991,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { add_node_error(g, field_source_node, buf_sprintf("packed structs cannot contain fields of type '%s'", buf_ptr(&field_type->name))); - struct_type->data.structure.is_invalid = true; + struct_type->data.structure.resolve_status = ResolveStatusInvalid; break; } @@ -2049,12 +2042,13 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { gen_field_index += 1; } - struct_type->data.structure.embedded_in_current = false; - struct_type->data.structure.complete = true; + struct_type->data.structure.resolve_loop_flag = false; - if (struct_type->data.structure.is_invalid) + if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) return ErrorSemanticAnalyzeFail; + struct_type->data.structure.resolve_status = ResolveStatusSizeKnown; + if (struct_type->zero_bits) { struct_type->type_ref = LLVMVoidType(); @@ -2116,7 +2110,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { assert(field_type->type_ref); assert(struct_type->type_ref); - assert(struct_type->data.structure.complete); + assert(struct_type->data.structure.resolve_status == ResolveStatusSizeKnown); uint64_t debug_size_in_bits; uint64_t debug_align_in_bits; uint64_t debug_offset_in_bits; @@ -2570,30 +2564,18 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { Error err; - if (struct_type->data.structure.is_invalid) + if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) return ErrorSemanticAnalyzeFail; - - if (struct_type->data.structure.zero_bits_known) + if (struct_type->data.structure.resolve_status >= ResolveStatusZeroBitsKnown) return ErrorNone; - if (struct_type->data.structure.zero_bits_loop_flag) { - // If we get here it's due to recursion. This is a design flaw in the compiler, - // we should be able to still figure out alignment, but here we give up and say that - // the alignment is pointer width, then assert that the first field is within that - // alignment - struct_type->data.structure.zero_bits_known = true; - struct_type->data.structure.zero_bits_loop_flag = false; - if (struct_type->data.structure.abi_alignment == 0) { - if (struct_type->data.structure.layout == ContainerLayoutPacked) { - struct_type->data.structure.abi_alignment = 1; - } else { - struct_type->data.structure.abi_alignment = LLVMABIAlignmentOfType(g->target_data_ref, LLVMPointerType(LLVMInt8Type(), 0)); - } - } + if (struct_type->data.structure.resolve_loop_flag) { + struct_type->data.structure.resolve_status = ResolveStatusZeroBitsKnown; + struct_type->data.structure.resolve_loop_flag = false; return ErrorNone; } - struct_type->data.structure.zero_bits_loop_flag = true; + struct_type->data.structure.resolve_loop_flag = true; AstNode *decl_node = struct_type->data.structure.decl_node; assert(decl_node->type == NodeTypeContainerDecl); @@ -2616,7 +2598,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { if (field_node->data.struct_field.type == nullptr) { add_node_error(g, field_node, buf_sprintf("struct field missing type")); - struct_type->data.structure.is_invalid = true; + struct_type->data.structure.resolve_status = ResolveStatusInvalid; continue; } @@ -2625,7 +2607,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { ErrorMsg *msg = add_node_error(g, field_node, buf_sprintf("duplicate struct field: '%s'", buf_ptr(type_struct_field->name))); add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here")); - struct_type->data.structure.is_invalid = true; + struct_type->data.structure.resolve_status = ResolveStatusInvalid; continue; } @@ -2639,8 +2621,8 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { buf_sprintf("enums, not structs, support field assignment")); } - if ((err = type_ensure_zero_bits_known(g, field_type))) { - struct_type->data.structure.is_invalid = true; + if ((err = type_resolve(g, field_type, ResolveStatusZeroBitsKnown))) { + struct_type->data.structure.resolve_status = ResolveStatusInvalid; continue; } @@ -2651,36 +2633,87 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { if (!type_has_bits(field_type)) continue; - if (gen_field_index == 0) { - if (struct_type->data.structure.layout == ContainerLayoutPacked) { - struct_type->data.structure.abi_alignment = 1; - } else if (struct_type->data.structure.abi_alignment == 0) { - // Alignment of structs is the alignment of the first field, for now. - // TODO change this when we re-order struct fields (issue #168) - struct_type->data.structure.abi_alignment = get_abi_alignment(g, field_type); - assert(struct_type->data.structure.abi_alignment != 0); - } else { - // due to a design flaw in the compiler we assumed that alignment was - // pointer width, so we assert that this wasn't violated. - if (get_abi_alignment(g, field_type) > struct_type->data.structure.abi_alignment) { - zig_panic("compiler design flaw: incorrect alignment assumption"); - } - } - } - type_struct_field->gen_index = gen_field_index; gen_field_index += 1; } - struct_type->data.structure.zero_bits_loop_flag = false; + struct_type->data.structure.resolve_loop_flag = false; struct_type->data.structure.gen_field_count = (uint32_t)gen_field_index; struct_type->zero_bits = (gen_field_index == 0); - struct_type->data.structure.zero_bits_known = true; - if (struct_type->data.structure.is_invalid) { + if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) + return ErrorSemanticAnalyzeFail; + + struct_type->data.structure.resolve_status = ResolveStatusZeroBitsKnown; + return ErrorNone; +} + +static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { + assert(struct_type->id == ZigTypeIdStruct); + + Error err; + + if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) + return ErrorSemanticAnalyzeFail; + if (struct_type->data.structure.resolve_status >= ResolveStatusAlignmentKnown) + return ErrorNone; + + if ((err = resolve_struct_zero_bits(g, struct_type))) + return err; + + AstNode *decl_node = struct_type->data.structure.decl_node; + + if (struct_type->data.structure.resolve_loop_flag) { + if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { + struct_type->data.structure.resolve_status = ResolveStatusInvalid; + add_node_error(g, decl_node, + buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name))); + } return ErrorSemanticAnalyzeFail; } + struct_type->data.structure.resolve_loop_flag = true; + assert(decl_node->type == NodeTypeContainerDecl); + assert(struct_type->di_type); + + if (struct_type->data.structure.layout == ContainerLayoutPacked) { + struct_type->data.structure.abi_alignment = 1; + } + + size_t field_count = struct_type->data.structure.src_field_count; + for (size_t i = 0; i < field_count; i += 1) { + TypeStructField *field = &struct_type->data.structure.fields[i]; + + // If this assertion trips, look up the call stack. Probably something is + // calling type_resolve with ResolveStatusAlignmentKnown when it should only + // be resolving ResolveStatusZeroBitsKnown + assert(field->type_entry != nullptr); + + if (!type_has_bits(field->type_entry)) + continue; + + // alignment of structs is the alignment of the most-aligned field + if (struct_type->data.structure.layout != ContainerLayoutPacked) { + if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) { + struct_type->data.structure.resolve_status = ResolveStatusInvalid; + break; + } + + uint32_t this_field_align = get_abi_alignment(g, field->type_entry); + assert(this_field_align != 0); + if (this_field_align > struct_type->data.structure.abi_alignment) { + struct_type->data.structure.abi_alignment = this_field_align; + } + } + } + + struct_type->data.structure.resolve_loop_flag = false; + + if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) { + return ErrorSemanticAnalyzeFail; + } + + struct_type->data.structure.resolve_status = ResolveStatusAlignmentKnown; return ErrorNone; } @@ -2807,7 +2840,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name))); return ErrorSemanticAnalyzeFail; } - if ((err = type_ensure_zero_bits_known(g, enum_type))) { + if ((err = type_resolve(g, enum_type, ResolveStatusAlignmentKnown))) { assert(g->errors.length != 0); return err; } @@ -2848,7 +2881,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { } } else { field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type); - if ((err = type_ensure_zero_bits_known(g, field_type))) { + if ((err = type_resolve(g, field_type, ResolveStatusAlignmentKnown))) { union_type->data.unionation.is_invalid = true; continue; } @@ -3111,7 +3144,7 @@ static void typecheck_panic_fn(CodeGen *g, ZigFn *panic_fn) { return wrong_panic_prototype(g, proto_node, fn_type); } ZigType *const_u8_ptr = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, - PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0); + PtrLenUnknown, 0, 0, 0); ZigType *const_u8_slice = get_slice_type(g, const_u8_ptr); if (fn_type_id->param_info[0].type != const_u8_slice) { return wrong_panic_prototype(g, proto_node, fn_type); @@ -3801,7 +3834,7 @@ TypeEnumField *find_enum_type_field(ZigType *enum_type, Buf *name) { TypeStructField *find_struct_type_field(ZigType *type_entry, Buf *name) { assert(type_entry->id == ZigTypeIdStruct); - assert(type_entry->data.structure.complete); + assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown)); if (type_entry->data.structure.src_field_count == 0) return nullptr; auto entry = type_entry->data.structure.fields_by_name.maybe_get(name); @@ -3956,9 +3989,12 @@ bool type_is_codegen_pointer(ZigType *type) { uint32_t get_ptr_align(CodeGen *g, ZigType *type) { ZigType *ptr_type = get_codegen_ptr_type(type); if (ptr_type->id == ZigTypeIdPointer) { - return ptr_type->data.pointer.alignment; + return (ptr_type->data.pointer.explicit_alignment == 0) ? + get_abi_alignment(g, ptr_type->data.pointer.child_type) : ptr_type->data.pointer.explicit_alignment; } else if (ptr_type->id == ZigTypeIdFn) { - return (ptr_type->data.fn.fn_type_id.alignment == 0) ? 1 : ptr_type->data.fn.fn_type_id.alignment; + return (ptr_type->data.fn.fn_type_id.alignment == 0) ? + LLVMABIAlignmentOfType(g->target_data_ref, ptr_type->data.fn.raw_type_ref) : + ptr_type->data.fn.fn_type_id.alignment; } else if (ptr_type->id == ZigTypeIdPromise) { return get_coro_frame_align_bytes(g); } else { @@ -5023,8 +5059,8 @@ bool fn_eval_eql(Scope *a, Scope *b) { bool type_has_bits(ZigType *type_entry) { assert(type_entry); - assert(type_entry->id != ZigTypeIdInvalid); - assert(type_has_zero_bits_known(type_entry)); + assert(!type_is_invalid(type_entry)); + assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown)); return !type_entry->zero_bits; } @@ -5045,10 +5081,10 @@ bool type_requires_comptime(ZigType *type_entry) { case ZigTypeIdArray: return type_requires_comptime(type_entry->data.array.child_type); case ZigTypeIdStruct: - assert(type_has_zero_bits_known(type_entry)); + assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown)); return type_entry->data.structure.requires_comptime; case ZigTypeIdUnion: - assert(type_has_zero_bits_known(type_entry)); + assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown)); return type_entry->data.unionation.requires_comptime; case ZigTypeIdOptional: return type_requires_comptime(type_entry->data.maybe.child_type); @@ -5124,7 +5160,7 @@ void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) { const_val->special = ConstValSpecialStatic; // TODO make this `[*]null u8` instead of `[*]u8` const_val->type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, - PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0); + PtrLenUnknown, 0, 0, 0); const_val->data.x_ptr.special = ConstPtrSpecialBaseArray; const_val->data.x_ptr.data.base_array.array_val = array_val; const_val->data.x_ptr.data.base_array.elem_index = 0; @@ -5269,8 +5305,7 @@ void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *arr assert(array_val->type->id == ZigTypeIdArray); ZigType *ptr_type = get_pointer_to_type_extra(g, array_val->type->data.array.child_type, - is_const, false, PtrLenUnknown, get_abi_alignment(g, array_val->type->data.array.child_type), - 0, 0); + is_const, false, PtrLenUnknown, 0, 0, 0); const_val->special = ConstValSpecialStatic; const_val->type = get_slice_type(g, ptr_type); @@ -5295,7 +5330,7 @@ void init_const_ptr_array(CodeGen *g, ConstExprValue *const_val, ConstExprValue const_val->special = ConstValSpecialStatic; const_val->type = get_pointer_to_type_extra(g, child_type, is_const, false, - ptr_len, get_abi_alignment(g, child_type), 0, 0); + ptr_len, 0, 0, 0); const_val->data.x_ptr.special = ConstPtrSpecialBaseArray; const_val->data.x_ptr.data.base_array.array_val = array_val; const_val->data.x_ptr.data.base_array.elem_index = elem_index; @@ -5394,32 +5429,46 @@ ConstExprValue *create_const_vals(size_t count) { } Error ensure_complete_type(CodeGen *g, ZigType *type_entry) { - if (type_is_invalid(type_entry)) - return ErrorSemanticAnalyzeFail; - if (type_entry->id == ZigTypeIdStruct) { - if (!type_entry->data.structure.complete) - return resolve_struct_type(g, type_entry); - } else if (type_entry->id == ZigTypeIdEnum) { - if (!type_entry->data.enumeration.complete) - return resolve_enum_type(g, type_entry); - } else if (type_entry->id == ZigTypeIdUnion) { - if (!type_entry->data.unionation.complete) - return resolve_union_type(g, type_entry); - } - return ErrorNone; + return type_resolve(g, type_entry, ResolveStatusSizeKnown); } -Error type_ensure_zero_bits_known(CodeGen *g, ZigType *type_entry) { - if (type_is_invalid(type_entry)) +Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) { + if (type_is_invalid(ty)) return ErrorSemanticAnalyzeFail; - if (type_entry->id == ZigTypeIdStruct) { - return resolve_struct_zero_bits(g, type_entry); - } else if (type_entry->id == ZigTypeIdEnum) { - return resolve_enum_zero_bits(g, type_entry); - } else if (type_entry->id == ZigTypeIdUnion) { - return resolve_union_zero_bits(g, type_entry); + switch (status) { + case ResolveStatusUnstarted: + return ErrorNone; + case ResolveStatusInvalid: + zig_unreachable(); + case ResolveStatusZeroBitsKnown: + if (ty->id == ZigTypeIdStruct) { + return resolve_struct_zero_bits(g, ty); + } else if (ty->id == ZigTypeIdEnum) { + return resolve_enum_zero_bits(g, ty); + } else if (ty->id == ZigTypeIdUnion) { + return resolve_union_zero_bits(g, ty); + } + return ErrorNone; + case ResolveStatusAlignmentKnown: + if (ty->id == ZigTypeIdStruct) { + return resolve_struct_alignment(g, ty); + } else if (ty->id == ZigTypeIdEnum) { + return resolve_enum_zero_bits(g, ty); + } else if (ty->id == ZigTypeIdUnion) { + return resolve_union_zero_bits(g, ty); + } + return ErrorNone; + case ResolveStatusSizeKnown: + if (ty->id == ZigTypeIdStruct) { + return resolve_struct_type(g, ty); + } else if (ty->id == ZigTypeIdEnum) { + return resolve_enum_type(g, ty); + } else if (ty->id == ZigTypeIdUnion) { + return resolve_union_type(g, ty); + } + return ErrorNone; } - return ErrorNone; + zig_unreachable(); } bool ir_get_var_is_comptime(ZigVar *var) { @@ -6262,7 +6311,7 @@ LinkLib *add_link_lib(CodeGen *g, Buf *name) { } uint32_t get_abi_alignment(CodeGen *g, ZigType *type_entry) { - assertNoError(type_ensure_zero_bits_known(g, type_entry)); + assert(type_is_resolved(type_entry, ResolveStatusAlignmentKnown)); if (type_entry->zero_bits) return 0; // We need to make this function work without requiring ensure_complete_type diff --git a/src/analyze.hpp b/src/analyze.hpp index 76f2000cf7..874a29ceb8 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -59,9 +59,9 @@ 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); @@ -89,7 +89,7 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou AstNode *get_param_decl_node(ZigFn *fn_entry, size_t index); 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); diff --git a/src/codegen.cpp b/src/codegen.cpp index 98bb06e6ee..090812bbb9 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -775,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, @@ -793,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) { @@ -1795,7 +1797,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); @@ -4084,7 +4086,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; @@ -4092,7 +4094,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) @@ -4105,7 +4107,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, ""); @@ -4260,7 +4262,8 @@ static LLVMValueRef ir_render_memset(CodeGen *g, IrExecutable *executable, IrIns LLVMValueRef is_volatile = ptr_type->data.pointer.is_volatile ? LLVMConstAllOnes(LLVMInt1Type()) : LLVMConstNull(LLVMInt1Type()); - LLVMValueRef align_val = LLVMConstInt(LLVMInt32Type(), ptr_type->data.pointer.alignment, false); + uint32_t alignment = get_ptr_align(g, ptr_type); + LLVMValueRef align_val = LLVMConstInt(LLVMInt32Type(), alignment, false); LLVMValueRef params[] = { dest_ptr_casted, @@ -4293,7 +4296,7 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutable *executable, IrIns LLVMValueRef is_volatile = (dest_ptr_type->data.pointer.is_volatile || src_ptr_type->data.pointer.is_volatile) ? LLVMConstAllOnes(LLVMInt1Type()) : LLVMConstNull(LLVMInt1Type()); - uint32_t min_align_bytes = min(src_ptr_type->data.pointer.alignment, dest_ptr_type->data.pointer.alignment); + uint32_t min_align_bytes = min(get_ptr_align(g, src_ptr_type), get_ptr_align(g, dest_ptr_type)); LLVMValueRef align_val = LLVMConstInt(LLVMInt32Type(), min_align_bytes, false); LLVMValueRef params[] = { diff --git a/src/ir.cpp b/src/ir.cpp index fd23992a9e..ce044aa0f3 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -40,6 +40,7 @@ struct IrAnalyze { enum ConstCastResultId { ConstCastResultIdOk, + ConstCastResultIdInvalid, ConstCastResultIdErrSet, ConstCastResultIdErrSetGlobal, ConstCastResultIdPointerChild, @@ -7490,8 +7491,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec if (type_has_bits(return_type)) { IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node, get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8, - false, false, PtrLenUnknown, get_abi_alignment(irb->codegen, irb->codegen->builtin_types.entry_u8), - 0, 0)); + false, false, PtrLenUnknown, 0, 0, 0)); IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr); IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, result_ptr); IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, @@ -7544,8 +7544,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec IrInstruction *coro_mem_ptr_maybe = ir_build_coro_free(irb, scope, node, coro_id, irb->exec->coro_handle); IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node, get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8, - false, false, PtrLenUnknown, get_abi_alignment(irb->codegen, irb->codegen->builtin_types.entry_u8), - 0, 0)); + false, false, PtrLenUnknown, 0, 0, 0)); IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe); IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false); IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var); @@ -8516,6 +8515,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted ConstCastOnly result = {}; result.id = ConstCastResultIdOk; + Error err; + if (wanted_type == actual_type) return result; @@ -8528,6 +8529,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted { ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.maybe.child_type, actual_type, source_node, wanted_is_mutable); + if (child.id == ConstCastResultIdInvalid) + return child; if (child.id != ConstCastResultIdOk) { result.id = ConstCastResultIdNullWrapPtr; result.data.null_wrap_ptr_child = allocate_nonzero(1); @@ -8544,7 +8547,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) && (!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile)) { - assert(actual_type->data.pointer.alignment >= wanted_type->data.pointer.alignment); return result; } @@ -8552,6 +8554,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted if (wanted_type->id == ZigTypeIdPointer && actual_type->id == ZigTypeIdPointer) { ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, actual_type->data.pointer.child_type, source_node, !wanted_type->data.pointer.is_const); + if (child.id == ConstCastResultIdInvalid) + return child; if (child.id != ConstCastResultIdOk) { result.id = ConstCastResultIdPointerChild; result.data.pointer_mismatch = allocate_nonzero(1); @@ -8560,12 +8564,20 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted result.data.pointer_mismatch->actual_child = actual_type->data.pointer.child_type; return result; } + if ((err = type_resolve(g, actual_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) { + result.id = ConstCastResultIdInvalid; + return result; + } + if ((err = type_resolve(g, wanted_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) { + result.id = ConstCastResultIdInvalid; + return result; + } if ((actual_type->data.pointer.ptr_len == wanted_type->data.pointer.ptr_len) && (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) && (!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile) && actual_type->data.pointer.bit_offset == wanted_type->data.pointer.bit_offset && actual_type->data.pointer.unaligned_bit_count == wanted_type->data.pointer.unaligned_bit_count && - actual_type->data.pointer.alignment >= wanted_type->data.pointer.alignment) + get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, wanted_type)) { return result; } @@ -8575,14 +8587,24 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted if (is_slice(wanted_type) && is_slice(actual_type)) { ZigType *actual_ptr_type = actual_type->data.structure.fields[slice_ptr_index].type_entry; ZigType *wanted_ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry; + if ((err = type_resolve(g, actual_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) { + result.id = ConstCastResultIdInvalid; + return result; + } + if ((err = type_resolve(g, wanted_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) { + result.id = ConstCastResultIdInvalid; + return result; + } if ((!actual_ptr_type->data.pointer.is_const || wanted_ptr_type->data.pointer.is_const) && (!actual_ptr_type->data.pointer.is_volatile || wanted_ptr_type->data.pointer.is_volatile) && actual_ptr_type->data.pointer.bit_offset == wanted_ptr_type->data.pointer.bit_offset && actual_ptr_type->data.pointer.unaligned_bit_count == wanted_ptr_type->data.pointer.unaligned_bit_count && - actual_ptr_type->data.pointer.alignment >= wanted_ptr_type->data.pointer.alignment) + get_ptr_align(g, actual_ptr_type) >= get_ptr_align(g, wanted_ptr_type)) { ConstCastOnly child = types_match_const_cast_only(ira, wanted_ptr_type->data.pointer.child_type, actual_ptr_type->data.pointer.child_type, source_node, !wanted_ptr_type->data.pointer.is_const); + if (child.id == ConstCastResultIdInvalid) + return child; if (child.id != ConstCastResultIdOk) { result.id = ConstCastResultIdSliceChild; result.data.slice_mismatch = allocate_nonzero(1); @@ -8598,6 +8620,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted if (wanted_type->id == ZigTypeIdOptional && actual_type->id == ZigTypeIdOptional) { ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.maybe.child_type, actual_type->data.maybe.child_type, source_node, wanted_is_mutable); + if (child.id == ConstCastResultIdInvalid) + return child; if (child.id != ConstCastResultIdOk) { result.id = ConstCastResultIdOptionalChild; result.data.optional = allocate_nonzero(1); @@ -8612,6 +8636,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted if (wanted_type->id == ZigTypeIdErrorUnion && actual_type->id == ZigTypeIdErrorUnion) { ConstCastOnly payload_child = types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type->data.error_union.payload_type, source_node, wanted_is_mutable); + if (payload_child.id == ConstCastResultIdInvalid) + return payload_child; if (payload_child.id != ConstCastResultIdOk) { result.id = ConstCastResultIdErrorUnionPayload; result.data.error_union_payload = allocate_nonzero(1); @@ -8622,6 +8648,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted } ConstCastOnly error_set_child = types_match_const_cast_only(ira, wanted_type->data.error_union.err_set_type, actual_type->data.error_union.err_set_type, source_node, wanted_is_mutable); + if (error_set_child.id == ConstCastResultIdInvalid) + return error_set_child; if (error_set_child.id != ConstCastResultIdOk) { result.id = ConstCastResultIdErrorUnionErrorSet; result.data.error_union_error_set = allocate_nonzero(1); @@ -8709,6 +8737,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted { ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.fn.fn_type_id.return_type, actual_type->data.fn.fn_type_id.return_type, source_node, false); + if (child.id == ConstCastResultIdInvalid) + return child; if (child.id != ConstCastResultIdOk) { result.id = ConstCastResultIdFnReturnType; result.data.return_type = allocate_nonzero(1); @@ -8721,6 +8751,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted actual_type->data.fn.fn_type_id.async_allocator_type, wanted_type->data.fn.fn_type_id.async_allocator_type, source_node, false); + if (child.id == ConstCastResultIdInvalid) + return child; if (child.id != ConstCastResultIdOk) { result.id = ConstCastResultIdAsyncAllocatorType; result.data.async_allocator_type = allocate_nonzero(1); @@ -8745,6 +8777,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted ConstCastOnly arg_child = types_match_const_cast_only(ira, actual_param_info->type, expected_param_info->type, source_node, false); + if (arg_child.id == ConstCastResultIdInvalid) + return arg_child; if (arg_child.id != ConstCastResultIdOk) { result.id = ConstCastResultIdFnArg; result.data.fn_arg.arg_index = i; @@ -9238,7 +9272,7 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT if (prev_type->id == ZigTypeIdEnum && cur_type->id == ZigTypeIdUnion && (cur_type->data.unionation.decl_node->data.container_decl.auto_enum || cur_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr)) { - if ((err = type_ensure_zero_bits_known(ira->codegen, cur_type))) + if ((err = type_resolve(ira->codegen, cur_type, ResolveStatusZeroBitsKnown))) return ira->codegen->builtin_types.entry_invalid; if (cur_type->data.unionation.tag_type == prev_type) { continue; @@ -9248,7 +9282,7 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT if (cur_type->id == ZigTypeIdEnum && prev_type->id == ZigTypeIdUnion && (prev_type->data.unionation.decl_node->data.container_decl.auto_enum || prev_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr)) { - if ((err = type_ensure_zero_bits_known(ira->codegen, prev_type))) + if ((err = type_resolve(ira->codegen, prev_type, ResolveStatusZeroBitsKnown))) return ira->codegen->builtin_types.entry_invalid; if (prev_type->data.unionation.tag_type == cur_type) { prev_inst = cur_inst; @@ -9274,8 +9308,7 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT ZigType *ptr_type = get_pointer_to_type_extra( ira->codegen, prev_inst->value.type->data.array.child_type, true, false, PtrLenUnknown, - get_abi_alignment(ira->codegen, prev_inst->value.type->data.array.child_type), - 0, 0); + 0, 0, 0); ZigType *slice_type = get_slice_type(ira->codegen, ptr_type); if (err_set_type != nullptr) { return get_error_union_type(ira->codegen, err_set_type, slice_type); @@ -9472,7 +9505,16 @@ static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira, IrInstruction *value, ZigType *wanted_type) { assert(value->value.type->id == ZigTypeIdPointer); - wanted_type = adjust_ptr_align(ira->codegen, wanted_type, value->value.type->data.pointer.alignment); + + Error err; + + if ((err = type_resolve(ira->codegen, value->value.type->data.pointer.child_type, + ResolveStatusAlignmentKnown))) + { + return ira->codegen->invalid_instruction; + } + + wanted_type = adjust_ptr_align(ira->codegen, wanted_type, get_ptr_align(ira->codegen, value->value.type)); if (instr_is_comptime(value)) { ConstExprValue *pointee = ir_const_ptr_pointee(ira, &value->value, source_instr->source_node); @@ -9500,7 +9542,15 @@ static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira, static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, ZigType *wanted_type) { - wanted_type = adjust_slice_align(ira->codegen, wanted_type, value->value.type->data.pointer.alignment); + Error err; + + if ((err = type_resolve(ira->codegen, value->value.type->data.pointer.child_type, + ResolveStatusAlignmentKnown))) + { + return ira->codegen->invalid_instruction; + } + + wanted_type = adjust_slice_align(ira->codegen, wanted_type, get_ptr_align(ira->codegen, value->value.type)); if (instr_is_comptime(value)) { ConstExprValue *pointee = ir_const_ptr_pointee(ira, &value->value, source_instr->source_node); @@ -9687,8 +9737,7 @@ static ZigType *ir_analyze_const_ptr(IrAnalyze *ira, IrInstruction *instruction, ConstPtrMut ptr_mut, bool ptr_is_const, bool ptr_is_volatile) { IrInstruction *const_instr = ir_get_const_ptr(ira, instruction, pointee, - pointee_type, ptr_mut, ptr_is_const, ptr_is_volatile, - get_abi_alignment(ira->codegen, pointee_type)); + pointee_type, ptr_mut, ptr_is_const, ptr_is_volatile, 0); ir_link_new_instruction(const_instr, instruction); return const_instr->value.type; } @@ -10005,20 +10054,24 @@ static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *so static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *value, bool is_const, bool is_volatile) { + Error err; + if (type_is_invalid(value->value.type)) return ira->codegen->invalid_instruction; + if ((err = type_resolve(ira->codegen, value->value.type, ResolveStatusZeroBitsKnown))) + return ira->codegen->invalid_instruction; + if (instr_is_comptime(value)) { ConstExprValue *val = ir_resolve_const(ira, value, UndefOk); if (!val) return ira->codegen->invalid_instruction; return ir_get_const_ptr(ira, source_instruction, val, value->value.type, - ConstPtrMutComptimeConst, is_const, is_volatile, - get_abi_alignment(ira->codegen, value->value.type)); + ConstPtrMutComptimeConst, is_const, is_volatile, 0); } ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, value->value.type, - is_const, is_volatile, PtrLenSingle, get_abi_alignment(ira->codegen, value->value.type), 0, 0); + is_const, is_volatile, PtrLenSingle, 0, 0, 0); IrInstruction *new_instruction = ir_build_ref(&ira->new_irb, source_instruction->scope, source_instruction->source_node, value, is_const, is_volatile); new_instruction->value.type = ptr_type; @@ -10185,9 +10238,9 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so return ira->codegen->invalid_instruction; TypeUnionField *union_field = find_union_field_by_tag(wanted_type, &val->data.x_enum_tag); assert(union_field != nullptr); - if ((err = type_ensure_zero_bits_known(ira->codegen, union_field->type_entry))) + if ((err = type_resolve(ira->codegen, union_field->type_entry, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_instruction; - if (!union_field->type_entry->zero_bits) { + if (type_has_bits(union_field->type_entry)) { AstNode *field_node = wanted_type->data.unionation.decl_node->data.container_decl.fields.at( union_field->enum_field->decl_index); ErrorMsg *msg = ir_add_error(ira, source_instr, @@ -10490,7 +10543,10 @@ static IrInstruction *ir_analyze_ptr_to_array(IrAnalyze *ira, IrInstruction *sou ZigType *wanted_type) { assert(wanted_type->id == ZigTypeIdPointer); - wanted_type = adjust_ptr_align(ira->codegen, wanted_type, target->value.type->data.pointer.alignment); + Error err; + if ((err = type_resolve(ira->codegen, target->value.type->data.pointer.child_type, ResolveStatusAlignmentKnown))) + return ira->codegen->invalid_instruction; + wanted_type = adjust_ptr_align(ira->codegen, wanted_type, get_ptr_align(ira->codegen, target->value.type)); ZigType *array_type = wanted_type->data.pointer.child_type; assert(array_type->id == ZigTypeIdArray); assert(array_type->data.array.len == 1); @@ -10537,6 +10593,8 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa switch (cast_result->id) { case ConstCastResultIdOk: zig_unreachable(); + case ConstCastResultIdInvalid: + zig_unreachable(); case ConstCastResultIdOptionalChild: { ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node, buf_sprintf("optional type child '%s' cannot cast into optional type child '%s'", @@ -10636,6 +10694,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst // perfect match or non-const to const ConstCastOnly const_cast_result = types_match_const_cast_only(ira, wanted_type, actual_type, source_node, false); + if (const_cast_result.id == ConstCastResultIdInvalid) + return ira->codegen->invalid_instruction; if (const_cast_result.id == ConstCastResultIdOk) { return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false); } @@ -10751,13 +10811,19 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst wanted_type->data.pointer.ptr_len == PtrLenUnknown && actual_type->id == ZigTypeIdPointer && actual_type->data.pointer.ptr_len == PtrLenSingle && - actual_type->data.pointer.child_type->id == ZigTypeIdArray && - actual_type->data.pointer.alignment >= wanted_type->data.pointer.alignment && - types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, - actual_type->data.pointer.child_type->data.array.child_type, source_node, - !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk) + actual_type->data.pointer.child_type->id == ZigTypeIdArray) { - return ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, wanted_type); + if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) + return ira->codegen->invalid_instruction; + if ((err = type_resolve(ira->codegen, wanted_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) + return ira->codegen->invalid_instruction; + if (get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, wanted_type) && + types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, + actual_type->data.pointer.child_type->data.array.child_type, source_node, + !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk) + { + return ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, wanted_type); + } } // *[N]T to []T @@ -10811,16 +10877,23 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst wanted_child_type->data.pointer.ptr_len == PtrLenUnknown && actual_type->id == ZigTypeIdPointer && actual_type->data.pointer.ptr_len == PtrLenSingle && - actual_type->data.pointer.child_type->id == ZigTypeIdArray && - actual_type->data.pointer.alignment >= wanted_child_type->data.pointer.alignment && - types_match_const_cast_only(ira, wanted_child_type->data.pointer.child_type, - actual_type->data.pointer.child_type->data.array.child_type, source_node, - !wanted_child_type->data.pointer.is_const).id == ConstCastResultIdOk) + actual_type->data.pointer.child_type->id == ZigTypeIdArray) { - IrInstruction *cast1 = ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, wanted_child_type); - if (type_is_invalid(cast1->value.type)) + if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) return ira->codegen->invalid_instruction; - return ir_analyze_maybe_wrap(ira, source_instr, cast1, wanted_type); + if ((err = type_resolve(ira->codegen, wanted_child_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) + return ira->codegen->invalid_instruction; + if (get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, wanted_child_type) && + types_match_const_cast_only(ira, wanted_child_type->data.pointer.child_type, + actual_type->data.pointer.child_type->data.array.child_type, source_node, + !wanted_child_type->data.pointer.is_const).id == ConstCastResultIdOk) + { + IrInstruction *cast1 = ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, + wanted_child_type); + if (type_is_invalid(cast1->value.type)) + return ira->codegen->invalid_instruction; + return ir_analyze_maybe_wrap(ira, source_instr, cast1, wanted_type); + } } } @@ -10963,7 +11036,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst // cast from union to the enum type of the union if (actual_type->id == ZigTypeIdUnion && wanted_type->id == ZigTypeIdEnum) { - if ((err = type_ensure_zero_bits_known(ira->codegen, actual_type))) + if ((err = type_resolve(ira->codegen, actual_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_instruction; if (actual_type->data.unionation.tag_type == wanted_type) { @@ -10976,7 +11049,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst (wanted_type->data.unionation.decl_node->data.container_decl.auto_enum || wanted_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr)) { - if ((err = type_ensure_zero_bits_known(ira->codegen, wanted_type))) + if ((err = type_resolve(ira->codegen, wanted_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_instruction; if (wanted_type->data.unionation.tag_type == actual_type) { @@ -10990,7 +11063,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst if (union_type->data.unionation.decl_node->data.container_decl.auto_enum || union_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr) { - if ((err = type_ensure_zero_bits_known(ira->codegen, union_type))) + if ((err = type_resolve(ira->codegen, union_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_instruction; if (union_type->data.unionation.tag_type == actual_type) { @@ -11017,14 +11090,24 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst actual_type->data.pointer.child_type, source_node, !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk) { - if (wanted_type->data.pointer.alignment > actual_type->data.pointer.alignment) { + if ((err = type_resolve(ira->codegen, wanted_type->data.pointer.child_type, + ResolveStatusAlignmentKnown))) + { + return ira->codegen->invalid_instruction; + } + if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, + ResolveStatusAlignmentKnown))) + { + return ira->codegen->invalid_instruction; + } + uint32_t wanted_align = get_ptr_align(ira->codegen, wanted_type); + uint32_t actual_align = get_ptr_align(ira->codegen, actual_type); + if (wanted_align > actual_align) { ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("cast increases pointer alignment")); add_error_note(ira->codegen, msg, value->source_node, - buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&actual_type->name), - actual_type->data.pointer.alignment)); + buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&actual_type->name), actual_align)); add_error_note(ira->codegen, msg, source_instr->source_node, - buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&wanted_type->name), - wanted_type->data.pointer.alignment)); + buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&wanted_type->name), wanted_align)); return ira->codegen->invalid_instruction; } return ir_analyze_ptr_to_array(ira, source_instr, value, wanted_type); @@ -11036,7 +11119,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, actual_type, source_node, !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk) { - if ((err = type_ensure_zero_bits_known(ira->codegen, actual_type))) { + if ((err = type_resolve(ira->codegen, actual_type, ResolveStatusZeroBitsKnown))) { return ira->codegen->invalid_instruction; } if (!type_has_bits(actual_type)) { @@ -11282,8 +11365,7 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) { return nullptr; ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, - true, false, PtrLenUnknown, - get_abi_alignment(ira->codegen, ira->codegen->builtin_types.entry_u8), 0, 0); + true, false, PtrLenUnknown, 0, 0, 0); ZigType *str_type = get_slice_type(ira->codegen, ptr_type); IrInstruction *casted_value = ir_implicit_cast(ira, value, str_type); if (type_is_invalid(casted_value->value.type)) @@ -11573,8 +11655,6 @@ static ZigType *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op ZigType *resolved_type = ir_resolve_peer_types(ira, source_node, nullptr, instructions, 2); if (type_is_invalid(resolved_type)) return resolved_type; - if ((err = type_ensure_zero_bits_known(ira->codegen, resolved_type))) - return resolved_type; bool operator_allowed; switch (resolved_type->id) { @@ -11630,6 +11710,9 @@ static ZigType *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op if (casted_op2 == ira->codegen->invalid_instruction) return ira->codegen->builtin_types.entry_invalid; + if ((err = type_resolve(ira->codegen, resolved_type, ResolveStatusZeroBitsKnown))) + return resolved_type; + bool one_possible_value = !type_requires_comptime(resolved_type) && !type_has_bits(resolved_type); if (one_possible_value || (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2))) { ConstExprValue *op1_val = one_possible_value ? &casted_op1->value : ir_resolve_const(ira, casted_op1, UndefBad); @@ -12316,7 +12399,7 @@ static ZigType *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *instruc out_array_val = out_val; } else if (is_slice(op1_type) || is_slice(op2_type)) { ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, child_type, - true, false, PtrLenUnknown, get_abi_alignment(ira->codegen, child_type), 0, 0); + true, false, PtrLenUnknown, 0, 0, 0); result_type = get_slice_type(ira->codegen, ptr_type); out_array_val = create_const_vals(1); out_array_val->special = ConstValSpecialStatic; @@ -12337,8 +12420,7 @@ static ZigType *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *instruc new_len += 1; // null byte // TODO make this `[*]null T` instead of `[*]T` - result_type = get_pointer_to_type_extra(ira->codegen, child_type, true, false, - PtrLenUnknown, get_abi_alignment(ira->codegen, child_type), 0, 0); + result_type = get_pointer_to_type_extra(ira->codegen, child_type, true, false, PtrLenUnknown, 0, 0, 0); out_array_val = create_const_vals(1); out_array_val->special = ConstValSpecialStatic; @@ -12563,7 +12645,7 @@ static ZigType *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstructionDec if (type_is_invalid(result_type)) { result_type = ira->codegen->builtin_types.entry_invalid; } else { - if ((err = type_ensure_zero_bits_known(ira->codegen, result_type))) { + if ((err = type_resolve(ira->codegen, result_type, ResolveStatusZeroBitsKnown))) { result_type = ira->codegen->builtin_types.entry_invalid; } } @@ -12631,6 +12713,11 @@ static ZigType *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstructionDec } if (decl_var_instruction->align_value == nullptr) { + if ((err = type_resolve(ira->codegen, result_type, ResolveStatusAlignmentKnown))) { + var->value->type = ira->codegen->builtin_types.entry_invalid; + decl_var_instruction->base.other = &decl_var_instruction->base; + return ira->codegen->builtin_types.entry_void; + } var->align_bytes = get_abi_alignment(ira->codegen, result_type); } else { if (!ir_resolve_align(ira, decl_var_instruction->align_value->other, &var->align_bytes)) { @@ -13100,7 +13187,6 @@ static ZigVar *get_fn_var_by_index(ZigFn *fn_entry, size_t index) { static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, ZigVar *var) { - Error err; while (var->next_var != nullptr) { var = var->next_var; } @@ -13158,8 +13244,6 @@ no_mem_slot: instruction->scope, instruction->source_node, var); var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->value->type, var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0); - if ((err = type_ensure_zero_bits_known(ira->codegen, var->value->type))) - return ira->codegen->invalid_instruction; bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr); var_ptr_instruction->value.data.rh_ptr = in_fn_scope ? RuntimeHintPtrStack : RuntimeHintPtrNonStack; @@ -13356,8 +13440,7 @@ static ZigType *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instr IrInstruction *casted_new_stack = nullptr; if (call_instruction->new_stack != nullptr) { ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, - false, false, PtrLenUnknown, - get_abi_alignment(ira->codegen, ira->codegen->builtin_types.entry_u8), 0, 0); + false, false, PtrLenUnknown, 0, 0, 0); ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); IrInstruction *new_stack = call_instruction->new_stack->other; if (type_is_invalid(new_stack->value.type)) @@ -13536,7 +13619,7 @@ static ZigType *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instr inst_fn_type_id.return_type = specified_return_type; } - if ((err = type_ensure_zero_bits_known(ira->codegen, specified_return_type))) + if ((err = type_resolve(ira->codegen, specified_return_type, ResolveStatusZeroBitsKnown))) return ira->codegen->builtin_types.entry_invalid; if (type_requires_comptime(specified_return_type)) { @@ -14212,7 +14295,7 @@ static ZigType *adjust_ptr_len(CodeGen *g, ZigType *ptr_type, PtrLen ptr_len) { ptr_type->data.pointer.child_type, ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, ptr_len, - ptr_type->data.pointer.alignment, + ptr_type->data.pointer.explicit_alignment, ptr_type->data.pointer.bit_offset, ptr_type->data.pointer.unaligned_bit_count); } @@ -14264,7 +14347,7 @@ static ZigType *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstructionEle return_type = get_pointer_to_type_extra(ira->codegen, child_type, ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, elem_ptr_instruction->ptr_len, - ptr_type->data.pointer.alignment, 0, 0); + ptr_type->data.pointer.explicit_alignment, 0, 0); } else { uint64_t elem_val_scalar; if (!ir_resolve_usize(ira, elem_index, &elem_val_scalar)) @@ -14336,7 +14419,7 @@ static ZigType *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstructionEle uint64_t elem_size = type_size(ira->codegen, return_type->data.pointer.child_type); uint64_t abi_align = get_abi_alignment(ira->codegen, return_type->data.pointer.child_type); - uint64_t ptr_align = return_type->data.pointer.alignment; + uint64_t ptr_align = get_ptr_align(ira->codegen, return_type); if (instr_is_comptime(casted_elem_index)) { uint64_t index = bigint_as_unsigned(&casted_elem_index->value.data.x_bigint); if (array_type->id == ZigTypeIdArray) { @@ -14653,9 +14736,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ } ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field_type, - is_const, is_volatile, - PtrLenSingle, - get_abi_alignment(ira->codegen, field_type), 0, 0); + is_const, is_volatile, PtrLenSingle, 0, 0, 0); IrInstruction *result = ir_get_const(ira, source_instr); ConstExprValue *const_val = &result->value; @@ -14669,7 +14750,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, container_ptr, field); result->value.type = get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile, - PtrLenSingle, get_abi_alignment(ira->codegen, field->type_entry), 0, 0); + PtrLenSingle, 0, 0, 0); return result; } else { return ir_analyze_container_member_access_inner(ira, bare_type, field_name, @@ -15002,9 +15083,14 @@ static ZigType *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstructionFi } else if (buf_eql_str(field_name, "alignment")) { bool ptr_is_const = true; bool ptr_is_volatile = false; + if ((err = type_resolve(ira->codegen, child_type->data.pointer.child_type, + ResolveStatusAlignmentKnown))) + { + return ira->codegen->builtin_types.entry_invalid; + } return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, create_const_unsigned_negative(ira->codegen->builtin_types.entry_num_lit_int, - child_type->data.pointer.alignment, false), + get_ptr_align(ira->codegen, child_type), false), ira->codegen->builtin_types.entry_num_lit_int, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile); } else { @@ -15461,7 +15547,7 @@ static ZigType *ir_analyze_instruction_slice_type(IrAnalyze *ira, IrInstructionSliceType *slice_type_instruction) { Error err; - uint32_t align_bytes; + uint32_t align_bytes = 0; if (slice_type_instruction->align_value != nullptr) { if (!ir_resolve_align(ira, slice_type_instruction->align_value->other, &align_bytes)) return ira->codegen->builtin_types.entry_invalid; @@ -15471,12 +15557,6 @@ static ZigType *ir_analyze_instruction_slice_type(IrAnalyze *ira, if (type_is_invalid(child_type)) return ira->codegen->builtin_types.entry_invalid; - if (slice_type_instruction->align_value == nullptr) { - if ((err = type_ensure_zero_bits_known(ira->codegen, child_type))) - return ira->codegen->builtin_types.entry_invalid; - align_bytes = get_abi_alignment(ira->codegen, child_type); - } - bool is_const = slice_type_instruction->is_const; bool is_volatile = slice_type_instruction->is_volatile; @@ -15511,7 +15591,7 @@ static ZigType *ir_analyze_instruction_slice_type(IrAnalyze *ira, case ZigTypeIdBoundFn: case ZigTypeIdPromise: { - if ((err = type_ensure_zero_bits_known(ira->codegen, child_type))) + if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown))) return ira->codegen->builtin_types.entry_invalid; ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, child_type, is_const, is_volatile, PtrLenUnknown, align_bytes, 0, 0); @@ -15751,9 +15831,7 @@ static ZigType *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira, } ZigType *child_type = type_entry->data.maybe.child_type; ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type, - ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, - PtrLenSingle, - get_abi_alignment(ira->codegen, child_type), 0, 0); + ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0); if (instr_is_comptime(value)) { ConstExprValue *val = ir_resolve_const(ira, value, UndefBad); @@ -16123,7 +16201,7 @@ static ZigType *ir_analyze_instruction_switch_target(IrAnalyze *ira, return tag_type; } case ZigTypeIdEnum: { - if ((err = type_ensure_zero_bits_known(ira->codegen, target_type))) + if ((err = type_resolve(ira->codegen, target_type, ResolveStatusZeroBitsKnown))) return ira->codegen->builtin_types.entry_invalid; if (target_type->data.enumeration.src_field_count < 2) { TypeEnumField *only_field = &target_type->data.enumeration.fields[0]; @@ -16352,7 +16430,7 @@ static ZigType *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrInstruc if (casted_field_value == ira->codegen->invalid_instruction) return ira->codegen->builtin_types.entry_invalid; - if ((err = type_ensure_zero_bits_known(ira->codegen, casted_field_value->value.type))) + if ((err = type_resolve(ira->codegen, casted_field_value->value.type, ResolveStatusZeroBitsKnown))) return ira->codegen->builtin_types.entry_invalid; bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope); @@ -16752,7 +16830,7 @@ static ZigType *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstructionErr return ira->codegen->builtin_types.entry_invalid; ZigType *u8_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, - true, false, PtrLenUnknown, get_abi_alignment(ira->codegen, ira->codegen->builtin_types.entry_u8), 0, 0); + true, false, PtrLenUnknown, 0, 0, 0); ZigType *str_type = get_slice_type(ira->codegen, u8_ptr_type); if (casted_value->value.special == ConstValSpecialStatic) { ErrorTableEntry *err = casted_value->value.data.x_err_set; @@ -16779,7 +16857,7 @@ static ZigType *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstructi assert(target->value.type->id == ZigTypeIdEnum); if (instr_is_comptime(target)) { - if ((err = type_ensure_zero_bits_known(ira->codegen, target->value.type))) + if ((err = type_resolve(ira->codegen, target->value.type, ResolveStatusZeroBitsKnown))) return ira->codegen->builtin_types.entry_invalid; TypeEnumField *field = find_enum_field_by_tag(target->value.type, &target->value.data.x_bigint); ConstExprValue *array_val = create_const_str_lit(ira->codegen, field->name); @@ -16794,8 +16872,7 @@ static ZigType *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstructi ZigType *u8_ptr_type = get_pointer_to_type_extra( ira->codegen, ira->codegen->builtin_types.entry_u8, true, false, PtrLenUnknown, - get_abi_alignment(ira->codegen, ira->codegen->builtin_types.entry_u8), - 0, 0); + 0, 0, 0); result->value.type = get_slice_type(ira->codegen, u8_ptr_type); return result->value.type; } @@ -17158,8 +17235,7 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco ZigType *u8_ptr = get_pointer_to_type_extra( ira->codegen, ira->codegen->builtin_types.entry_u8, true, false, PtrLenUnknown, - get_abi_alignment(ira->codegen, ira->codegen->builtin_types.entry_u8), - 0, 0); + 0, 0, 0); fn_def_fields[6].type = get_optional_type(ira->codegen, get_slice_type(ira->codegen, u8_ptr)); if (fn_node->is_extern && buf_len(fn_node->lib_name) > 0) { fn_def_fields[6].data.x_optional = create_const_vals(1); @@ -17279,7 +17355,7 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty ensure_field_index(result->type, "alignment", 3); fields[3].special = ConstValSpecialStatic; fields[3].type = get_int_type(ira->codegen, false, 29); - bigint_init_unsigned(&fields[3].data.x_bigint, attrs_type->data.pointer.alignment); + bigint_init_unsigned(&fields[3].data.x_bigint, get_ptr_align(ira->codegen, attrs_type)); // child: type ensure_field_index(result->type, "child", 4); fields[4].special = ConstValSpecialStatic; @@ -18369,7 +18445,21 @@ static ZigType *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInstructio return dest_type; } +static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) { + Error err; + + if (ty->id == ZigTypeIdPointer) { + if ((err = type_resolve(ira->codegen, ty->data.pointer.child_type, ResolveStatusAlignmentKnown))) + return err; + } + + *result_align = get_ptr_align(ira->codegen, ty); + return ErrorNone; +} + static ZigType *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstructionFromBytes *instruction) { + Error err; + ZigType *dest_child_type = ir_resolve_type(ira, instruction->dest_child_type->other); if (type_is_invalid(dest_child_type)) return ira->codegen->builtin_types.entry_invalid; @@ -18384,15 +18474,23 @@ static ZigType *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstructionF if (target->value.type->id == ZigTypeIdPointer) { src_ptr_const = target->value.type->data.pointer.is_const; src_ptr_volatile = target->value.type->data.pointer.is_volatile; - src_ptr_align = target->value.type->data.pointer.alignment; + + if ((err = resolve_ptr_align(ira, target->value.type, &src_ptr_align))) + return ira->codegen->builtin_types.entry_invalid; } else if (is_slice(target->value.type)) { ZigType *src_ptr_type = target->value.type->data.structure.fields[slice_ptr_index].type_entry; src_ptr_const = src_ptr_type->data.pointer.is_const; src_ptr_volatile = src_ptr_type->data.pointer.is_volatile; - src_ptr_align = src_ptr_type->data.pointer.alignment; + + if ((err = resolve_ptr_align(ira, src_ptr_type, &src_ptr_align))) + return ira->codegen->builtin_types.entry_invalid; } else { src_ptr_const = true; src_ptr_volatile = false; + + if ((err = type_resolve(ira->codegen, target->value.type, ResolveStatusAlignmentKnown))) + return ira->codegen->builtin_types.entry_invalid; + src_ptr_align = get_abi_alignment(ira->codegen, target->value.type); } @@ -18450,6 +18548,8 @@ static ZigType *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstructionF } static ZigType *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstructionToBytes *instruction) { + Error err; + IrInstruction *target = instruction->target->other; if (type_is_invalid(target->value.type)) return ira->codegen->builtin_types.entry_invalid; @@ -18462,9 +18562,13 @@ static ZigType *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstructionToB ZigType *src_ptr_type = target->value.type->data.structure.fields[slice_ptr_index].type_entry; + uint32_t alignment; + if ((err = resolve_ptr_align(ira, src_ptr_type, &alignment))) + return ira->codegen->builtin_types.entry_invalid; + ZigType *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, src_ptr_type->data.pointer.is_const, src_ptr_type->data.pointer.is_volatile, PtrLenUnknown, - src_ptr_type->data.pointer.alignment, 0, 0); + alignment, 0, 0); ZigType *dest_slice_type = get_slice_type(ira->codegen, dest_ptr_type); IrInstruction *result = ir_resolve_cast(ira, &instruction->base, target, dest_slice_type, CastOpResizeSlice, true); @@ -18622,6 +18726,8 @@ static ZigType *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstructionBoo } static ZigType *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructionMemset *instruction) { + Error err; + IrInstruction *dest_ptr = instruction->dest_ptr->other; if (type_is_invalid(dest_ptr->value.type)) return ira->codegen->builtin_types.entry_invalid; @@ -18640,8 +18746,13 @@ static ZigType *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructionMemse ZigType *usize = ira->codegen->builtin_types.entry_usize; ZigType *u8 = ira->codegen->builtin_types.entry_u8; - uint32_t dest_align = (dest_uncasted_type->id == ZigTypeIdPointer) ? - dest_uncasted_type->data.pointer.alignment : get_abi_alignment(ira->codegen, u8); + uint32_t dest_align; + if (dest_uncasted_type->id == ZigTypeIdPointer) { + if ((err = resolve_ptr_align(ira, dest_uncasted_type, &dest_align))) + return ira->codegen->builtin_types.entry_invalid; + } else { + dest_align = get_abi_alignment(ira->codegen, u8); + } ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, u8, false, dest_is_volatile, PtrLenUnknown, dest_align, 0, 0); @@ -18714,6 +18825,8 @@ static ZigType *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructionMemse } static ZigType *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructionMemcpy *instruction) { + Error err; + IrInstruction *dest_ptr = instruction->dest_ptr->other; if (type_is_invalid(dest_ptr->value.type)) return ira->codegen->builtin_types.entry_invalid; @@ -18733,10 +18846,22 @@ static ZigType *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructionMemcp dest_uncasted_type->data.pointer.is_volatile; bool src_is_volatile = (src_uncasted_type->id == ZigTypeIdPointer) && src_uncasted_type->data.pointer.is_volatile; - uint32_t dest_align = (dest_uncasted_type->id == ZigTypeIdPointer) ? - dest_uncasted_type->data.pointer.alignment : get_abi_alignment(ira->codegen, u8); - uint32_t src_align = (src_uncasted_type->id == ZigTypeIdPointer) ? - src_uncasted_type->data.pointer.alignment : get_abi_alignment(ira->codegen, u8); + + uint32_t dest_align; + if (dest_uncasted_type->id == ZigTypeIdPointer) { + if ((err = resolve_ptr_align(ira, dest_uncasted_type, &dest_align))) + return ira->codegen->builtin_types.entry_invalid; + } else { + dest_align = get_abi_alignment(ira->codegen, u8); + } + + uint32_t src_align; + if (src_uncasted_type->id == ZigTypeIdPointer) { + if ((err = resolve_ptr_align(ira, src_uncasted_type, &src_align))) + return ira->codegen->builtin_types.entry_invalid; + } else { + src_align = get_abi_alignment(ira->codegen, u8); + } ZigType *usize = ira->codegen->builtin_types.entry_usize; ZigType *u8_ptr_mut = get_pointer_to_type_extra(ira->codegen, u8, false, dest_is_volatile, @@ -18881,17 +19006,13 @@ static ZigType *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructionSlice ZigType *return_type; if (array_type->id == ZigTypeIdArray) { - uint32_t byte_alignment = ptr_type->data.pointer.alignment; - if (array_type->data.array.len == 0 && byte_alignment == 0) { - byte_alignment = get_abi_alignment(ira->codegen, array_type->data.array.child_type); - } bool is_comptime_const = ptr_ptr->value.special == ConstValSpecialStatic && ptr_ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst; ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.array.child_type, ptr_type->data.pointer.is_const || is_comptime_const, ptr_type->data.pointer.is_volatile, PtrLenUnknown, - byte_alignment, 0, 0); + ptr_type->data.pointer.explicit_alignment, 0, 0); return_type = get_slice_type(ira->codegen, slice_ptr_type); } else if (array_type->id == ZigTypeIdPointer) { if (array_type->data.pointer.ptr_len == PtrLenSingle) { @@ -18901,7 +19022,7 @@ static ZigType *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructionSlice main_type->data.pointer.child_type, array_type->data.pointer.is_const, array_type->data.pointer.is_volatile, PtrLenUnknown, - array_type->data.pointer.alignment, 0, 0); + array_type->data.pointer.explicit_alignment, 0, 0); return_type = get_slice_type(ira->codegen, slice_ptr_type); } else { ir_add_error(ira, &instruction->base, buf_sprintf("slice of single-item pointer")); @@ -18911,7 +19032,7 @@ static ZigType *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructionSlice ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.pointer.child_type, array_type->data.pointer.is_const, array_type->data.pointer.is_volatile, PtrLenUnknown, - array_type->data.pointer.alignment, 0, 0); + array_type->data.pointer.explicit_alignment, 0, 0); return_type = get_slice_type(ira->codegen, slice_ptr_type); if (!end) { ir_add_error(ira, &instruction->base, buf_sprintf("slice of pointer must include end value")); @@ -19292,7 +19413,7 @@ static ZigType *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstructionAli return ira->codegen->builtin_types.entry_invalid; ZigType *type_entry = ir_resolve_type(ira, type_value); - if ((err = type_ensure_zero_bits_known(ira->codegen, type_entry))) + if ((err = type_resolve(ira->codegen, type_entry, ResolveStatusAlignmentKnown))) return ira->codegen->builtin_types.entry_invalid; switch (type_entry->id) { @@ -19336,6 +19457,8 @@ static ZigType *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstructionAli } static ZigType *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstructionOverflowOp *instruction) { + Error err; + IrInstruction *type_value = instruction->type_value->other; if (type_is_invalid(type_value->value.type)) return ira->codegen->builtin_types.entry_invalid; @@ -19379,10 +19502,13 @@ static ZigType *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstruction ZigType *expected_ptr_type; if (result_ptr->value.type->id == ZigTypeIdPointer) { + uint32_t alignment; + if ((err = resolve_ptr_align(ira, result_ptr->value.type, &alignment))) + return ira->codegen->builtin_types.entry_invalid; expected_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_type, false, result_ptr->value.type->data.pointer.is_volatile, PtrLenSingle, - result_ptr->value.type->data.pointer.alignment, 0, 0); + alignment, 0, 0); } else { expected_ptr_type = get_pointer_to_type(ira->codegen, dest_type, false); } @@ -19544,8 +19670,7 @@ static ZigType *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, } ZigType *result_type = get_pointer_to_type_extra(ira->codegen, payload_type, ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, - PtrLenSingle, - get_abi_alignment(ira->codegen, payload_type), 0, 0); + PtrLenSingle, 0, 0, 0); if (instr_is_comptime(value)) { ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad); if (!ptr_val) @@ -19624,7 +19749,7 @@ static ZigType *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnP ZigType *param_type = ir_resolve_type(ira, param_type_value); if (type_is_invalid(param_type)) return ira->codegen->builtin_types.entry_invalid; - if ((err = type_ensure_zero_bits_known(ira->codegen, param_type))) + if ((err = type_resolve(ira->codegen, param_type, ResolveStatusZeroBitsKnown))) return ira->codegen->builtin_types.entry_invalid; if (type_requires_comptime(param_type)) { if (!calling_convention_allows_zig_types(fn_type_id.cc)) { @@ -19899,7 +20024,7 @@ static ZigType *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstructionPanic } ZigType *u8_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, - true, false, PtrLenUnknown, get_abi_alignment(ira->codegen, ira->codegen->builtin_types.entry_u8), 0, 0); + true, false, PtrLenUnknown, 0, 0, 0); ZigType *str_type = get_slice_type(ira->codegen, u8_ptr_type); IrInstruction *casted_msg = ir_implicit_cast(ira, msg, str_type); if (type_is_invalid(casted_msg->value.type)) @@ -19912,6 +20037,8 @@ static ZigType *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstructionPanic } static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint32_t align_bytes, bool safety_check_on) { + Error err; + ZigType *target_type = target->value.type; assert(!type_is_invalid(target_type)); @@ -19920,7 +20047,8 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3 if (target_type->id == ZigTypeIdPointer) { result_type = adjust_ptr_align(ira->codegen, target_type, align_bytes); - old_align_bytes = target_type->data.pointer.alignment; + if ((err = resolve_ptr_align(ira, target_type, &old_align_bytes))) + return ira->codegen->invalid_instruction; } else if (target_type->id == ZigTypeIdFn) { FnTypeId fn_type_id = target_type->data.fn.fn_type_id; old_align_bytes = fn_type_id.alignment; @@ -19930,7 +20058,8 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3 target_type->data.maybe.child_type->id == ZigTypeIdPointer) { ZigType *ptr_type = target_type->data.maybe.child_type; - old_align_bytes = ptr_type->data.pointer.alignment; + if ((err = resolve_ptr_align(ira, ptr_type, &old_align_bytes))) + return ira->codegen->invalid_instruction; ZigType *better_ptr_type = adjust_ptr_align(ira->codegen, ptr_type, align_bytes); result_type = get_optional_type(ira->codegen, better_ptr_type); @@ -19944,7 +20073,8 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3 result_type = get_optional_type(ira->codegen, fn_type); } else if (is_slice(target_type)) { ZigType *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index].type_entry; - old_align_bytes = slice_ptr_type->data.pointer.alignment; + if ((err = resolve_ptr_align(ira, slice_ptr_type, &old_align_bytes))) + return ira->codegen->invalid_instruction; ZigType *result_ptr_type = adjust_ptr_align(ira->codegen, slice_ptr_type, align_bytes); result_type = get_slice_type(ira->codegen, result_ptr_type); } else { @@ -20023,8 +20153,13 @@ static ZigType *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtr return dest_type; } - uint32_t src_align_bytes = get_ptr_align(ira->codegen, src_type); - uint32_t dest_align_bytes = get_ptr_align(ira->codegen, dest_type); + uint32_t src_align_bytes; + if ((err = resolve_ptr_align(ira, src_type, &src_align_bytes))) + return ira->codegen->builtin_types.entry_invalid; + + uint32_t dest_align_bytes; + if ((err = resolve_ptr_align(ira, dest_type, &dest_align_bytes))) + return ira->codegen->builtin_types.entry_invalid; if (dest_align_bytes > src_align_bytes) { ErrorMsg *msg = ir_add_error(ira, &instruction->base, buf_sprintf("cast increases pointer alignment")); @@ -20041,7 +20176,7 @@ static ZigType *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtr // Keep the bigger alignment, it can only help- // unless the target is zero bits. - if ((err = type_ensure_zero_bits_known(ira->codegen, dest_type))) + if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown))) return ira->codegen->builtin_types.entry_invalid; IrInstruction *result; @@ -20289,7 +20424,7 @@ static ZigType *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstructionI return ira->codegen->builtin_types.entry_invalid; } - if ((err = type_ensure_zero_bits_known(ira->codegen, dest_type))) + if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown))) return ira->codegen->builtin_types.entry_invalid; if (!type_has_bits(dest_type)) { ir_add_error(ira, dest_type_value, @@ -20440,12 +20575,15 @@ static ZigType *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstructionPtr if (instruction->align_value != nullptr) { if (!ir_resolve_align(ira, instruction->align_value->other, &align_bytes)) return ira->codegen->builtin_types.entry_invalid; + if ((err = type_resolve(ira->codegen, child_type, ResolveStatusAlignmentKnown))) + return ira->codegen->builtin_types.entry_invalid; } else { - if ((err = type_ensure_zero_bits_known(ira->codegen, child_type))) + if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown))) return ira->codegen->builtin_types.entry_invalid; - align_bytes = get_abi_alignment(ira->codegen, child_type); + align_bytes = 0; } + ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); out_val->data.x_type = get_pointer_to_type_extra(ira->codegen, child_type, instruction->is_const, instruction->is_volatile, @@ -21089,7 +21227,7 @@ static ZigType *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstruction return ira->codegen->builtin_types.entry_invalid; } - if ((err = type_ensure_zero_bits_known(ira->codegen, target->value.type))) + if ((err = type_resolve(ira->codegen, target->value.type, ResolveStatusZeroBitsKnown))) return ira->codegen->builtin_types.entry_invalid; ZigType *tag_type = target->value.type->data.enumeration.tag_int_type; @@ -21112,7 +21250,7 @@ static ZigType *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInstruction return ira->codegen->builtin_types.entry_invalid; } - if ((err = type_ensure_zero_bits_known(ira->codegen, dest_type))) + if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown))) return ira->codegen->builtin_types.entry_invalid; ZigType *tag_type = dest_type->data.enumeration.tag_int_type; diff --git a/std/debug/index.zig b/std/debug/index.zig index 14e8b9197a..9ad15ccd7e 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -916,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); @@ -1497,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) diff --git a/test/cases/align.zig b/test/cases/align.zig index 64f0788efc..e052c3c3ad 100644 --- a/test/cases/align.zig +++ b/test/cases/align.zig @@ -212,3 +212,10 @@ fn fnWithAlignedStack() i32 { @setAlignStack(256); return 1234; } + +test "alignment of structs" { + assert(@alignOf(struct { + a: i32, + b: *i32, + }) == @alignOf(usize)); +} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 6bdbca9ff5..40afc6df2d 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -3444,7 +3444,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\export fn entry() usize { return @sizeOf(@typeOf(foo)); } , - ".tmp_source.zig:8:26: error: expected type '*const u3', found '*align(1:3:6) const u3'", + ".tmp_source.zig:8:26: error: expected type '*const u3', found '*align(:3:6) const u3'", ); cases.add( -- cgit v1.2.3