From d64bd30690b042177f084a5c17166777b953dd27 Mon Sep 17 00:00:00 2001
From: dimenus
Date: Wed, 17 Jul 2019 10:58:32 -0500
Subject: [PATCH 01/47] fixed slice length in getEnvVarOwned
---
std/process.zig | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/std/process.zig b/std/process.zig
index b39c6e119672d322c849777710b53ca9f6476446..c74e8c43be479197473d31d9ffa4f17ce9a3bf5f 100644
--- a/std/process.zig
+++ b/std/process.zig
@@ -146,13 +146,12 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned
error.Unexpected => return error.EnvironmentVariableNotFound,
else => |e| return e,
};
-
if (result > buf.len) {
buf = try allocator.realloc(buf, result);
continue;
}
- return std.unicode.utf16leToUtf8Alloc(allocator, buf) catch |err| switch (err) {
+ return std.unicode.utf16leToUtf8Alloc(allocator, buf[0..result]) catch |err| switch (err) {
error.DanglingSurrogateHalf => return error.InvalidUtf8,
error.ExpectedSecondSurrogateHalf => return error.InvalidUtf8,
error.UnexpectedSecondSurrogateHalf => return error.InvalidUtf8,
--
2.54.0
From 95e04e3874dd1284c39182e7909d122ceb1c56c4 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 17 Jul 2019 12:40:48 -0400
Subject: [PATCH 02/47] back to msvc as the default C ABI on Windows
Zig provides a libc for the GNU C ABI on Windows, and cannot (at least
yet) provide one for the MSVC C ABI. However when not linking libc,
zig has no problem targeting MSVC as the C ABI. And this should be the
default.
Related: #2911
---
src/target.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/target.cpp b/src/target.cpp
index 804c42161886475868f7b145449428493454947e..6a949270aefa274a2daefc69cc053616109cbdeb 100644
--- a/src/target.cpp
+++ b/src/target.cpp
@@ -1477,9 +1477,9 @@ ZigLLVM_EnvironmentType target_default_abi(ZigLLVM_ArchType arch, Os os) {
case OsKFreeBSD:
case OsNetBSD:
case OsHurd:
- case OsWindows:
return ZigLLVM_GNU;
case OsUefi:
+ case OsWindows:
return ZigLLVM_MSVC;
case OsLinux:
case OsWASI:
--
2.54.0
From 3879bebc37133ad4160b127a6f3331cf07fe3219 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 17 Jul 2019 16:10:54 -0400
Subject: [PATCH 03/47] WIN32 -> _WIN32
---
src/util.hpp | 2 +-
src/zig_clang.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/util.hpp b/src/util.hpp
index 1fa33b30f98ad1d2ed00f3f384b7856b009011b3..1248635de9c82c81222155c596d49ff049304860 100644
--- a/src/util.hpp
+++ b/src/util.hpp
@@ -43,7 +43,7 @@ ATTRIBUTE_NORETURN
ATTRIBUTE_PRINTF(1, 2)
void zig_panic(const char *format, ...);
-#ifdef WIN32
+#ifdef _WIN32
#define __func__ __FUNCTION__
#endif
diff --git a/src/zig_clang.h b/src/zig_clang.h
index 9d03b592fdae2fdead366d6af8cdfb54edfa7ba8..de17404f2e7e8e7d128a010f3bb71751eda047e2 100644
--- a/src/zig_clang.h
+++ b/src/zig_clang.h
@@ -48,7 +48,7 @@ enum ZigClangAPValue_ValueKind {
struct ZigClangAPValue {
enum ZigClangAPValue_ValueKind Kind;
// experimentally-derived size of clang::APValue::DataType
-#if defined(WIN32) && defined(_MSC_VER)
+#if defined(_WIN32) && defined(_MSC_VER)
char Data[52];
#else
char Data[68];
--
2.54.0
From e5d032982e7a7b76e08341a0a3d9e287c6ef7c94 Mon Sep 17 00:00:00 2001
From: Michael Dusan
Date: Thu, 18 Jul 2019 13:38:11 -0400
Subject: [PATCH 04/47] closes #2916
---
src/ir.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 5193a63ec4b87e272a17dd029aa6f7c76d0de7b7..579875dc3cc58f647eb189369febb2031df35b33 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -14597,7 +14597,7 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp *
for (uint64_t x = 0; x < mult_amt; x += 1) {
for (uint64_t y = 0; y < old_array_len; y += 1) {
copy_const_val(&out_val->data.x_array.data.s_none.elements[i],
- &array_val->data.x_array.data.s_none.elements[y], true);
+ &array_val->data.x_array.data.s_none.elements[y], false);
i += 1;
}
}
--
2.54.0
From 1d07bbbef23993338b231fbd9d7bbf5a349c5f31 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 18 Jul 2019 20:03:38 -0400
Subject: [PATCH 05/47] zig build: add valgrind cli options
---
std/build.zig | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/std/build.zig b/std/build.zig
index f4e9c2b53b03edc0b3ff26d26eaf82f4189dbf39..fc0786094d9e4c17499f9e16cfb19287b30b2a26 100644
--- a/std/build.zig
+++ b/std/build.zig
@@ -1255,6 +1255,8 @@ pub const LibExeObjStep = struct {
libc_file: ?[]const u8 = null,
target_glibc: ?Version = null,
+ valgrind_support: ?bool = null,
+
const LinkObject = union(enum) {
StaticPath: []const u8,
OtherStep: *LibExeObjStep,
@@ -1882,6 +1884,14 @@ pub const LibExeObjStep = struct {
try zig_args.append("--system-linker-hack");
}
+ if (self.valgrind_support) |valgrind_support| {
+ if (valgrind_support) {
+ try zig_args.append("--enable-valgrind");
+ } else {
+ try zig_args.append("--disable-valgrind");
+ }
+ }
+
if (self.override_std_dir) |dir| {
try zig_args.append("--override-std-dir");
try zig_args.append(builder.pathFromRoot(dir));
--
2.54.0
From af8661405b908c0abfc191501a8ad1a59a54e86a Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 19 Jul 2019 16:56:44 -0400
Subject: [PATCH 06/47] fix usingnamespace
It used to be that usingnamespace was only allowed at top level. This
made it OK to put the state inside the AST node data structure. However,
now usingnamespace can occur inside any aggregate data structure, and
therefore the state must be in the TopLevelDeclaration rather than in
the AST node.
There were two other problems with the usingnamespace implementation:
* It was passing the wrong destination ScopeDecl, so it could cause an
incorrect error such as "import of file outside package path".
* When doing `usingnamespace` on a file that already had
`pub usingnamespace` in it would "steal" the usingnamespace, causing
incorrect "use of undeclared identifier" errors in the target file.
closes #2632
closes #2580
---
src/all_types.hpp | 16 +-
src/analyze.cpp | 265 ++++++++++++------------
src/analyze.hpp | 2 -
src/ast_render.cpp | 8 +-
src/ir.cpp | 3 +-
src/parser.cpp | 4 +-
test/compile_errors.zig | 2 +-
test/stage1/behavior.zig | 1 +
test/stage1/behavior/usingnamespace.zig | 14 ++
9 files changed, 170 insertions(+), 145 deletions(-)
create mode 100644 test/stage1/behavior/usingnamespace.zig
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 79ade39ef74b192e357bbc2c9cd98228526e9f20..a6b2bc51c3e727b2286d11adda163eff83bc13ee 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -366,6 +366,7 @@ enum TldId {
TldIdFn,
TldIdContainer,
TldIdCompTime,
+ TldIdUsingNamespace,
};
enum TldResolution {
@@ -413,6 +414,12 @@ struct TldCompTime {
Tld base;
};
+struct TldUsingNamespace {
+ Tld base;
+
+ ConstExprValue *using_namespace_value;
+};
+
struct TypeEnumField {
Buf *name;
BigInt value;
@@ -453,7 +460,7 @@ enum NodeType {
NodeTypeFieldAccessExpr,
NodeTypePtrDeref,
NodeTypeUnwrapOptional,
- NodeTypeUse,
+ NodeTypeUsingNamespace,
NodeTypeBoolLiteral,
NodeTypeNullLiteral,
NodeTypeUndefinedLiteral,
@@ -715,9 +722,6 @@ struct AstNodeArrayType {
struct AstNodeUsingNamespace {
VisibMod visib_mod;
AstNode *expr;
-
- TldResolution resolution;
- ConstExprValue *using_namespace_value;
};
struct AstNodeIfBoolExpr {
@@ -1745,8 +1749,6 @@ struct CodeGen {
ZigList resolve_queue;
size_t resolve_queue_index;
- ZigList use_queue;
- size_t use_queue_index;
ZigList timing_events;
ZigList tld_ref_source_node_stack;
ZigList inline_fns;
@@ -2005,7 +2007,7 @@ struct ScopeDecls {
Scope base;
HashMap decl_table;
- ZigList use_decls;
+ ZigList use_decls;
AstNode *safety_set_node;
AstNode *fast_math_set_node;
ZigType *import;
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 797451c8f84a91c07fee01bc4c3a2099104529c7..de4d64f5d65425084ee33f7dc80ca49a6e2f0758 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -28,6 +28,8 @@ static Error ATTRIBUTE_MUST_USE resolve_union_zero_bits(CodeGen *g, ZigType *uni
static Error ATTRIBUTE_MUST_USE resolve_union_alignment(CodeGen *g, ZigType *union_type);
static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry);
static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status);
+static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope);
+static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope);
static bool is_top_level_struct(ZigType *import) {
return import->id == ZigTypeIdStruct && import->data.structure.root_struct != nullptr;
@@ -2854,6 +2856,8 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) {
add_node_error(g, tld->source_node, buf_sprintf("non-extern function has no body"));
return;
}
+ } else if (tld->id == TldIdUsingNamespace) {
+ g->resolve_queue.append(tld);
}
if (is_export) {
g->resolve_queue.append(tld);
@@ -2867,7 +2871,7 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) {
}
}
- {
+ if (tld->name != nullptr) {
auto entry = decls_scope->decl_table.put_unique(tld->name, tld);
if (entry) {
Tld *other_tld = entry->value;
@@ -2875,9 +2879,7 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) {
add_error_note(g, msg, other_tld->source_node, buf_sprintf("previous definition is here"));
return;
}
- }
- {
ZigType *type;
if (get_primitive_type(g, tld->name, &type) != ErrorPrimitiveTypeNotFound) {
add_node_error(g, tld->source_node,
@@ -2977,12 +2979,14 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
break;
}
- case NodeTypeUse:
- {
- g->use_queue.append(node);
- decls_scope->use_decls.append(node);
- break;
- }
+ case NodeTypeUsingNamespace: {
+ VisibMod visib_mod = node->data.using_namespace.visib_mod;
+ TldUsingNamespace *tld_using_namespace = allocate(1);
+ init_tld(&tld_using_namespace->base, TldIdUsingNamespace, nullptr, visib_mod, node, &decls_scope->base);
+ add_top_level_decl(g, decls_scope, &tld_using_namespace->base);
+ decls_scope->use_decls.append(tld_using_namespace);
+ break;
+ }
case NodeTypeTestDecl:
preview_test_decl(g, node, decls_scope);
break;
@@ -3266,6 +3270,117 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
g->global_vars.append(tld_var);
}
+static void add_symbols_from_container(CodeGen *g, TldUsingNamespace *src_using_namespace,
+ TldUsingNamespace *dst_using_namespace, ScopeDecls* dest_decls_scope)
+{
+ if (src_using_namespace->base.resolution == TldResolutionUnresolved ||
+ src_using_namespace->base.resolution == TldResolutionResolving)
+ {
+ assert(src_using_namespace->base.parent_scope->id == ScopeIdDecls);
+ ScopeDecls *src_decls_scope = (ScopeDecls *)src_using_namespace->base.parent_scope;
+ preview_use_decl(g, src_using_namespace, src_decls_scope);
+ if (src_using_namespace != dst_using_namespace) {
+ resolve_use_decl(g, src_using_namespace, src_decls_scope);
+ }
+ }
+
+ ConstExprValue *use_expr = src_using_namespace->using_namespace_value;
+ if (type_is_invalid(use_expr->type)) {
+ dest_decls_scope->any_imports_failed = true;
+ return;
+ }
+
+ dst_using_namespace->base.resolution = TldResolutionOk;
+
+ assert(use_expr->special != ConstValSpecialRuntime);
+
+ // The source scope for the imported symbols
+ ScopeDecls *src_scope = get_container_scope(use_expr->data.x_type);
+ // The top-level container where the symbols are defined, it's used in the
+ // loop below in order to exclude the ones coming from an import statement
+ ZigType *src_import = get_scope_import(&src_scope->base);
+ assert(src_import != nullptr);
+
+ if (src_scope->any_imports_failed) {
+ dest_decls_scope->any_imports_failed = true;
+ }
+
+ auto it = src_scope->decl_table.entry_iterator();
+ for (;;) {
+ auto *entry = it.next();
+ if (!entry)
+ break;
+
+ Buf *target_tld_name = entry->key;
+ Tld *target_tld = entry->value;
+
+ if (target_tld->visib_mod == VisibModPrivate) {
+ continue;
+ }
+
+ if (target_tld->import != src_import) {
+ continue;
+ }
+
+ auto existing_entry = dest_decls_scope->decl_table.put_unique(target_tld_name, target_tld);
+ if (existing_entry) {
+ Tld *existing_decl = existing_entry->value;
+ if (existing_decl != target_tld) {
+ ErrorMsg *msg = add_node_error(g, dst_using_namespace->base.source_node,
+ buf_sprintf("import of '%s' overrides existing definition",
+ buf_ptr(target_tld_name)));
+ add_error_note(g, msg, existing_decl->source_node, buf_sprintf("previous definition here"));
+ add_error_note(g, msg, target_tld->source_node, buf_sprintf("imported definition here"));
+ }
+ }
+ }
+
+ for (size_t i = 0; i < src_scope->use_decls.length; i += 1) {
+ TldUsingNamespace *tld_using_namespace = src_scope->use_decls.at(i);
+ if (tld_using_namespace->base.visib_mod != VisibModPrivate)
+ add_symbols_from_container(g, tld_using_namespace, dst_using_namespace, dest_decls_scope);
+ }
+}
+
+static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope) {
+ if (tld_using_namespace->base.resolution == TldResolutionOk ||
+ tld_using_namespace->base.resolution == TldResolutionInvalid)
+ {
+ return;
+ }
+ add_symbols_from_container(g, tld_using_namespace, tld_using_namespace, dest_decls_scope);
+}
+
+static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope) {
+ if (using_namespace->base.resolution == TldResolutionOk ||
+ using_namespace->base.resolution == TldResolutionInvalid)
+ {
+ return;
+ }
+
+ using_namespace->base.resolution = TldResolutionResolving;
+ assert(using_namespace->base.source_node->type == NodeTypeUsingNamespace);
+ ConstExprValue *result = analyze_const_value(g, &dest_decls_scope->base,
+ using_namespace->base.source_node->data.using_namespace.expr, g->builtin_types.entry_type, nullptr);
+ using_namespace->using_namespace_value = result;
+
+ if (type_is_invalid(result->type)) {
+ dest_decls_scope->any_imports_failed = true;
+ using_namespace->base.resolution = TldResolutionInvalid;
+ using_namespace->using_namespace_value = &g->invalid_instruction->value;
+ return;
+ }
+
+ if (!is_container(result->data.x_type)) {
+ add_node_error(g, using_namespace->base.source_node,
+ buf_sprintf("expected struct, enum, or union; found '%s'", buf_ptr(&result->data.x_type->name)));
+ dest_decls_scope->any_imports_failed = true;
+ using_namespace->base.resolution = TldResolutionInvalid;
+ using_namespace->using_namespace_value = &g->invalid_instruction->value;
+ return;
+ }
+}
+
void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node) {
if (tld->resolution != TldResolutionUnresolved)
return;
@@ -3299,6 +3414,14 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node) {
resolve_decl_comptime(g, tld_comptime);
break;
}
+ case TldIdUsingNamespace: {
+ TldUsingNamespace *tld_using_namespace = (TldUsingNamespace *)tld;
+ assert(tld_using_namespace->base.parent_scope->id == ScopeIdDecls);
+ ScopeDecls *dest_decls_scope = (ScopeDecls *)tld_using_namespace->base.parent_scope;
+ preview_use_decl(g, tld_using_namespace, dest_decls_scope);
+ resolve_use_decl(g, tld_using_namespace, dest_decls_scope);
+ break;
+ }
}
tld->resolution = TldResolutionOk;
@@ -3308,10 +3431,10 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node) {
Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name) {
// resolve all the using_namespace decls
for (size_t i = 0; i < decls_scope->use_decls.length; i += 1) {
- AstNode *use_decl_node = decls_scope->use_decls.at(i);
- if (use_decl_node->data.using_namespace.resolution == TldResolutionUnresolved) {
- preview_use_decl(g, use_decl_node, decls_scope);
- resolve_use_decl(g, use_decl_node, decls_scope);
+ TldUsingNamespace *tld_using_namespace = decls_scope->use_decls.at(i);
+ if (tld_using_namespace->base.resolution == TldResolutionUnresolved) {
+ preview_use_decl(g, tld_using_namespace, decls_scope);
+ resolve_use_decl(g, tld_using_namespace, decls_scope);
}
}
@@ -3752,110 +3875,6 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) {
analyze_fn_ir(g, fn_table_entry, return_type_node);
}
-static void add_symbols_from_container(CodeGen *g, AstNode *src_use_node, AstNode *dst_use_node, ScopeDecls* decls_scope) {
- if (src_use_node->data.using_namespace.resolution == TldResolutionUnresolved) {
- preview_use_decl(g, src_use_node, decls_scope);
- }
-
- ConstExprValue *use_expr = src_use_node->data.using_namespace.using_namespace_value;
- if (type_is_invalid(use_expr->type)) {
- decls_scope->any_imports_failed = true;
- return;
- }
-
- dst_use_node->data.using_namespace.resolution = TldResolutionOk;
-
- assert(use_expr->special != ConstValSpecialRuntime);
-
- // The source struct for the imported symbols
- ZigType *src_ty = use_expr->data.x_type;
- assert(src_ty);
-
- if (!is_container(src_ty)) {
- add_node_error(g, dst_use_node,
- buf_sprintf("expected struct, enum, or union; found '%s'", buf_ptr(&src_ty->name)));
- decls_scope->any_imports_failed = true;
- return;
- }
-
- // The source scope for the imported symbols
- ScopeDecls *src_scope = get_container_scope(src_ty);
- // The top-level container where the symbols are defined, it's used in the
- // loop below in order to exclude the ones coming from an import statement
- ZigType *src_import = get_scope_import(&src_scope->base);
- assert(src_import != nullptr);
-
- if (src_scope->any_imports_failed) {
- decls_scope->any_imports_failed = true;
- }
-
- auto it = src_scope->decl_table.entry_iterator();
- for (;;) {
- auto *entry = it.next();
- if (!entry)
- break;
-
- Buf *target_tld_name = entry->key;
- Tld *target_tld = entry->value;
-
- if (target_tld->visib_mod == VisibModPrivate) {
- continue;
- }
-
- if (target_tld->import != src_import) {
- continue;
- }
-
- auto existing_entry = decls_scope->decl_table.put_unique(target_tld_name, target_tld);
- if (existing_entry) {
- Tld *existing_decl = existing_entry->value;
- if (existing_decl != target_tld) {
- ErrorMsg *msg = add_node_error(g, dst_use_node,
- buf_sprintf("import of '%s' overrides existing definition",
- buf_ptr(target_tld_name)));
- add_error_note(g, msg, existing_decl->source_node, buf_sprintf("previous definition here"));
- add_error_note(g, msg, target_tld->source_node, buf_sprintf("imported definition here"));
- }
- }
- }
-
- for (size_t i = 0; i < src_scope->use_decls.length; i += 1) {
- AstNode *use_decl_node = src_scope->use_decls.at(i);
- if (use_decl_node->data.using_namespace.visib_mod != VisibModPrivate)
- add_symbols_from_container(g, use_decl_node, dst_use_node, decls_scope);
- }
-}
-
-void resolve_use_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope) {
- assert(node->type == NodeTypeUse);
-
- if (node->data.using_namespace.resolution == TldResolutionOk ||
- node->data.using_namespace.resolution == TldResolutionInvalid)
- {
- return;
- }
- add_symbols_from_container(g, node, node, decls_scope);
-}
-
-void preview_use_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope) {
- assert(node->type == NodeTypeUse);
-
- if (node->data.using_namespace.resolution == TldResolutionOk ||
- node->data.using_namespace.resolution == TldResolutionInvalid)
- {
- return;
- }
-
- node->data.using_namespace.resolution = TldResolutionResolving;
- ConstExprValue *result = analyze_const_value(g, &decls_scope->base,
- node->data.using_namespace.expr, g->builtin_types.entry_type, nullptr);
-
- if (type_is_invalid(result->type))
- decls_scope->any_imports_failed = true;
-
- node->data.using_namespace.using_namespace_value = result;
-}
-
ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Buf *source_code,
SourceKind source_kind)
{
@@ -3975,18 +3994,8 @@ ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Bu
void semantic_analyze(CodeGen *g) {
while (g->resolve_queue_index < g->resolve_queue.length ||
- g->fn_defs_index < g->fn_defs.length ||
- g->use_queue_index < g->use_queue.length)
+ g->fn_defs_index < g->fn_defs.length)
{
- for (; g->use_queue_index < g->use_queue.length; g->use_queue_index += 1) {
- AstNode *use_decl_node = g->use_queue.at(g->use_queue_index);
- // Get the top-level scope where `using_namespace` is used
- ScopeDecls *decls_scope = get_container_scope(use_decl_node->owner);
- if (use_decl_node->data.using_namespace.resolution == TldResolutionUnresolved) {
- preview_use_decl(g, use_decl_node, decls_scope);
- resolve_use_decl(g, use_decl_node, decls_scope);
- }
- }
for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) {
Tld *tld = g->resolve_queue.at(g->resolve_queue_index);
AstNode *source_node = nullptr;
diff --git a/src/analyze.hpp b/src/analyze.hpp
index a6ad92110e4ba8b0e6349cd3cd8a690d28f4c9de..b9e9f2df7daa44cdff41d5b04a9bbd6b09e01169 100644
--- a/src/analyze.hpp
+++ b/src/analyze.hpp
@@ -86,8 +86,6 @@ bool is_array_ref(ZigType *type_entry);
bool is_container_ref(ZigType *type_entry);
bool is_valid_vector_elem_type(ZigType *elem_type);
void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);
-void preview_use_decl(CodeGen *g, AstNode *node, ScopeDecls* decls_scope);
-void resolve_use_decl(CodeGen *g, AstNode *node, ScopeDecls* decls_scope);
ZigFn *scope_fn_entry(Scope *scope);
ZigPackage *scope_package(Scope *scope);
ZigType *get_scope_import(Scope *scope);
diff --git a/src/ast_render.cpp b/src/ast_render.cpp
index 154803f8846b915dc10b46979985cf735104aa41..fe131ab65f2390326c5ec4c2232d4fc49957def3 100644
--- a/src/ast_render.cpp
+++ b/src/ast_render.cpp
@@ -193,8 +193,8 @@ static const char *node_type_str(NodeType node_type) {
return "Symbol";
case NodeTypePrefixOpExpr:
return "PrefixOpExpr";
- case NodeTypeUse:
- return "Use";
+ case NodeTypeUsingNamespace:
+ return "UsingNamespace";
case NodeTypeBoolLiteral:
return "BoolLiteral";
case NodeTypeNullLiteral:
@@ -791,7 +791,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
AstNode *decls_node = node->data.container_decl.decls.at(decl_i);
render_node_grouped(ar, decls_node);
- if (decls_node->type == NodeTypeUse ||
+ if (decls_node->type == NodeTypeUsingNamespace ||
decls_node->type == NodeTypeVariableDeclaration ||
decls_node->type == NodeTypeFnProto)
{
@@ -1170,7 +1170,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
case NodeTypeParamDecl:
case NodeTypeTestDecl:
case NodeTypeStructField:
- case NodeTypeUse:
+ case NodeTypeUsingNamespace:
zig_panic("TODO more ast rendering");
}
}
diff --git a/src/ir.cpp b/src/ir.cpp
index 579875dc3cc58f647eb189369febb2031df35b33..be7a8e2e5124b054cfb96ea3b9268e4c21d05d66 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -8430,7 +8430,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
switch (node->type) {
case NodeTypeStructValueField:
case NodeTypeParamDecl:
- case NodeTypeUse:
+ case NodeTypeUsingNamespace:
case NodeTypeSwitchProng:
case NodeTypeSwitchRange:
case NodeTypeStructField:
@@ -17847,6 +17847,7 @@ static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_
switch (tld->id) {
case TldIdContainer:
case TldIdCompTime:
+ case TldIdUsingNamespace:
zig_unreachable();
case TldIdVar:
{
diff --git a/src/parser.cpp b/src/parser.cpp
index 0783d4ec1015960e4318833f6b580aaeffa67caf..fe1f89ac9297fbba517c44dc20c414365d40e612 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -676,7 +676,7 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod) {
AstNode *expr = ast_expect(pc, ast_parse_expr);
expect_token(pc, TokenIdSemicolon);
- AstNode *res = ast_create_node(pc, NodeTypeUse, usingnamespace);
+ AstNode *res = ast_create_node(pc, NodeTypeUsingNamespace, usingnamespace);
res->data.using_namespace.visib_mod = visib_mod;
res->data.using_namespace.expr = expr;
return res;
@@ -2938,7 +2938,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
case NodeTypeUnwrapOptional:
visit_field(&node->data.unwrap_optional.expr, visit, context);
break;
- case NodeTypeUse:
+ case NodeTypeUsingNamespace:
visit_field(&node->data.using_namespace.expr, visit, context);
break;
case NodeTypeBoolLiteral:
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index fd365235d81aa48fd9ef4a85b41de1192ba0e80a..40ce8d304b91ff8aa4c21c7a15705c7ef59c760a 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -234,7 +234,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
cases.add(
"usingnamespace with wrong type",
- \\use void;
+ \\usingnamespace void;
,
"tmp.zig:1:1: error: expected struct, enum, or union; found 'void'",
);
diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig
index db8fdcf3683bc25f55d893b277020959f320f365..71af5586ed92b0ac7d424f5325191736608c5d4f 100644
--- a/test/stage1/behavior.zig
+++ b/test/stage1/behavior.zig
@@ -93,6 +93,7 @@ comptime {
_ = @import("behavior/undefined.zig");
_ = @import("behavior/underscore.zig");
_ = @import("behavior/union.zig");
+ _ = @import("behavior/usingnamespace.zig");
_ = @import("behavior/var_args.zig");
_ = @import("behavior/vector.zig");
_ = @import("behavior/void.zig");
diff --git a/test/stage1/behavior/usingnamespace.zig b/test/stage1/behavior/usingnamespace.zig
new file mode 100644
index 0000000000000000000000000000000000000000..fb45a9392da4137e00841d081e7305a6676678a8
--- /dev/null
+++ b/test/stage1/behavior/usingnamespace.zig
@@ -0,0 +1,14 @@
+const std = @import("std");
+
+fn Foo(comptime T: type) type {
+ return struct {
+ usingnamespace T;
+ };
+}
+
+test "usingnamespace inside a generic struct" {
+ const std2 = Foo(std);
+ const testing2 = Foo(std.testing);
+ std2.testing.expect(true);
+ testing2.expect(true);
+}
--
2.54.0
From d4ff27180b31d7a4a5c284453b37d5301aece06d Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Wed, 12 Jun 2019 14:00:25 -0500
Subject: [PATCH 07/47] Tokenize '&&' as AmpersandAmpersand
---
std/zig/tokenizer.zig | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/std/zig/tokenizer.zig b/std/zig/tokenizer.zig
index 7bd5c537d3c0035b39705c6b31b926abd8c33ae6..df39c04f91b05fbacbbd19c68c4e11e21e689623 100644
--- a/std/zig/tokenizer.zig
+++ b/std/zig/tokenizer.zig
@@ -125,6 +125,7 @@ pub const Token = struct {
SlashEqual,
Comma,
Ampersand,
+ AmpersandAmpersand,
AmpersandEqual,
QuestionMark,
AngleBracketLeft,
@@ -484,6 +485,10 @@ pub const Tokenizer = struct {
},
State.Ampersand => switch (c) {
+ '&' => {
+ result.id = Token.Id.AmpersandAmpersand;
+ break;
+ },
'=' => {
result.id = Token.Id.AmpersandEqual;
self.index += 1;
--
2.54.0
From 4708fb23c0d96de171d173e252689d26cd01b102 Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Thu, 20 Jun 2019 22:06:20 -0500
Subject: [PATCH 08/47] Generate parse error from &&
---
std/zig/ast.zig | 4 ++++
std/zig/parse.zig | 14 +++++++++++++-
2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/std/zig/ast.zig b/std/zig/ast.zig
index 79d1ae8dada16a2186a9342a3e1b81843cd5cb30..72a5234f6159d62ca43bb463615155be0a45ac36 100644
--- a/std/zig/ast.zig
+++ b/std/zig/ast.zig
@@ -113,6 +113,7 @@ pub const Tree = struct {
pub const Error = union(enum) {
InvalidToken: InvalidToken,
+ InvalidAmpersandAmpersand: InvalidAmpersandAmpersand,
ExpectedContainerMembers: ExpectedContainerMembers,
ExpectedStringLiteral: ExpectedStringLiteral,
ExpectedIntegerLiteral: ExpectedIntegerLiteral,
@@ -161,6 +162,7 @@ pub const Error = union(enum) {
switch (self.*) {
// TODO https://github.com/ziglang/zig/issues/683
@TagType(Error).InvalidToken => |*x| return x.render(tokens, stream),
+ @TagType(Error).InvalidAmpersandAmpersand => |*x| return x.render(tokens, stream),
@TagType(Error).ExpectedContainerMembers => |*x| return x.render(tokens, stream),
@TagType(Error).ExpectedStringLiteral => |*x| return x.render(tokens, stream),
@TagType(Error).ExpectedIntegerLiteral => |*x| return x.render(tokens, stream),
@@ -211,6 +213,7 @@ pub const Error = union(enum) {
switch (self.*) {
// TODO https://github.com/ziglang/zig/issues/683
@TagType(Error).InvalidToken => |x| return x.token,
+ @TagType(Error).InvalidAmpersandAmpersand => |x| return x.token,
@TagType(Error).ExpectedContainerMembers => |x| return x.token,
@TagType(Error).ExpectedStringLiteral => |x| return x.token,
@TagType(Error).ExpectedIntegerLiteral => |x| return x.token,
@@ -291,6 +294,7 @@ pub const Error = union(enum) {
pub const ExpectedDerefOrUnwrap = SingleTokenError("Expected pointer dereference or optional unwrap, found {}");
pub const ExpectedSuffixOp = SingleTokenError("Expected pointer dereference, optional unwrap, or field access, found {}");
+ pub const InvalidAmpersandAmpersand = SimpleError("Invalid token '&&', 'and' performs boolean AND");
pub const ExpectedParamType = SimpleError("Expected parameter type");
pub const ExpectedPubItem = SimpleError("Pub must be followed by fn decl, var decl, or container member");
pub const UnattachedDocComment = SimpleError("Unattached documentation comment");
diff --git a/std/zig/parse.zig b/std/zig/parse.zig
index 4f3fb76b54361bacd715b4c8f0a16a6a305e444b..0daa9f35a8afa52d726d9724dccb5db0aa7ab4c8 100644
--- a/std/zig/parse.zig
+++ b/std/zig/parse.zig
@@ -774,7 +774,7 @@ fn parseBoolAndExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
arena,
it,
tree,
- SimpleBinOpParseFn(.Keyword_and, Node.InfixOp.Op.BoolAnd),
+ parseAmpersandAmpersandOp,
parseCompareExpr,
.Infinitely,
);
@@ -2687,6 +2687,18 @@ fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) No
// Helper parsers not included in the grammar
+fn parseAmpersandAmpersandOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
+ const op_parse_and = SimpleBinOpParseFn(.Keyword_and, Node.InfixOp.Op.BoolAnd);
+ const op_token = eatToken(it, .AmpersandAmpersand);
+ if (op_token != null) {
+ try tree.errors.push(AstError{
+ .InvalidAmpersandAmpersand = AstError.InvalidAmpersandAmpersand{ .token = it.index },
+ });
+ return error.ParseError;
+ }
+ return op_parse_and(arena, it, tree);
+}
+
fn parseBuiltinCall(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const token = eatToken(it, .Builtin) orelse return null;
const params = (try parseFnCallArguments(arena, it, tree)) orelse {
--
2.54.0
From 484f8a4cc217fc08d09160ea02d8de6e122b07e9 Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Thu, 20 Jun 2019 23:11:41 -0500
Subject: [PATCH 09/47] Switch old switch / @TagType() to use inferred enums
---
std/zig/ast.zig | 198 ++++++++++++++++++++++++------------------------
1 file changed, 98 insertions(+), 100 deletions(-)
diff --git a/std/zig/ast.zig b/std/zig/ast.zig
index 72a5234f6159d62ca43bb463615155be0a45ac36..f648ced94386c7aca8005567c515720b2b5461bf 100644
--- a/std/zig/ast.zig
+++ b/std/zig/ast.zig
@@ -160,103 +160,101 @@ pub const Error = union(enum) {
pub fn render(self: *const Error, tokens: *Tree.TokenList, stream: var) !void {
switch (self.*) {
- // TODO https://github.com/ziglang/zig/issues/683
- @TagType(Error).InvalidToken => |*x| return x.render(tokens, stream),
- @TagType(Error).InvalidAmpersandAmpersand => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedContainerMembers => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedStringLiteral => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedIntegerLiteral => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedPubItem => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedIdentifier => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedStatement => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedVarDeclOrFn => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedVarDecl => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedReturnType => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedAggregateKw => |*x| return x.render(tokens, stream),
- @TagType(Error).UnattachedDocComment => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedEqOrSemi => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedSemiOrLBrace => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedSemiOrElse => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedLabelOrLBrace => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedLBrace => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedColonOrRParen => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedLabelable => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedInlinable => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedAsmOutputReturnOrType => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedCall => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedCallOrFnProto => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedSliceOrRBracket => |*x| return x.render(tokens, stream),
- @TagType(Error).ExtraAlignQualifier => |*x| return x.render(tokens, stream),
- @TagType(Error).ExtraConstQualifier => |*x| return x.render(tokens, stream),
- @TagType(Error).ExtraVolatileQualifier => |*x| return x.render(tokens, stream),
- @TagType(Error).ExtraAllowZeroQualifier => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedTypeExpr => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedPrimaryTypeExpr => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedParamType => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedExpr => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedPrimaryExpr => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedToken => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedCommaOrEnd => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedParamList => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedPayload => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedBlockOrAssignment => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedBlockOrExpression => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedExprOrAssignment => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedPrefixExpr => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedLoopExpr => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedDerefOrUnwrap => |*x| return x.render(tokens, stream),
- @TagType(Error).ExpectedSuffixOp => |*x| return x.render(tokens, stream),
+ .InvalidToken => |*x| return x.render(tokens, stream),
+ .InvalidAmpersandAmpersand => |*x| return x.render(tokens, stream),
+ .ExpectedContainerMembers => |*x| return x.render(tokens, stream),
+ .ExpectedStringLiteral => |*x| return x.render(tokens, stream),
+ .ExpectedIntegerLiteral => |*x| return x.render(tokens, stream),
+ .ExpectedPubItem => |*x| return x.render(tokens, stream),
+ .ExpectedIdentifier => |*x| return x.render(tokens, stream),
+ .ExpectedStatement => |*x| return x.render(tokens, stream),
+ .ExpectedVarDeclOrFn => |*x| return x.render(tokens, stream),
+ .ExpectedVarDecl => |*x| return x.render(tokens, stream),
+ .ExpectedReturnType => |*x| return x.render(tokens, stream),
+ .ExpectedAggregateKw => |*x| return x.render(tokens, stream),
+ .UnattachedDocComment => |*x| return x.render(tokens, stream),
+ .ExpectedEqOrSemi => |*x| return x.render(tokens, stream),
+ .ExpectedSemiOrLBrace => |*x| return x.render(tokens, stream),
+ .ExpectedSemiOrElse => |*x| return x.render(tokens, stream),
+ .ExpectedLabelOrLBrace => |*x| return x.render(tokens, stream),
+ .ExpectedLBrace => |*x| return x.render(tokens, stream),
+ .ExpectedColonOrRParen => |*x| return x.render(tokens, stream),
+ .ExpectedLabelable => |*x| return x.render(tokens, stream),
+ .ExpectedInlinable => |*x| return x.render(tokens, stream),
+ .ExpectedAsmOutputReturnOrType => |*x| return x.render(tokens, stream),
+ .ExpectedCall => |*x| return x.render(tokens, stream),
+ .ExpectedCallOrFnProto => |*x| return x.render(tokens, stream),
+ .ExpectedSliceOrRBracket => |*x| return x.render(tokens, stream),
+ .ExtraAlignQualifier => |*x| return x.render(tokens, stream),
+ .ExtraConstQualifier => |*x| return x.render(tokens, stream),
+ .ExtraVolatileQualifier => |*x| return x.render(tokens, stream),
+ .ExtraAllowZeroQualifier => |*x| return x.render(tokens, stream),
+ .ExpectedTypeExpr => |*x| return x.render(tokens, stream),
+ .ExpectedPrimaryTypeExpr => |*x| return x.render(tokens, stream),
+ .ExpectedParamType => |*x| return x.render(tokens, stream),
+ .ExpectedExpr => |*x| return x.render(tokens, stream),
+ .ExpectedPrimaryExpr => |*x| return x.render(tokens, stream),
+ .ExpectedToken => |*x| return x.render(tokens, stream),
+ .ExpectedCommaOrEnd => |*x| return x.render(tokens, stream),
+ .ExpectedParamList => |*x| return x.render(tokens, stream),
+ .ExpectedPayload => |*x| return x.render(tokens, stream),
+ .ExpectedBlockOrAssignment => |*x| return x.render(tokens, stream),
+ .ExpectedBlockOrExpression => |*x| return x.render(tokens, stream),
+ .ExpectedExprOrAssignment => |*x| return x.render(tokens, stream),
+ .ExpectedPrefixExpr => |*x| return x.render(tokens, stream),
+ .ExpectedLoopExpr => |*x| return x.render(tokens, stream),
+ .ExpectedDerefOrUnwrap => |*x| return x.render(tokens, stream),
+ .ExpectedSuffixOp => |*x| return x.render(tokens, stream),
}
}
pub fn loc(self: *const Error) TokenIndex {
switch (self.*) {
- // TODO https://github.com/ziglang/zig/issues/683
- @TagType(Error).InvalidToken => |x| return x.token,
- @TagType(Error).InvalidAmpersandAmpersand => |x| return x.token,
- @TagType(Error).ExpectedContainerMembers => |x| return x.token,
- @TagType(Error).ExpectedStringLiteral => |x| return x.token,
- @TagType(Error).ExpectedIntegerLiteral => |x| return x.token,
- @TagType(Error).ExpectedPubItem => |x| return x.token,
- @TagType(Error).ExpectedIdentifier => |x| return x.token,
- @TagType(Error).ExpectedStatement => |x| return x.token,
- @TagType(Error).ExpectedVarDeclOrFn => |x| return x.token,
- @TagType(Error).ExpectedVarDecl => |x| return x.token,
- @TagType(Error).ExpectedReturnType => |x| return x.token,
- @TagType(Error).ExpectedAggregateKw => |x| return x.token,
- @TagType(Error).UnattachedDocComment => |x| return x.token,
- @TagType(Error).ExpectedEqOrSemi => |x| return x.token,
- @TagType(Error).ExpectedSemiOrLBrace => |x| return x.token,
- @TagType(Error).ExpectedSemiOrElse => |x| return x.token,
- @TagType(Error).ExpectedLabelOrLBrace => |x| return x.token,
- @TagType(Error).ExpectedLBrace => |x| return x.token,
- @TagType(Error).ExpectedColonOrRParen => |x| return x.token,
- @TagType(Error).ExpectedLabelable => |x| return x.token,
- @TagType(Error).ExpectedInlinable => |x| return x.token,
- @TagType(Error).ExpectedAsmOutputReturnOrType => |x| return x.token,
- @TagType(Error).ExpectedCall => |x| return x.node.firstToken(),
- @TagType(Error).ExpectedCallOrFnProto => |x| return x.node.firstToken(),
- @TagType(Error).ExpectedSliceOrRBracket => |x| return x.token,
- @TagType(Error).ExtraAlignQualifier => |x| return x.token,
- @TagType(Error).ExtraConstQualifier => |x| return x.token,
- @TagType(Error).ExtraVolatileQualifier => |x| return x.token,
- @TagType(Error).ExtraAllowZeroQualifier => |x| return x.token,
- @TagType(Error).ExpectedTypeExpr => |x| return x.token,
- @TagType(Error).ExpectedPrimaryTypeExpr => |x| return x.token,
- @TagType(Error).ExpectedParamType => |x| return x.token,
- @TagType(Error).ExpectedExpr => |x| return x.token,
- @TagType(Error).ExpectedPrimaryExpr => |x| return x.token,
- @TagType(Error).ExpectedToken => |x| return x.token,
- @TagType(Error).ExpectedCommaOrEnd => |x| return x.token,
- @TagType(Error).ExpectedParamList => |x| return x.token,
- @TagType(Error).ExpectedPayload => |x| return x.token,
- @TagType(Error).ExpectedBlockOrAssignment => |x| return x.token,
- @TagType(Error).ExpectedBlockOrExpression => |x| return x.token,
- @TagType(Error).ExpectedExprOrAssignment => |x| return x.token,
- @TagType(Error).ExpectedPrefixExpr => |x| return x.token,
- @TagType(Error).ExpectedLoopExpr => |x| return x.token,
- @TagType(Error).ExpectedDerefOrUnwrap => |x| return x.token,
- @TagType(Error).ExpectedSuffixOp => |x| return x.token,
+ .InvalidToken => |x| return x.token,
+ .InvalidAmpersandAmpersand => |x| return x.token,
+ .ExpectedContainerMembers => |x| return x.token,
+ .ExpectedStringLiteral => |x| return x.token,
+ .ExpectedIntegerLiteral => |x| return x.token,
+ .ExpectedPubItem => |x| return x.token,
+ .ExpectedIdentifier => |x| return x.token,
+ .ExpectedStatement => |x| return x.token,
+ .ExpectedVarDeclOrFn => |x| return x.token,
+ .ExpectedVarDecl => |x| return x.token,
+ .ExpectedReturnType => |x| return x.token,
+ .ExpectedAggregateKw => |x| return x.token,
+ .UnattachedDocComment => |x| return x.token,
+ .ExpectedEqOrSemi => |x| return x.token,
+ .ExpectedSemiOrLBrace => |x| return x.token,
+ .ExpectedSemiOrElse => |x| return x.token,
+ .ExpectedLabelOrLBrace => |x| return x.token,
+ .ExpectedLBrace => |x| return x.token,
+ .ExpectedColonOrRParen => |x| return x.token,
+ .ExpectedLabelable => |x| return x.token,
+ .ExpectedInlinable => |x| return x.token,
+ .ExpectedAsmOutputReturnOrType => |x| return x.token,
+ .ExpectedCall => |x| return x.node.firstToken(),
+ .ExpectedCallOrFnProto => |x| return x.node.firstToken(),
+ .ExpectedSliceOrRBracket => |x| return x.token,
+ .ExtraAlignQualifier => |x| return x.token,
+ .ExtraConstQualifier => |x| return x.token,
+ .ExtraVolatileQualifier => |x| return x.token,
+ .ExtraAllowZeroQualifier => |x| return x.token,
+ .ExpectedTypeExpr => |x| return x.token,
+ .ExpectedPrimaryTypeExpr => |x| return x.token,
+ .ExpectedParamType => |x| return x.token,
+ .ExpectedExpr => |x| return x.token,
+ .ExpectedPrimaryExpr => |x| return x.token,
+ .ExpectedToken => |x| return x.token,
+ .ExpectedCommaOrEnd => |x| return x.token,
+ .ExpectedParamList => |x| return x.token,
+ .ExpectedPayload => |x| return x.token,
+ .ExpectedBlockOrAssignment => |x| return x.token,
+ .ExpectedBlockOrExpression => |x| return x.token,
+ .ExpectedExprOrAssignment => |x| return x.token,
+ .ExpectedPrefixExpr => |x| return x.token,
+ .ExpectedLoopExpr => |x| return x.token,
+ .ExpectedDerefOrUnwrap => |x| return x.token,
+ .ExpectedSuffixOp => |x| return x.token,
}
}
@@ -1712,15 +1710,15 @@ pub const Node = struct {
i -= 1;
switch (self.op) {
- @TagType(Op).Call => |*call_info| {
+ .Call => |*call_info| {
if (i < call_info.params.len) return call_info.params.at(i).*;
i -= call_info.params.len;
},
- Op.ArrayAccess => |index_expr| {
+ .ArrayAccess => |index_expr| {
if (i < 1) return index_expr;
i -= 1;
},
- @TagType(Op).Slice => |range| {
+ .Slice => |range| {
if (i < 1) return range.start;
i -= 1;
@@ -1729,16 +1727,16 @@ pub const Node = struct {
i -= 1;
}
},
- Op.ArrayInitializer => |*exprs| {
+ .ArrayInitializer => |*exprs| {
if (i < exprs.len) return exprs.at(i).*;
i -= exprs.len;
},
- Op.StructInitializer => |*fields| {
+ .StructInitializer => |*fields| {
if (i < fields.len) return fields.at(i).*;
i -= fields.len;
},
- Op.UnwrapOptional,
- Op.Deref,
+ .UnwrapOptional,
+ .Deref,
=> {},
}
@@ -1747,7 +1745,7 @@ pub const Node = struct {
pub fn firstToken(self: *const SuffixOp) TokenIndex {
switch (self.op) {
- @TagType(Op).Call => |*call_info| if (call_info.async_attr) |async_attr| return async_attr.firstToken(),
+ .Call => |*call_info| if (call_info.async_attr) |async_attr| return async_attr.firstToken(),
else => {},
}
return self.lhs.firstToken();
--
2.54.0
From 111d3792e0f2d92f7b9f73fb8265ee17fc229eb4 Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Mon, 24 Jun 2019 23:31:59 -0500
Subject: [PATCH 10/47] Docgen invalid for &&
---
doc/docgen.zig | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/doc/docgen.zig b/doc/docgen.zig
index bff110449c9e04659b09924342ceceee0deed5dc..831241de0f3705c7f740234a26f37c663b76e938 100644
--- a/doc/docgen.zig
+++ b/doc/docgen.zig
@@ -929,7 +929,9 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
std.zig.Token.Id.BracketStarCBracket,
=> try writeEscaped(out, src[token.start..token.end]),
- std.zig.Token.Id.Invalid => return parseError(
+ std.zig.Token.Id.AmpersandAmpersand,
+ std.zig.Token.Id.Invalid,
+ => return parseError(
docgen_tokenizer,
source_token,
"syntax error",
--
2.54.0
From 8ea8cff4912bf66b8e95b7518877c7f55c7a9356 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 19 Jul 2019 17:54:06 -0400
Subject: [PATCH 11/47] slightly simpler implementation
---
doc/docgen.zig | 236 +++++++++++++++++++++---------------------
std/zig/ast.zig | 19 ++--
std/zig/parse.zig | 14 +--
std/zig/tokenizer.zig | 5 +-
4 files changed, 134 insertions(+), 140 deletions(-)
diff --git a/doc/docgen.zig b/doc/docgen.zig
index 831241de0f3705c7f740234a26f37c663b76e938..3d3dcba76d5cb27e325de4063f6df2dc425cfa4e 100644
--- a/doc/docgen.zig
+++ b/doc/docgen.zig
@@ -742,101 +742,101 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
const token = tokenizer.next();
try writeEscaped(out, src[index..token.start]);
switch (token.id) {
- std.zig.Token.Id.Eof => break,
+ .Eof => break,
- std.zig.Token.Id.Keyword_align,
- std.zig.Token.Id.Keyword_and,
- std.zig.Token.Id.Keyword_asm,
- std.zig.Token.Id.Keyword_async,
- std.zig.Token.Id.Keyword_await,
- std.zig.Token.Id.Keyword_break,
- std.zig.Token.Id.Keyword_cancel,
- std.zig.Token.Id.Keyword_catch,
- std.zig.Token.Id.Keyword_comptime,
- std.zig.Token.Id.Keyword_const,
- std.zig.Token.Id.Keyword_continue,
- std.zig.Token.Id.Keyword_defer,
- std.zig.Token.Id.Keyword_else,
- std.zig.Token.Id.Keyword_enum,
- std.zig.Token.Id.Keyword_errdefer,
- std.zig.Token.Id.Keyword_error,
- std.zig.Token.Id.Keyword_export,
- std.zig.Token.Id.Keyword_extern,
- std.zig.Token.Id.Keyword_for,
- std.zig.Token.Id.Keyword_if,
- std.zig.Token.Id.Keyword_inline,
- std.zig.Token.Id.Keyword_nakedcc,
- std.zig.Token.Id.Keyword_noalias,
- std.zig.Token.Id.Keyword_or,
- std.zig.Token.Id.Keyword_orelse,
- std.zig.Token.Id.Keyword_packed,
- std.zig.Token.Id.Keyword_promise,
- std.zig.Token.Id.Keyword_pub,
- std.zig.Token.Id.Keyword_resume,
- std.zig.Token.Id.Keyword_return,
- std.zig.Token.Id.Keyword_linksection,
- std.zig.Token.Id.Keyword_stdcallcc,
- std.zig.Token.Id.Keyword_struct,
- std.zig.Token.Id.Keyword_suspend,
- std.zig.Token.Id.Keyword_switch,
- std.zig.Token.Id.Keyword_test,
- std.zig.Token.Id.Keyword_threadlocal,
- std.zig.Token.Id.Keyword_try,
- std.zig.Token.Id.Keyword_union,
- std.zig.Token.Id.Keyword_unreachable,
- std.zig.Token.Id.Keyword_usingnamespace,
- std.zig.Token.Id.Keyword_var,
- std.zig.Token.Id.Keyword_volatile,
- std.zig.Token.Id.Keyword_allowzero,
- std.zig.Token.Id.Keyword_while,
+ .Keyword_align,
+ .Keyword_and,
+ .Keyword_asm,
+ .Keyword_async,
+ .Keyword_await,
+ .Keyword_break,
+ .Keyword_cancel,
+ .Keyword_catch,
+ .Keyword_comptime,
+ .Keyword_const,
+ .Keyword_continue,
+ .Keyword_defer,
+ .Keyword_else,
+ .Keyword_enum,
+ .Keyword_errdefer,
+ .Keyword_error,
+ .Keyword_export,
+ .Keyword_extern,
+ .Keyword_for,
+ .Keyword_if,
+ .Keyword_inline,
+ .Keyword_nakedcc,
+ .Keyword_noalias,
+ .Keyword_or,
+ .Keyword_orelse,
+ .Keyword_packed,
+ .Keyword_promise,
+ .Keyword_pub,
+ .Keyword_resume,
+ .Keyword_return,
+ .Keyword_linksection,
+ .Keyword_stdcallcc,
+ .Keyword_struct,
+ .Keyword_suspend,
+ .Keyword_switch,
+ .Keyword_test,
+ .Keyword_threadlocal,
+ .Keyword_try,
+ .Keyword_union,
+ .Keyword_unreachable,
+ .Keyword_usingnamespace,
+ .Keyword_var,
+ .Keyword_volatile,
+ .Keyword_allowzero,
+ .Keyword_while,
=> {
try out.write("");
try writeEscaped(out, src[token.start..token.end]);
try out.write("");
},
- std.zig.Token.Id.Keyword_fn => {
+ .Keyword_fn => {
try out.write("");
try writeEscaped(out, src[token.start..token.end]);
try out.write("");
next_tok_is_fn = true;
},
- std.zig.Token.Id.Keyword_undefined,
- std.zig.Token.Id.Keyword_null,
- std.zig.Token.Id.Keyword_true,
- std.zig.Token.Id.Keyword_false,
+ .Keyword_undefined,
+ .Keyword_null,
+ .Keyword_true,
+ .Keyword_false,
=> {
try out.write("");
try writeEscaped(out, src[token.start..token.end]);
try out.write("");
},
- std.zig.Token.Id.StringLiteral,
- std.zig.Token.Id.MultilineStringLiteralLine,
- std.zig.Token.Id.CharLiteral,
+ .StringLiteral,
+ .MultilineStringLiteralLine,
+ .CharLiteral,
=> {
try out.write("");
try writeEscaped(out, src[token.start..token.end]);
try out.write("");
},
- std.zig.Token.Id.Builtin => {
+ .Builtin => {
try out.write("");
try writeEscaped(out, src[token.start..token.end]);
try out.write("");
},
- std.zig.Token.Id.LineComment,
- std.zig.Token.Id.DocComment,
- std.zig.Token.Id.ShebangLine,
+ .LineComment,
+ .DocComment,
+ .ShebangLine,
=> {
try out.write("");
},
- std.zig.Token.Id.Identifier => {
+ .Identifier => {
if (prev_tok_was_fn) {
try out.write("");
try writeEscaped(out, src[token.start..token.end]);
@@ -864,74 +864,72 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
}
},
- std.zig.Token.Id.IntegerLiteral,
- std.zig.Token.Id.FloatLiteral,
+ .IntegerLiteral,
+ .FloatLiteral,
=> {
try out.write("");
try writeEscaped(out, src[token.start..token.end]);
try out.write("");
},
- std.zig.Token.Id.Bang,
- std.zig.Token.Id.Pipe,
- std.zig.Token.Id.PipePipe,
- std.zig.Token.Id.PipeEqual,
- std.zig.Token.Id.Equal,
- std.zig.Token.Id.EqualEqual,
- std.zig.Token.Id.EqualAngleBracketRight,
- std.zig.Token.Id.BangEqual,
- std.zig.Token.Id.LParen,
- std.zig.Token.Id.RParen,
- std.zig.Token.Id.Semicolon,
- std.zig.Token.Id.Percent,
- std.zig.Token.Id.PercentEqual,
- std.zig.Token.Id.LBrace,
- std.zig.Token.Id.RBrace,
- std.zig.Token.Id.LBracket,
- std.zig.Token.Id.RBracket,
- std.zig.Token.Id.Period,
- std.zig.Token.Id.Ellipsis2,
- std.zig.Token.Id.Ellipsis3,
- std.zig.Token.Id.Caret,
- std.zig.Token.Id.CaretEqual,
- std.zig.Token.Id.Plus,
- std.zig.Token.Id.PlusPlus,
- std.zig.Token.Id.PlusEqual,
- std.zig.Token.Id.PlusPercent,
- std.zig.Token.Id.PlusPercentEqual,
- std.zig.Token.Id.Minus,
- std.zig.Token.Id.MinusEqual,
- std.zig.Token.Id.MinusPercent,
- std.zig.Token.Id.MinusPercentEqual,
- std.zig.Token.Id.Asterisk,
- std.zig.Token.Id.AsteriskEqual,
- std.zig.Token.Id.AsteriskAsterisk,
- std.zig.Token.Id.AsteriskPercent,
- std.zig.Token.Id.AsteriskPercentEqual,
- std.zig.Token.Id.Arrow,
- std.zig.Token.Id.Colon,
- std.zig.Token.Id.Slash,
- std.zig.Token.Id.SlashEqual,
- std.zig.Token.Id.Comma,
- std.zig.Token.Id.Ampersand,
- std.zig.Token.Id.AmpersandEqual,
- std.zig.Token.Id.QuestionMark,
- std.zig.Token.Id.AngleBracketLeft,
- std.zig.Token.Id.AngleBracketLeftEqual,
- std.zig.Token.Id.AngleBracketAngleBracketLeft,
- std.zig.Token.Id.AngleBracketAngleBracketLeftEqual,
- std.zig.Token.Id.AngleBracketRight,
- std.zig.Token.Id.AngleBracketRightEqual,
- std.zig.Token.Id.AngleBracketAngleBracketRight,
- std.zig.Token.Id.AngleBracketAngleBracketRightEqual,
- std.zig.Token.Id.Tilde,
- std.zig.Token.Id.BracketStarBracket,
- std.zig.Token.Id.BracketStarCBracket,
+ .Bang,
+ .Pipe,
+ .PipePipe,
+ .PipeEqual,
+ .Equal,
+ .EqualEqual,
+ .EqualAngleBracketRight,
+ .BangEqual,
+ .LParen,
+ .RParen,
+ .Semicolon,
+ .Percent,
+ .PercentEqual,
+ .LBrace,
+ .RBrace,
+ .LBracket,
+ .RBracket,
+ .Period,
+ .Ellipsis2,
+ .Ellipsis3,
+ .Caret,
+ .CaretEqual,
+ .Plus,
+ .PlusPlus,
+ .PlusEqual,
+ .PlusPercent,
+ .PlusPercentEqual,
+ .Minus,
+ .MinusEqual,
+ .MinusPercent,
+ .MinusPercentEqual,
+ .Asterisk,
+ .AsteriskEqual,
+ .AsteriskAsterisk,
+ .AsteriskPercent,
+ .AsteriskPercentEqual,
+ .Arrow,
+ .Colon,
+ .Slash,
+ .SlashEqual,
+ .Comma,
+ .Ampersand,
+ .AmpersandEqual,
+ .QuestionMark,
+ .AngleBracketLeft,
+ .AngleBracketLeftEqual,
+ .AngleBracketAngleBracketLeft,
+ .AngleBracketAngleBracketLeftEqual,
+ .AngleBracketRight,
+ .AngleBracketRightEqual,
+ .AngleBracketAngleBracketRight,
+ .AngleBracketAngleBracketRightEqual,
+ .Tilde,
+ .BracketStarBracket,
+ .BracketStarCBracket,
=> try writeEscaped(out, src[token.start..token.end]),
- std.zig.Token.Id.AmpersandAmpersand,
- std.zig.Token.Id.Invalid,
- => return parseError(
+ .Invalid, .Invalid_ampersands => return parseError(
docgen_tokenizer,
source_token,
"syntax error",
diff --git a/std/zig/ast.zig b/std/zig/ast.zig
index f648ced94386c7aca8005567c515720b2b5461bf..38bd94339f5bcb1e564ca4199dd25f2c793a1bcb 100644
--- a/std/zig/ast.zig
+++ b/std/zig/ast.zig
@@ -113,7 +113,6 @@ pub const Tree = struct {
pub const Error = union(enum) {
InvalidToken: InvalidToken,
- InvalidAmpersandAmpersand: InvalidAmpersandAmpersand,
ExpectedContainerMembers: ExpectedContainerMembers,
ExpectedStringLiteral: ExpectedStringLiteral,
ExpectedIntegerLiteral: ExpectedIntegerLiteral,
@@ -161,7 +160,6 @@ pub const Error = union(enum) {
pub fn render(self: *const Error, tokens: *Tree.TokenList, stream: var) !void {
switch (self.*) {
.InvalidToken => |*x| return x.render(tokens, stream),
- .InvalidAmpersandAmpersand => |*x| return x.render(tokens, stream),
.ExpectedContainerMembers => |*x| return x.render(tokens, stream),
.ExpectedStringLiteral => |*x| return x.render(tokens, stream),
.ExpectedIntegerLiteral => |*x| return x.render(tokens, stream),
@@ -211,7 +209,6 @@ pub const Error = union(enum) {
pub fn loc(self: *const Error) TokenIndex {
switch (self.*) {
.InvalidToken => |x| return x.token,
- .InvalidAmpersandAmpersand => |x| return x.token,
.ExpectedContainerMembers => |x| return x.token,
.ExpectedStringLiteral => |x| return x.token,
.ExpectedIntegerLiteral => |x| return x.token,
@@ -292,7 +289,6 @@ pub const Error = union(enum) {
pub const ExpectedDerefOrUnwrap = SingleTokenError("Expected pointer dereference or optional unwrap, found {}");
pub const ExpectedSuffixOp = SingleTokenError("Expected pointer dereference, optional unwrap, or field access, found {}");
- pub const InvalidAmpersandAmpersand = SimpleError("Invalid token '&&', 'and' performs boolean AND");
pub const ExpectedParamType = SimpleError("Expected parameter type");
pub const ExpectedPubItem = SimpleError("Pub must be followed by fn decl, var decl, or container member");
pub const UnattachedDocComment = SimpleError("Unattached documentation comment");
@@ -322,8 +318,19 @@ pub const Error = union(enum) {
expected_id: Token.Id,
pub fn render(self: *const ExpectedToken, tokens: *Tree.TokenList, stream: var) !void {
- const token_name = @tagName(tokens.at(self.token).id);
- return stream.print("expected {}, found {}", @tagName(self.expected_id), token_name);
+ const found_token = tokens.at(self.token);
+ switch (found_token.id) {
+ .Invalid_ampersands => {
+ return stream.print("`&&` is invalid. Note that `and` is boolean AND.");
+ },
+ .Invalid => {
+ return stream.print("expected {}, found invalid bytes", @tagName(self.expected_id));
+ },
+ else => {
+ const token_name = @tagName(found_token.id);
+ return stream.print("expected {}, found {}", @tagName(self.expected_id), token_name);
+ },
+ }
}
};
diff --git a/std/zig/parse.zig b/std/zig/parse.zig
index 0daa9f35a8afa52d726d9724dccb5db0aa7ab4c8..59acf9989084540949a5300c98f01936fb94e123 100644
--- a/std/zig/parse.zig
+++ b/std/zig/parse.zig
@@ -774,7 +774,7 @@ fn parseBoolAndExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
arena,
it,
tree,
- parseAmpersandAmpersandOp,
+ SimpleBinOpParseFn(.Keyword_and, .BoolAnd),
parseCompareExpr,
.Infinitely,
);
@@ -2687,18 +2687,6 @@ fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) No
// Helper parsers not included in the grammar
-fn parseAmpersandAmpersandOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
- const op_parse_and = SimpleBinOpParseFn(.Keyword_and, Node.InfixOp.Op.BoolAnd);
- const op_token = eatToken(it, .AmpersandAmpersand);
- if (op_token != null) {
- try tree.errors.push(AstError{
- .InvalidAmpersandAmpersand = AstError.InvalidAmpersandAmpersand{ .token = it.index },
- });
- return error.ParseError;
- }
- return op_parse_and(arena, it, tree);
-}
-
fn parseBuiltinCall(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const token = eatToken(it, .Builtin) orelse return null;
const params = (try parseFnCallArguments(arena, it, tree)) orelse {
diff --git a/std/zig/tokenizer.zig b/std/zig/tokenizer.zig
index df39c04f91b05fbacbbd19c68c4e11e21e689623..4539e1e5b271f9e533593f08e53fd060636580ea 100644
--- a/std/zig/tokenizer.zig
+++ b/std/zig/tokenizer.zig
@@ -77,6 +77,7 @@ pub const Token = struct {
pub const Id = enum {
Invalid,
+ Invalid_ampersands,
Identifier,
StringLiteral,
MultilineStringLiteralLine,
@@ -125,7 +126,6 @@ pub const Token = struct {
SlashEqual,
Comma,
Ampersand,
- AmpersandAmpersand,
AmpersandEqual,
QuestionMark,
AngleBracketLeft,
@@ -486,7 +486,8 @@ pub const Tokenizer = struct {
State.Ampersand => switch (c) {
'&' => {
- result.id = Token.Id.AmpersandAmpersand;
+ result.id = Token.Id.Invalid_ampersands;
+ self.index += 1;
break;
},
'=' => {
--
2.54.0
From 77c2ac3fcd27b114b0068d3b64b3d884aa71e4ef Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sun, 21 Jul 2019 18:04:23 -0400
Subject: [PATCH 12/47] zig build: support DESTDIR environment variable
closes #2929
---
std/build.zig | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/std/build.zig b/std/build.zig
index fc0786094d9e4c17499f9e16cfb19287b30b2a26..e6e7143f0661d112a4e828920129d104ca994a3a 100644
--- a/std/build.zig
+++ b/std/build.zig
@@ -41,9 +41,10 @@ pub const Builder = struct {
env_map: *BufMap,
top_level_steps: ArrayList(*TopLevelStep),
install_prefix: ?[]const u8,
- search_prefixes: ArrayList([]const u8),
+ dest_dir: ?[]const u8,
lib_dir: ?[]const u8,
exe_dir: ?[]const u8,
+ search_prefixes: ArrayList([]const u8),
installed_files: ArrayList(InstalledFile),
build_root: []const u8,
cache_root: []const u8,
@@ -125,10 +126,11 @@ pub const Builder = struct {
.top_level_steps = ArrayList(*TopLevelStep).init(allocator),
.default_step = undefined,
.env_map = env_map,
- .install_prefix = null,
.search_prefixes = ArrayList([]const u8).init(allocator),
+ .install_prefix = null,
.lib_dir = null,
.exe_dir = null,
+ .dest_dir = env_map.get("DESTDIR"),
.installed_files = ArrayList(InstalledFile).init(allocator),
.install_tls = TopLevelStep{
.step = Step.initNoOp("install", allocator),
@@ -164,14 +166,14 @@ pub const Builder = struct {
}
fn resolveInstallPrefix(self: *Builder) void {
- const prefix = if (self.install_prefix) |prefix| prefix else blk: {
- const prefix = self.cache_root;
- self.install_prefix = prefix;
- break :blk prefix;
+ const dest_dir = self.dest_dir orelse blk: {
+ const dest_dir = self.install_prefix orelse self.cache_root;
+ self.dest_dir = dest_dir;
+ break :blk dest_dir;
};
-
- self.lib_dir = fs.path.join(self.allocator, [_][]const u8{ prefix, "lib" }) catch unreachable;
- self.exe_dir = fs.path.join(self.allocator, [_][]const u8{ prefix, "bin" }) catch unreachable;
+ self.dest_dir = dest_dir;
+ self.lib_dir = fs.path.join(self.allocator, [_][]const u8{ dest_dir, "lib" }) catch unreachable;
+ self.exe_dir = fs.path.join(self.allocator, [_][]const u8{ dest_dir, "bin" }) catch unreachable;
}
pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
@@ -884,7 +886,7 @@ pub const Builder = struct {
fn getInstallPath(self: *Builder, dir: InstallDir, dest_rel_path: []const u8) []const u8 {
const base_dir = switch (dir) {
- .Prefix => self.install_prefix.?,
+ .Prefix => self.dest_dir.?,
.Bin => self.exe_dir.?,
.Lib => self.lib_dir.?,
};
--
2.54.0
From d6d0bb054219da26a55f880f48f00902a4fbaf56 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 22 Jul 2019 10:45:59 -0400
Subject: [PATCH 13/47] zig build: adjust DESTDIR logic
now if DESTDIR is provided then the default install prefix is /usr.
otherwise the default install prefix is still zig-cache directly.
DESTDIR is prepended to the prefix to match what make install does.
---
std/build.zig | 25 ++++++++++++++++---------
1 file changed, 16 insertions(+), 9 deletions(-)
diff --git a/std/build.zig b/std/build.zig
index e6e7143f0661d112a4e828920129d104ca994a3a..3a0c34c8d1ae2ad9dde4f4b304623b8067631ce6 100644
--- a/std/build.zig
+++ b/std/build.zig
@@ -44,6 +44,7 @@ pub const Builder = struct {
dest_dir: ?[]const u8,
lib_dir: ?[]const u8,
exe_dir: ?[]const u8,
+ install_path: []const u8,
search_prefixes: ArrayList([]const u8),
installed_files: ArrayList(InstalledFile),
build_root: []const u8,
@@ -144,6 +145,7 @@ pub const Builder = struct {
.is_release = false,
.override_std_dir = null,
.override_lib_dir = null,
+ .install_path = undefined,
};
try self.top_level_steps.append(&self.install_tls);
try self.top_level_steps.append(&self.uninstall_tls);
@@ -166,14 +168,19 @@ pub const Builder = struct {
}
fn resolveInstallPrefix(self: *Builder) void {
- const dest_dir = self.dest_dir orelse blk: {
- const dest_dir = self.install_prefix orelse self.cache_root;
- self.dest_dir = dest_dir;
- break :blk dest_dir;
- };
- self.dest_dir = dest_dir;
- self.lib_dir = fs.path.join(self.allocator, [_][]const u8{ dest_dir, "lib" }) catch unreachable;
- self.exe_dir = fs.path.join(self.allocator, [_][]const u8{ dest_dir, "bin" }) catch unreachable;
+ if (self.dest_dir) |dest_dir| {
+ const install_prefix = self.install_prefix orelse "/usr";
+ self.install_path = fs.path.join(self.allocator, [_][]const u8{ dest_dir, install_prefix }) catch unreachable;
+ } else {
+ const install_prefix = self.install_prefix orelse blk: {
+ const p = self.cache_root;
+ self.install_prefix = p;
+ break :blk p;
+ };
+ self.install_path = install_prefix;
+ }
+ self.lib_dir = fs.path.join(self.allocator, [_][]const u8{ self.install_path, "lib" }) catch unreachable;
+ self.exe_dir = fs.path.join(self.allocator, [_][]const u8{ self.install_path, "bin" }) catch unreachable;
}
pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
@@ -886,7 +893,7 @@ pub const Builder = struct {
fn getInstallPath(self: *Builder, dir: InstallDir, dest_rel_path: []const u8) []const u8 {
const base_dir = switch (dir) {
- .Prefix => self.dest_dir.?,
+ .Prefix => self.install_path,
.Bin => self.exe_dir.?,
.Lib => self.lib_dir.?,
};
--
2.54.0
From a3327f0fbde0f7eebd6260bb5f47897599434bb4 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 22 Jul 2019 12:33:24 -0400
Subject: [PATCH 14/47] fix usingnamespace analyzing the expression multiple
times
---
src/analyze.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/analyze.cpp b/src/analyze.cpp
index de4d64f5d65425084ee33f7dc80ca49a6e2f0758..0af1baec35b79df396a16cff8e23f56fb6b978f3 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -3353,7 +3353,8 @@ static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace,
static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope) {
if (using_namespace->base.resolution == TldResolutionOk ||
- using_namespace->base.resolution == TldResolutionInvalid)
+ using_namespace->base.resolution == TldResolutionInvalid ||
+ using_namespace->using_namespace_value != nullptr)
{
return;
}
--
2.54.0
From bc31c1280e012377c3a2b00356a5876919a72775 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 22 Jul 2019 12:15:16 -0400
Subject: [PATCH 15/47] disable segfault handler when panicking
this prevents a segfault in stack trace printing to activate the
segfault handler.
---
src/codegen.cpp | 277 ++++++++++++++++++------------------
src/codegen.hpp | 3 +-
src/main.cpp | 7 +-
std/debug.zig | 64 ++++++---
std/os/windows/kernel32.zig | 1 +
std/special/start.zig | 14 +-
6 files changed, 193 insertions(+), 173 deletions(-)
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 188c5ccc8d14be0c3f325c49a95668f6ca59f8b0..be694b19f9feb40f8496d9d77300acbc816b194a 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -89,126 +89,6 @@ static const char *symbols_that_llvm_depends_on[] = {
// TODO probably all of compiler-rt needs to go here
};
-CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target,
- OutType out_type, BuildMode build_mode, Buf *override_lib_dir, Buf *override_std_dir,
- ZigLibCInstallation *libc, Buf *cache_dir)
-{
- CodeGen *g = allocate(1);
-
- codegen_add_time_event(g, "Initialize");
-
- g->subsystem = TargetSubsystemAuto;
- g->libc = libc;
- g->zig_target = target;
- g->cache_dir = cache_dir;
-
- if (override_lib_dir == nullptr) {
- g->zig_lib_dir = get_zig_lib_dir();
- } else {
- g->zig_lib_dir = override_lib_dir;
- }
-
- if (override_std_dir == nullptr) {
- g->zig_std_dir = buf_alloc();
- os_path_join(g->zig_lib_dir, buf_create_from_str("std"), g->zig_std_dir);
- } else {
- g->zig_std_dir = override_std_dir;
- }
-
- g->zig_c_headers_dir = buf_alloc();
- os_path_join(g->zig_lib_dir, buf_create_from_str("include"), g->zig_c_headers_dir);
-
- g->build_mode = build_mode;
- g->out_type = out_type;
- g->import_table.init(32);
- g->builtin_fn_table.init(32);
- g->primitive_type_table.init(32);
- g->type_table.init(32);
- g->fn_type_table.init(32);
- g->error_table.init(16);
- g->generic_table.init(16);
- g->llvm_fn_table.init(16);
- g->memoized_fn_eval_table.init(16);
- g->exported_symbol_names.init(8);
- g->external_prototypes.init(8);
- g->string_literals_table.init(16);
- g->type_info_cache.init(32);
- g->is_test_build = false;
- g->is_single_threaded = false;
- buf_resize(&g->global_asm, 0);
-
- for (size_t i = 0; i < array_length(symbols_that_llvm_depends_on); i += 1) {
- g->external_prototypes.put(buf_create_from_str(symbols_that_llvm_depends_on[i]), nullptr);
- }
-
- if (root_src_path) {
- Buf *root_pkg_path;
- Buf *rel_root_src_path;
- if (main_pkg_path == nullptr) {
- Buf *src_basename = buf_alloc();
- Buf *src_dir = buf_alloc();
- os_path_split(root_src_path, src_dir, src_basename);
-
- if (buf_len(src_basename) == 0) {
- fprintf(stderr, "Invalid root source path: %s\n", buf_ptr(root_src_path));
- exit(1);
- }
- root_pkg_path = src_dir;
- rel_root_src_path = src_basename;
- } else {
- Buf resolved_root_src_path = os_path_resolve(&root_src_path, 1);
- Buf resolved_main_pkg_path = os_path_resolve(&main_pkg_path, 1);
-
- if (!buf_starts_with_buf(&resolved_root_src_path, &resolved_main_pkg_path)) {
- fprintf(stderr, "Root source path '%s' outside main package path '%s'",
- buf_ptr(root_src_path), buf_ptr(main_pkg_path));
- exit(1);
- }
- root_pkg_path = main_pkg_path;
- rel_root_src_path = buf_create_from_mem(
- buf_ptr(&resolved_root_src_path) + buf_len(&resolved_main_pkg_path) + 1,
- buf_len(&resolved_root_src_path) - buf_len(&resolved_main_pkg_path) - 1);
- }
-
- g->root_package = new_package(buf_ptr(root_pkg_path), buf_ptr(rel_root_src_path), "");
- g->std_package = new_package(buf_ptr(g->zig_std_dir), "std.zig", "std");
- g->root_package->package_table.put(buf_create_from_str("std"), g->std_package);
- } else {
- g->root_package = new_package(".", "", "");
- }
-
- g->root_package->package_table.put(buf_create_from_str("root"), g->root_package);
-
- g->zig_std_special_dir = buf_alloc();
- os_path_join(g->zig_std_dir, buf_sprintf("special"), g->zig_std_special_dir);
-
- assert(target != nullptr);
- if (!target->is_native) {
- g->each_lib_rpath = false;
- } else {
- g->each_lib_rpath = true;
-
- if (target_os_is_darwin(g->zig_target->os)) {
- init_darwin_native(g);
- }
-
- }
-
- if (target_os_requires_libc(g->zig_target->os)) {
- g->libc_link_lib = create_link_lib(buf_create_from_str("c"));
- g->link_libs_list.append(g->libc_link_lib);
- }
-
- target_triple_llvm(&g->llvm_triple_str, g->zig_target);
- g->pointer_size_bytes = target_arch_pointer_bit_width(g->zig_target->arch) / 8;
-
- if (!target_has_debug_info(g->zig_target)) {
- g->strip_debug_symbols = true;
- }
-
- return g;
-}
-
void codegen_set_clang_argv(CodeGen *g, const char **args, size_t len) {
g->clang_argv = args;
g->clang_argv_len = len;
@@ -233,10 +113,6 @@ void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patc
g->version_patch = patch;
}
-void codegen_set_is_test(CodeGen *g, bool is_test_build) {
- g->is_test_build = is_test_build;
-}
-
void codegen_set_emit_file_type(CodeGen *g, EmitFileType emit_file_type) {
g->emit_file_type = emit_file_type;
}
@@ -7994,6 +7870,14 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
return contents;
}
+static ZigPackage *create_test_runner_pkg(CodeGen *g) {
+ return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "test_runner.zig", "std.special");
+}
+
+static ZigPackage *create_panic_pkg(CodeGen *g) {
+ return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "panic.zig", "std.special");
+}
+
static Error define_builtin_compile_vars(CodeGen *g) {
if (g->std_package == nullptr)
return ErrorNone;
@@ -8078,8 +7962,16 @@ static Error define_builtin_compile_vars(CodeGen *g) {
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->std_package->package_table.put(buf_create_from_str("std"), g->std_package);
- g->std_package->package_table.put(buf_create_from_str("root"),
- g->is_test_build ? g->test_runner_package : g->root_package);
+ ZigPackage *root_pkg;
+ if (g->is_test_build) {
+ if (g->test_runner_package == nullptr) {
+ g->test_runner_package = create_test_runner_pkg(g);
+ }
+ root_pkg = g->test_runner_package;
+ } else {
+ root_pkg = g->root_package;
+ }
+ g->std_package->package_table.put(buf_create_from_str("root"), root_pkg);
g->compile_var_import = add_source_file(g, g->compile_var_package, builtin_zig_path, contents,
SourceKindPkgMain);
@@ -8571,14 +8463,6 @@ static ZigPackage *create_start_pkg(CodeGen *g, ZigPackage *pkg_with_main) {
return package;
}
-static ZigPackage *create_test_runner_pkg(CodeGen *g) {
- return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "test_runner.zig", "std.special");
-}
-
-static ZigPackage *create_panic_pkg(CodeGen *g) {
- return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "panic.zig", "std.special");
-}
-
static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
Error err;
@@ -8628,7 +8512,7 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
ConstExprValue *test_fn_slice = create_const_slice(g, test_fn_array, 0, g->test_fns.length, true);
update_compile_var(g, buf_create_from_str("test_functions"), test_fn_slice);
- g->test_runner_package = create_test_runner_pkg(g);
+ assert(g->test_runner_package != nullptr);
g->test_runner_import = add_special_code(g, g->test_runner_package, "test_runner.zig");
}
@@ -9742,7 +9626,8 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o
ZigLibCInstallation *libc)
{
CodeGen *child_gen = codegen_create(nullptr, root_src_path, parent_gen->zig_target, out_type,
- parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir, libc, get_stage1_cache_path());
+ parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir, libc, get_stage1_cache_path(),
+ false);
child_gen->disable_gen_h = true;
child_gen->want_stack_check = WantStackCheckDisabled;
child_gen->verbose_tokenize = parent_gen->verbose_tokenize;
@@ -9769,3 +9654,123 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o
return child_gen;
}
+CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target,
+ OutType out_type, BuildMode build_mode, Buf *override_lib_dir, Buf *override_std_dir,
+ ZigLibCInstallation *libc, Buf *cache_dir, bool is_test_build)
+{
+ CodeGen *g = allocate(1);
+
+ codegen_add_time_event(g, "Initialize");
+
+ g->subsystem = TargetSubsystemAuto;
+ g->libc = libc;
+ g->zig_target = target;
+ g->cache_dir = cache_dir;
+
+ if (override_lib_dir == nullptr) {
+ g->zig_lib_dir = get_zig_lib_dir();
+ } else {
+ g->zig_lib_dir = override_lib_dir;
+ }
+
+ if (override_std_dir == nullptr) {
+ g->zig_std_dir = buf_alloc();
+ os_path_join(g->zig_lib_dir, buf_create_from_str("std"), g->zig_std_dir);
+ } else {
+ g->zig_std_dir = override_std_dir;
+ }
+
+ g->zig_c_headers_dir = buf_alloc();
+ os_path_join(g->zig_lib_dir, buf_create_from_str("include"), g->zig_c_headers_dir);
+
+ g->build_mode = build_mode;
+ g->out_type = out_type;
+ g->import_table.init(32);
+ g->builtin_fn_table.init(32);
+ g->primitive_type_table.init(32);
+ g->type_table.init(32);
+ g->fn_type_table.init(32);
+ g->error_table.init(16);
+ g->generic_table.init(16);
+ g->llvm_fn_table.init(16);
+ g->memoized_fn_eval_table.init(16);
+ g->exported_symbol_names.init(8);
+ g->external_prototypes.init(8);
+ g->string_literals_table.init(16);
+ g->type_info_cache.init(32);
+ g->is_test_build = is_test_build;
+ g->is_single_threaded = false;
+ buf_resize(&g->global_asm, 0);
+
+ for (size_t i = 0; i < array_length(symbols_that_llvm_depends_on); i += 1) {
+ g->external_prototypes.put(buf_create_from_str(symbols_that_llvm_depends_on[i]), nullptr);
+ }
+
+ if (root_src_path) {
+ Buf *root_pkg_path;
+ Buf *rel_root_src_path;
+ if (main_pkg_path == nullptr) {
+ Buf *src_basename = buf_alloc();
+ Buf *src_dir = buf_alloc();
+ os_path_split(root_src_path, src_dir, src_basename);
+
+ if (buf_len(src_basename) == 0) {
+ fprintf(stderr, "Invalid root source path: %s\n", buf_ptr(root_src_path));
+ exit(1);
+ }
+ root_pkg_path = src_dir;
+ rel_root_src_path = src_basename;
+ } else {
+ Buf resolved_root_src_path = os_path_resolve(&root_src_path, 1);
+ Buf resolved_main_pkg_path = os_path_resolve(&main_pkg_path, 1);
+
+ if (!buf_starts_with_buf(&resolved_root_src_path, &resolved_main_pkg_path)) {
+ fprintf(stderr, "Root source path '%s' outside main package path '%s'",
+ buf_ptr(root_src_path), buf_ptr(main_pkg_path));
+ exit(1);
+ }
+ root_pkg_path = main_pkg_path;
+ rel_root_src_path = buf_create_from_mem(
+ buf_ptr(&resolved_root_src_path) + buf_len(&resolved_main_pkg_path) + 1,
+ buf_len(&resolved_root_src_path) - buf_len(&resolved_main_pkg_path) - 1);
+ }
+
+ g->root_package = new_package(buf_ptr(root_pkg_path), buf_ptr(rel_root_src_path), "");
+ g->std_package = new_package(buf_ptr(g->zig_std_dir), "std.zig", "std");
+ g->root_package->package_table.put(buf_create_from_str("std"), g->std_package);
+ } else {
+ g->root_package = new_package(".", "", "");
+ }
+
+ g->root_package->package_table.put(buf_create_from_str("root"), g->root_package);
+
+ g->zig_std_special_dir = buf_alloc();
+ os_path_join(g->zig_std_dir, buf_sprintf("special"), g->zig_std_special_dir);
+
+ assert(target != nullptr);
+ if (!target->is_native) {
+ g->each_lib_rpath = false;
+ } else {
+ g->each_lib_rpath = true;
+
+ if (target_os_is_darwin(g->zig_target->os)) {
+ init_darwin_native(g);
+ }
+
+ }
+
+ if (target_os_requires_libc(g->zig_target->os)) {
+ g->libc_link_lib = create_link_lib(buf_create_from_str("c"));
+ g->link_libs_list.append(g->libc_link_lib);
+ }
+
+ target_triple_llvm(&g->llvm_triple_str, g->zig_target);
+ g->pointer_size_bytes = target_arch_pointer_bit_width(g->zig_target->arch) / 8;
+
+ if (!target_has_debug_info(g->zig_target)) {
+ g->strip_debug_symbols = true;
+ }
+
+ return g;
+}
+
diff --git a/src/codegen.hpp b/src/codegen.hpp
index 5de36c1aab750f20e9c77e9300e2334278f85bc7..cdff61a26fbc585ecbc82067d029b6ffacb354b3 100644
--- a/src/codegen.hpp
+++ b/src/codegen.hpp
@@ -18,14 +18,13 @@
CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target,
OutType out_type, BuildMode build_mode, Buf *zig_lib_dir, Buf *override_std_dir,
- ZigLibCInstallation *libc, Buf *cache_dir);
+ ZigLibCInstallation *libc, Buf *cache_dir, bool is_test_build);
CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType out_type,
ZigLibCInstallation *libc);
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);
-void codegen_set_is_test(CodeGen *codegen, bool is_test);
void codegen_set_each_lib_rpath(CodeGen *codegen, bool each_lib_rpath);
void codegen_set_emit_file_type(CodeGen *g, EmitFileType emit_file_type);
diff --git a/src/main.cpp b/src/main.cpp
index ce68e53d851ad6b91424a01a6e157f7749e92f55..42d0850046f9742065bedba25300054a811722cd 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -583,7 +583,7 @@ int main(int argc, char **argv) {
}
CodeGen *g = codegen_create(main_pkg_path, build_runner_path, &target, OutTypeExe,
- BuildModeDebug, override_lib_dir, override_std_dir, nullptr, &full_cache_dir);
+ BuildModeDebug, override_lib_dir, override_std_dir, nullptr, &full_cache_dir, false);
g->valgrind_support = valgrind_support;
g->enable_time_report = timing_info;
codegen_set_out_name(g, buf_create_from_str("build"));
@@ -1011,7 +1011,7 @@ int main(int argc, char **argv) {
}
case CmdBuiltin: {
CodeGen *g = codegen_create(main_pkg_path, nullptr, &target,
- out_type, build_mode, override_lib_dir, override_std_dir, nullptr, nullptr);
+ out_type, build_mode, override_lib_dir, override_std_dir, nullptr, nullptr, false);
codegen_set_strip(g, strip);
for (size_t i = 0; i < link_libs.length; i += 1) {
LinkLib *link_lib = codegen_add_link_lib(g, buf_create_from_str(link_libs.at(i)));
@@ -1115,7 +1115,7 @@ int main(int argc, char **argv) {
cache_dir_buf = buf_create_from_str(cache_dir);
}
CodeGen *g = codegen_create(main_pkg_path, zig_root_source_file, &target, out_type, build_mode,
- override_lib_dir, override_std_dir, libc, cache_dir_buf);
+ override_lib_dir, override_std_dir, libc, cache_dir_buf, cmd == CmdTest);
if (llvm_argv.length >= 2) codegen_set_llvm_argv(g, llvm_argv.items + 1, llvm_argv.length - 2);
g->valgrind_support = valgrind_support;
g->want_pic = want_pic;
@@ -1125,7 +1125,6 @@ int main(int argc, char **argv) {
g->enable_time_report = timing_info;
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);
g->want_single_threaded = want_single_threaded;
codegen_set_linker_script(g, linker_script);
g->version_script_path = version_script;
diff --git a/std/debug.zig b/std/debug.zig
index d81e62901adeb7ee133f5da1ccbc5147f4e3b6d3..7d1fd6ce47d79be5840cfb412a8428f8a73d37fd 100644
--- a/std/debug.zig
+++ b/std/debug.zig
@@ -12,6 +12,7 @@ const coff = std.coff;
const pdb = std.pdb;
const ArrayList = std.ArrayList;
const builtin = @import("builtin");
+const root = @import("root");
const maxInt = std.math.maxInt;
const File = std.fs.File;
const windows = std.os.windows;
@@ -217,6 +218,12 @@ var panicking: u8 = 0; // TODO make this a bool
pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, comptime format: []const u8, args: ...) noreturn {
@setCold(true);
+ if (enable_segfault_handler) {
+ // If a segfault happens while panicking, we want it to actually segfault, not trigger
+ // the handler.
+ resetSegfaultHandler();
+ }
+
if (@atomicRmw(u8, &panicking, builtin.AtomicRmwOp.Xchg, 1, builtin.AtomicOrder.SeqCst) == 1) {
// Panicked during a panic.
@@ -2312,39 +2319,58 @@ fn getDebugInfoAllocator() *mem.Allocator {
/// Whether or not the current target can print useful debug information when a segfault occurs.
pub const have_segfault_handling_support = (builtin.arch == builtin.Arch.x86_64 and builtin.os == .linux) or builtin.os == .windows;
+pub const enable_segfault_handler: bool = if (@hasDecl(root, "enable_segfault_handler"))
+ root.enable_segfault_handler
+else
+ runtime_safety and have_segfault_handling_support;
+
+pub fn maybeEnableSegfaultHandler() void {
+ if (enable_segfault_handler) {
+ std.debug.attachSegfaultHandler();
+ }
+}
+
+var windows_segfault_handle: ?windows.HANDLE = null;
/// Attaches a global SIGSEGV handler which calls @panic("segmentation fault");
pub fn attachSegfaultHandler() void {
if (!have_segfault_handling_support) {
@compileError("segfault handler not supported for this target");
}
- switch (builtin.os) {
- .linux => {
- var act = os.Sigaction{
- .sigaction = handleSegfaultLinux,
- .mask = os.empty_sigset,
- .flags = (os.SA_SIGINFO | os.SA_RESTART | os.SA_RESETHAND),
- };
+ if (windows.is_the_target) {
+ windows_segfault_handle = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);
+ return;
+ }
+ var act = os.Sigaction{
+ .sigaction = handleSegfaultLinux,
+ .mask = os.empty_sigset,
+ .flags = (os.SA_SIGINFO | os.SA_RESTART | os.SA_RESETHAND),
+ };
+
+ os.sigaction(os.SIGSEGV, &act, null);
+}
- os.sigaction(os.SIGSEGV, &act, null);
- },
- .windows => {
- _ = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);
- },
- else => unreachable,
+fn resetSegfaultHandler() void {
+ if (windows.is_the_target) {
+ if (windows_segfault_handle) |handle| {
+ assert(windows.kernel32.RemoveVectoredExceptionHandler(handle) != 0);
+ windows_segfault_handle = null;
+ }
+ return;
}
+ var act = os.Sigaction{
+ .sigaction = os.SIG_DFL,
+ .mask = os.empty_sigset,
+ .flags = 0,
+ };
+ os.sigaction(os.SIGSEGV, &act, null);
}
extern fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *const c_void) noreturn {
// Reset to the default handler so that if a segfault happens in this handler it will crash
// the process. Also when this handler returns, the original instruction will be repeated
// and the resulting segfault will crash the process rather than continually dump stack traces.
- var act = os.Sigaction{
- .sigaction = os.SIG_DFL,
- .mask = os.empty_sigset,
- .flags = 0,
- };
- os.sigaction(os.SIGSEGV, &act, null);
+ resetSegfaultHandler();
const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));
const ip = @intCast(usize, ctx.mcontext.gregs[os.REG_RIP]);
diff --git a/std/os/windows/kernel32.zig b/std/os/windows/kernel32.zig
index e4edc349ab0230237ebfbc5ce9ed66a8d3141c5f..2ae73ad45a63bce7a4bf3e503591ec71a2097d09 100644
--- a/std/os/windows/kernel32.zig
+++ b/std/os/windows/kernel32.zig
@@ -1,6 +1,7 @@
usingnamespace @import("bits.zig");
pub extern "kernel32" stdcallcc fn AddVectoredExceptionHandler(First: c_ulong, Handler: ?VECTORED_EXCEPTION_HANDLER) ?*c_void;
+pub extern "kernel32" stdcallcc fn RemoveVectoredExceptionHandler(Handle: HANDLE) c_ulong;
pub extern "kernel32" stdcallcc fn CancelIoEx(hFile: HANDLE, lpOverlapped: LPOVERLAPPED) BOOL;
diff --git a/std/special/start.zig b/std/special/start.zig
index 30298669e30efc8ab253014530315978940edcd7..f8a018e0ae08319f0a3a6331189639336f5a435c 100644
--- a/std/special/start.zig
+++ b/std/special/start.zig
@@ -24,16 +24,6 @@ comptime {
}
}
-fn enableSegfaultHandler() void {
- const enable_segfault_handler: bool = if (@hasDecl(root, "enable_segfault_handler"))
- root.enable_segfault_handler
- else
- std.debug.runtime_safety and std.debug.have_segfault_handling_support;
- if (enable_segfault_handler) {
- std.debug.attachSegfaultHandler();
- }
-}
-
extern fn wasm_freestanding_start() void {
_ = callMain();
}
@@ -72,7 +62,7 @@ extern fn WinMainCRTStartup() noreturn {
_ = @import("start_windows_tls.zig");
}
- enableSegfaultHandler();
+ std.debug.maybeEnableSegfaultHandler();
std.os.windows.kernel32.ExitProcess(callMain());
}
@@ -113,7 +103,7 @@ inline fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 {
std.os.argv = argv[0..argc];
std.os.environ = envp;
- enableSegfaultHandler();
+ std.debug.maybeEnableSegfaultHandler();
return callMain();
}
--
2.54.0
From 16be70cbbf8e6dc658b9fcacd3366df8f83fffa8 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 18 Jul 2019 13:54:22 -0400
Subject: [PATCH 16/47] compiler-rt: add __muldi3
---
build.zig | 9 +++--
std/special/compiler_rt.zig | 3 ++
std/special/compiler_rt/divti3.zig | 1 -
std/special/compiler_rt/muldi3.zig | 54 +++++++++++++++++++++++++
std/special/compiler_rt/muldi3_test.zig | 51 +++++++++++++++++++++++
test/tests.zig | 3 +-
6 files changed, 116 insertions(+), 5 deletions(-)
create mode 100644 std/special/compiler_rt/muldi3.zig
create mode 100644 std/special/compiler_rt/muldi3_test.zig
diff --git a/build.zig b/build.zig
index 07041d026fddd2c8696789572c31dac03d0aff10..011f742d820b82b22f0443cbe3db363b4e13d72a 100644
--- a/build.zig
+++ b/build.zig
@@ -122,16 +122,19 @@ pub fn build(b: *Builder) !void {
}
const modes = chosen_modes[0..chosen_mode_index];
+ const multi_and_single = [_]bool{ false, true };
+ const just_multi = [_]bool{false};
+
// run stage1 `zig fmt` on this build.zig file just to make sure it works
test_step.dependOn(&fmt_build_zig.step);
const fmt_step = b.step("test-fmt", "Run zig fmt against build.zig to make sure it works");
fmt_step.dependOn(&fmt_build_zig.step);
- test_step.dependOn(tests.addPkgTests(b, test_filter, "test/stage1/behavior.zig", "behavior", "Run the behavior tests", modes, skip_non_native));
+ test_step.dependOn(tests.addPkgTests(b, test_filter, "test/stage1/behavior.zig", "behavior", "Run the behavior tests", modes, multi_and_single, skip_non_native));
- test_step.dependOn(tests.addPkgTests(b, test_filter, "std/std.zig", "std", "Run the standard library tests", modes, skip_non_native));
+ test_step.dependOn(tests.addPkgTests(b, test_filter, "std/std.zig", "std", "Run the standard library tests", modes, multi_and_single, skip_non_native));
- test_step.dependOn(tests.addPkgTests(b, test_filter, "std/special/compiler_rt.zig", "compiler-rt", "Run the compiler_rt tests", modes, skip_non_native));
+ test_step.dependOn(tests.addPkgTests(b, test_filter, "std/special/compiler_rt.zig", "compiler-rt", "Run the compiler_rt tests", modes, just_multi, skip_non_native));
test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));
test_step.dependOn(tests.addStandaloneTests(b, test_filter, modes));
diff --git a/std/special/compiler_rt.zig b/std/special/compiler_rt.zig
index 5064e9db29b32b9a64ebfa1a9b60f167802a9c78..a5bbefa1db801fefcfc4b7e2e4507a77d45f5f97 100644
--- a/std/special/compiler_rt.zig
+++ b/std/special/compiler_rt.zig
@@ -127,6 +127,7 @@ comptime {
@export("__udivmoddi4", @import("compiler_rt/udivmoddi4.zig").__udivmoddi4, linkage);
@export("__popcountdi2", @import("compiler_rt/popcountdi2.zig").__popcountdi2, linkage);
+ @export("__muldi3", @import("compiler_rt/muldi3.zig").__muldi3, linkage);
@export("__divmoddi4", __divmoddi4, linkage);
@export("__divsi3", __divsi3, linkage);
@export("__divdi3", __divdi3, linkage);
@@ -147,6 +148,8 @@ comptime {
@export("__aeabi_unwind_cpp_pr1", __aeabi_unwind_cpp_pr1, linkage);
@export("__aeabi_unwind_cpp_pr2", __aeabi_unwind_cpp_pr2, linkage);
+ @export("__aeabi_lmul", @import("compiler_rt/muldi3.zig").__muldi3, linkage);
+
@export("__aeabi_ldivmod", __aeabi_ldivmod, linkage);
@export("__aeabi_uldivmod", __aeabi_uldivmod, linkage);
diff --git a/std/special/compiler_rt/divti3.zig b/std/special/compiler_rt/divti3.zig
index d5b2778a34c0e882a805dcb1b2153019cb2e91b9..477ce2cb985be973c81151bf57ebbb279a06de79 100644
--- a/std/special/compiler_rt/divti3.zig
+++ b/std/special/compiler_rt/divti3.zig
@@ -1,6 +1,5 @@
const udivmod = @import("udivmod.zig").udivmod;
const builtin = @import("builtin");
-const compiler_rt = @import("../compiler_rt.zig");
pub extern fn __divti3(a: i128, b: i128) i128 {
@setRuntimeSafety(builtin.is_test);
diff --git a/std/special/compiler_rt/muldi3.zig b/std/special/compiler_rt/muldi3.zig
new file mode 100644
index 0000000000000000000000000000000000000000..7a955120f5d5829683beee189c48d8b0207357ad
--- /dev/null
+++ b/std/special/compiler_rt/muldi3.zig
@@ -0,0 +1,54 @@
+const builtin = @import("builtin");
+
+// Ported from
+// https://github.com/llvm/llvm-project/blob/552c2c09d354a3ad9c1c9647e0a3bb5099c31088/compiler-rt/lib/builtins/muldi3.c
+
+const dwords = extern union {
+ all: i64,
+ s: switch (builtin.endian) {
+ .Little => extern struct {
+ low: u32,
+ high: u32,
+ },
+ .Big => extern struct {
+ high: u32,
+ low: u32,
+ },
+ },
+};
+
+fn __muldsi3(a: u32, b: u32) i64 {
+ @setRuntimeSafety(builtin.is_test);
+
+ const bits_in_word_2 = @sizeOf(i32) * 8 / 2;
+ const lower_mask = (~u32(0)) >> bits_in_word_2;
+
+ var r: dwords = undefined;
+ r.s.low = (a & lower_mask) *% (b & lower_mask);
+ var t: u32 = r.s.low >> bits_in_word_2;
+ r.s.low &= lower_mask;
+ t += (a >> bits_in_word_2) *% (b & lower_mask);
+ r.s.low +%= (t & lower_mask) << bits_in_word_2;
+ r.s.high = t >> bits_in_word_2;
+ t = r.s.low >> bits_in_word_2;
+ r.s.low &= lower_mask;
+ t +%= (b >> bits_in_word_2) *% (a & lower_mask);
+ r.s.low +%= (t & lower_mask) << bits_in_word_2;
+ r.s.high +%= t >> bits_in_word_2;
+ r.s.high +%= (a >> bits_in_word_2) *% (b >> bits_in_word_2);
+ return r.all;
+}
+
+pub extern fn __muldi3(a: i64, b: i64) i64 {
+ @setRuntimeSafety(builtin.is_test);
+
+ const x = dwords{ .all = a };
+ const y = dwords{ .all = b };
+ var r = dwords{ .all = __muldsi3(x.s.low, y.s.low) };
+ r.s.high +%= x.s.high *% y.s.low +% x.s.low *% y.s.high;
+ return r.all;
+}
+
+test "import muldi3" {
+ _ = @import("muldi3_test.zig");
+}
diff --git a/std/special/compiler_rt/muldi3_test.zig b/std/special/compiler_rt/muldi3_test.zig
new file mode 100644
index 0000000000000000000000000000000000000000..db4daf1e1ef09c74353572a8ad51350b8e8ba0d4
--- /dev/null
+++ b/std/special/compiler_rt/muldi3_test.zig
@@ -0,0 +1,51 @@
+const __muldi3 = @import("muldi3.zig").__muldi3;
+const testing = @import("std").testing;
+
+fn test__muldi3(a: i64, b: i64, expected: i64) void {
+ const x = __muldi3(a, b);
+ testing.expect(x == expected);
+}
+
+test "muldi3" {
+ test__muldi3(0, 0, 0);
+ test__muldi3(0, 1, 0);
+ test__muldi3(1, 0, 0);
+ test__muldi3(0, 10, 0);
+ test__muldi3(10, 0, 0);
+ test__muldi3(0, 81985529216486895, 0);
+ test__muldi3(81985529216486895, 0, 0);
+
+ test__muldi3(0, -1, 0);
+ test__muldi3(-1, 0, 0);
+ test__muldi3(0, -10, 0);
+ test__muldi3(-10, 0, 0);
+ test__muldi3(0, -81985529216486895, 0);
+ test__muldi3(-81985529216486895, 0, 0);
+
+ test__muldi3(1, 1, 1);
+ test__muldi3(1, 10, 10);
+ test__muldi3(10, 1, 10);
+ test__muldi3(1, 81985529216486895, 81985529216486895);
+ test__muldi3(81985529216486895, 1, 81985529216486895);
+
+ test__muldi3(1, -1, -1);
+ test__muldi3(1, -10, -10);
+ test__muldi3(-10, 1, -10);
+ test__muldi3(1, -81985529216486895, -81985529216486895);
+ test__muldi3(-81985529216486895, 1, -81985529216486895);
+
+ test__muldi3(3037000499, 3037000499, 9223372030926249001);
+ test__muldi3(-3037000499, 3037000499, -9223372030926249001);
+ test__muldi3(3037000499, -3037000499, -9223372030926249001);
+ test__muldi3(-3037000499, -3037000499, 9223372030926249001);
+
+ test__muldi3(4398046511103, 2097152, 9223372036852678656);
+ test__muldi3(-4398046511103, 2097152, -9223372036852678656);
+ test__muldi3(4398046511103, -2097152, -9223372036852678656);
+ test__muldi3(-4398046511103, -2097152, 9223372036852678656);
+
+ test__muldi3(2097152, 4398046511103, 9223372036852678656);
+ test__muldi3(-2097152, 4398046511103, -9223372036852678656);
+ test__muldi3(2097152, -4398046511103, -9223372036852678656);
+ test__muldi3(-2097152, -4398046511103, 9223372036852678656);
+}
diff --git a/test/tests.zig b/test/tests.zig
index d94c012ac14655af305e6ded27e2569e8ad89e82..c8aea3359130d52bebc39c01530434d649e40d23 100644
--- a/test/tests.zig
+++ b/test/tests.zig
@@ -170,6 +170,7 @@ pub fn addPkgTests(
name: []const u8,
desc: []const u8,
modes: []const Mode,
+ single_threaded_list: []const bool,
skip_non_native: bool,
) *build.Step {
const step = b.step(b.fmt("test-{}", name), desc);
@@ -179,7 +180,7 @@ pub fn addPkgTests(
continue;
for (modes) |mode| {
for ([_]bool{ false, true }) |link_libc| {
- for ([_]bool{ false, true }) |single_threaded| {
+ for (single_threaded_list) |single_threaded| {
if (link_libc and !is_native) {
// don't assume we have a cross-compiling libc set up
continue;
--
2.54.0
From 57aa8997bd0b651d56a22efee46598fff167253d Mon Sep 17 00:00:00 2001
From: Vexu <15308111+Vexu@users.noreply.github.com>
Date: Sun, 21 Jul 2019 14:35:45 +0300
Subject: [PATCH 17/47] fix escape sequence rendering
---
src/ast_render.cpp | 25 ++++++++++++++++---------
test/translate_c.zig | 34 ++++++++++++++++++++++++++++++++++
2 files changed, 50 insertions(+), 9 deletions(-)
diff --git a/src/ast_render.cpp b/src/ast_render.cpp
index fe131ab65f2390326c5ec4c2232d4fc49957def3..af134d29b511d42773e3a8eec6072f8a4fc98abd 100644
--- a/src/ast_render.cpp
+++ b/src/ast_render.cpp
@@ -319,6 +319,9 @@ static bool is_digit(uint8_t c) {
}
static bool is_printable(uint8_t c) {
+ if (c == 0) {
+ return false;
+ }
static const uint8_t printables[] =
" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.~`!@#$%^&*()_-+=\\{}[];'\"?/<>,:";
for (size_t i = 0; i < array_length(printables); i += 1) {
@@ -337,20 +340,12 @@ static void string_literal_escape(Buf *source, Buf *dest) {
buf_append_str(dest, "\\\"");
} else if (c == '\\') {
buf_append_str(dest, "\\\\");
- } else if (c == '\a') {
- buf_append_str(dest, "\\a");
- } else if (c == '\b') {
- buf_append_str(dest, "\\b");
- } else if (c == '\f') {
- buf_append_str(dest, "\\f");
} else if (c == '\n') {
buf_append_str(dest, "\\n");
} else if (c == '\r') {
buf_append_str(dest, "\\r");
} else if (c == '\t') {
buf_append_str(dest, "\\t");
- } else if (c == '\v') {
- buf_append_str(dest, "\\v");
} else if (is_printable(c)) {
buf_append_char(dest, c);
} else {
@@ -630,7 +625,19 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
case NodeTypeCharLiteral:
{
uint8_t c = node->data.char_literal.value;
- if (is_printable(c)) {
+ if (c == '\'') {
+ fprintf(ar->f, "'\\''");
+ } else if (c == '\"') {
+ fprintf(ar->f, "'\\\"'");
+ } else if (c == '\\') {
+ fprintf(ar->f, "'\\\\'");
+ } else if (c == '\n') {
+ fprintf(ar->f, "'\\n'");
+ } else if (c == '\r') {
+ fprintf(ar->f, "'\\r'");
+ } else if (c == '\t') {
+ fprintf(ar->f, "'\\t'");
+ } else if (is_printable(c)) {
fprintf(ar->f, "'%c'", c);
} else {
fprintf(ar->f, "'\\x%02x'", (int)c);
diff --git a/test/translate_c.zig b/test/translate_c.zig
index d2a5b72b2bdf1bedc8caf9b16239b37ba955667b..672075e3b65f5729dd0ac1d6231a012624c3a1d8 100644
--- a/test/translate_c.zig
+++ b/test/translate_c.zig
@@ -1780,6 +1780,40 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
);
+ cases.addC("escape sequences",
+ \\const char *escapes() {
+ \\char a = '\'',
+ \\ b = '\\',
+ \\ c = '\a',
+ \\ d = '\b',
+ \\ e = '\f',
+ \\ f = '\n',
+ \\ g = '\r',
+ \\ h = '\t',
+ \\ i = '\v',
+ \\ j = '\0',
+ \\ k = '\"';
+ \\ return "\'\\\a\b\f\n\r\t\v\0\"";
+ \\}
+ \\
+ ,
+ \\pub export fn escapes() [*c]const u8 {
+ \\ var a: u8 = u8('\'');
+ \\ var b: u8 = u8('\\');
+ \\ var c: u8 = u8('\x07');
+ \\ var d: u8 = u8('\x08');
+ \\ var e: u8 = u8('\x0c');
+ \\ var f: u8 = u8('\n');
+ \\ var g: u8 = u8('\r');
+ \\ var h: u8 = u8('\t');
+ \\ var i: u8 = u8('\x0b');
+ \\ var j: u8 = u8('\x00');
+ \\ var k: u8 = u8('\"');
+ \\ return c"\'\\\x07\x08\x0c\n\r\t\x0b\x00\"";
+ \\}
+ \\
+ );
+
/////////////// Cases for only stage1 because stage2 behavior is better ////////////////
cases.addC("Parameterless function prototypes",
\\void foo() {}
--
2.54.0
From 59850c1ce12a325c8602d9201ab4a62ce12865bc Mon Sep 17 00:00:00 2001
From: Timon Kruiper
Date: Fri, 14 Jun 2019 17:05:16 +0200
Subject: [PATCH 18/47] Fixed an integer overflow in zig fmt and added testcase
---
std/zig/parser_test.zig | 26 ++++++++++++++++++++++++++
std/zig/render.zig | 8 +++++++-
2 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/std/zig/parser_test.zig b/std/zig/parser_test.zig
index f6f3363bf6e9ba9f6550829186812d8400215312..66da3d73286a3187649579289200cb8dc8ef8582 100644
--- a/std/zig/parser_test.zig
+++ b/std/zig/parser_test.zig
@@ -2267,6 +2267,32 @@ test "zig fmt: file ends with struct field" {
);
}
+test "zig fmt: comments at several places in struct init" {
+ try testTransform(
+ \\var bar = Bar{
+ \\ .x = 10, // test
+ \\ .y = "test"
+ \\ // test
+ \\};
+ \\
+ ,
+ \\var bar = Bar{
+ \\ .x = 10, // test
+ \\ .y = "test", // test
+ \\};
+ \\
+ );
+
+ try testCanonical(
+ \\var bar = Bar{ // test
+ \\ .x = 10, // test
+ \\ .y = "test",
+ \\ // test
+ \\};
+ \\
+ );
+}
+
const std = @import("std");
const mem = std.mem;
const warn = std.debug.warn;
diff --git a/std/zig/render.zig b/std/zig/render.zig
index b85c11c6ac1c5b7e98d5b6d66b19017e24f2224a..6739db42851d6dc62d4a2fa961bdb1279c4cc12f 100644
--- a/std/zig/render.zig
+++ b/std/zig/render.zig
@@ -2020,7 +2020,13 @@ fn renderTokenOffset(
const after_comment_token = tree.tokens.at(token_index + offset);
const next_line_indent = switch (after_comment_token.id) {
- Token.Id.RParen, Token.Id.RBrace, Token.Id.RBracket => indent - indent_delta,
+ Token.Id.RParen, Token.Id.RBrace, Token.Id.RBracket => blk: {
+ if (indent > indent_delta) {
+ break :blk indent - indent_delta;
+ } else {
+ break :blk 0;
+ }
+ },
else => indent,
};
try stream.writeByteNTimes(' ', next_line_indent);
--
2.54.0
From 8e4f3a6f15590402ee2a0f1d0cb3a9b62522e46e Mon Sep 17 00:00:00 2001
From: Michael Dusan
Date: Wed, 24 Jul 2019 13:01:13 -0400
Subject: [PATCH 19/47] align src for IrInstructionArrayToVector
closes #2942
---
src/codegen.cpp | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/codegen.cpp b/src/codegen.cpp
index be694b19f9feb40f8496d9d77300acbc816b194a..0ac945e8c21bd375de4fc4e82dcd13e5859d5954 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -5362,7 +5362,8 @@ static LLVMValueRef ir_render_vector_to_array(CodeGen *g, IrExecutable *executab
LLVMValueRef vector = ir_llvm_value(g, instruction->vector);
LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, result_loc,
LLVMPointerType(get_llvm_type(g, instruction->vector->value.type), 0), "");
- gen_store_untyped(g, vector, casted_ptr, get_ptr_align(g, instruction->result_loc->value.type), false);
+ uint32_t alignment = get_ptr_align(g, instruction->result_loc->value.type);
+ gen_store_untyped(g, vector, casted_ptr, alignment, false);
return result_loc;
}
@@ -5375,7 +5376,10 @@ static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executab
LLVMValueRef array_ptr = ir_llvm_value(g, instruction->array);
LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, array_ptr,
LLVMPointerType(get_llvm_type(g, vector_type), 0), "");
- return gen_load_untyped(g, casted_ptr, 0, false, "");
+ ZigType *array_type = instruction->array->value.type;
+ assert(array_type->id == ZigTypeIdArray);
+ uint32_t alignment = get_abi_alignment(g, array_type->data.array.child_type);
+ return gen_load_untyped(g, casted_ptr, alignment, false, "");
}
static LLVMValueRef ir_render_assert_zero(CodeGen *g, IrExecutable *executable,
--
2.54.0
From 9e11f67f0d921ed1280dc39e991163053be8a9ee Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 24 Jul 2019 15:05:39 -0400
Subject: [PATCH 20/47] add test for previous commit
---
test/stage1/behavior/vector.zig | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/test/stage1/behavior/vector.zig b/test/stage1/behavior/vector.zig
index 70b47c459003608b5b0626a5a4cf1905d5fb73ec..431e3fe272b641daa6d5a2e248450f8ce1f0ed63 100644
--- a/test/stage1/behavior/vector.zig
+++ b/test/stage1/behavior/vector.zig
@@ -74,3 +74,9 @@ test "implicit cast vector to array" {
S.doTheTest();
comptime S.doTheTest();
}
+
+test "array to vector" {
+ var foo: f32 = 3.14;
+ var arr = [4]f32{ foo, 1.5, 0.0, 0.0 };
+ var vec: @Vector(4, f32) = arr;
+}
--
2.54.0
From 74abc5ad2f4bf4f737b6c910b3048f7937345aad Mon Sep 17 00:00:00 2001
From: Joachim Henke <37883863+jo-he@users.noreply.github.com>
Date: Fri, 26 Jul 2019 09:59:18 +0200
Subject: [PATCH 21/47] avoid a register copy when fetching the stack pointer
in _start
---
std/special/start.zig | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/std/special/start.zig b/std/special/start.zig
index f8a018e0ae08319f0a3a6331189639336f5a435c..3427ff422dbcd7e40b8435b1b9216583407308a3 100644
--- a/std/special/start.zig
+++ b/std/special/start.zig
@@ -35,13 +35,13 @@ nakedcc fn _start() noreturn {
switch (builtin.arch) {
.x86_64 => {
- argc_ptr = asm ("lea (%%rsp), %[argc]"
- : [argc] "=r" (-> [*]usize)
+ argc_ptr = asm (""
+ : [argc] "={rsp}" (-> [*]usize)
);
},
.i386 => {
- argc_ptr = asm ("lea (%%esp), %[argc]"
- : [argc] "=r" (-> [*]usize)
+ argc_ptr = asm (""
+ : [argc] "={esp}" (-> [*]usize)
);
},
.aarch64, .aarch64_be => {
--
2.54.0
From 5593c63e12a8d85052f548218b2957dea314be18 Mon Sep 17 00:00:00 2001
From: emekoi
Date: Fri, 26 Jul 2019 16:26:01 -0500
Subject: [PATCH 22/47] improved CMake file for MinGW
---
CMakeLists.txt | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d8cf0c507d8d34c47eb00152e6b77a7b9d808664..debfb9392c4173b1d38192687495889e7df21c83 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -209,7 +209,7 @@ else()
else()
set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -fvisibility-inlines-hidden -fno-exceptions -fno-rtti -Wno-comment")
if(MINGW)
- set(ZIG_LLD_COMPILE_FLAGS "${ZIG_LLD_COMPILE_FLAGS} -D__STDC_FORMAT_MACROS -D__USE_MINGW_ANSI_STDIO -Wno-pedantic-ms-format")
+ set(ZIG_LLD_COMPILE_FLAGS "${ZIG_LLD_COMPILE_FLAGS} -D__STDC_FORMAT_MACROS -D__USE_MINGW_ANSI_STDIO")
endif()
endif()
set_target_properties(embedded_lld_lib PROPERTIES
@@ -511,19 +511,23 @@ set(OPTIMIZED_C_FLAGS "-std=c99 -O3")
set(EXE_LDFLAGS " ")
if(MSVC)
- set(EXE_LDFLAGS "/STACK:16777216")
+ set(EXE_LDFLAGS "${EXE_LDFLAGS} /STACK:16777216")
elseif(MINGW)
set(EXE_LDFLAGS "${EXE_LDFLAGS} -Wl,--stack,16777216")
endif()
if(ZIG_STATIC)
if(APPLE)
- set(EXE_LDFLAGS "-static-libgcc -static-libstdc++")
+ set(EXE_LDFLAGS "${EXE_LDFLAGS} -static-libgcc -static-libstdc++")
elseif(MINGW)
- set(EXE_LDFLAGS "-static-libgcc -static-libstdc++ -Wl,-Bstatic,--whole-archive -lwinpthread -lz3 -lz -lgomp -Wl,--no-whole-archive")
+ set(EXE_LDFLAGS "${EXE_LDFLAGS} -static-libgcc -static-libstdc++ -Wl,-Bstatic, -lwinpthread -lz3 -lz -lgomp")
else()
- set(EXE_LDFLAGS "-static")
+ set(EXE_LDFLAGS "${EXE_LDFLAGS} -static")
endif()
+else()
+ if(MINGW)
+ set(EXE_LDFLAGS "${EXE_LDFLAGS} -lz3")
+ endif()
endif()
if(ZIG_TEST_COVERAGE)
@@ -559,11 +563,6 @@ if(NOT MSVC)
target_link_libraries(compiler LINK_PUBLIC ${LIBXML2})
endif()
-if(MINGW)
- find_library(Z3_LIBRARIES NAMES z3 z3.dll)
- target_link_libraries(compiler LINK_PUBLIC ${Z3_LIBRARIES})
-endif()
-
if(ZIG_DIA_GUIDS_LIB)
target_link_libraries(compiler LINK_PUBLIC ${ZIG_DIA_GUIDS_LIB})
endif()
--
2.54.0
From 10b10177025790ffa84304f282e8323ea2b10c37 Mon Sep 17 00:00:00 2001
From: emekoi
Date: Sat, 27 Jul 2019 17:50:44 -0500
Subject: [PATCH 23/47] fixed backtraces when linking libc on mingw
---
std/coff.zig | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/std/coff.zig b/std/coff.zig
index 9fdc3688787276c00f27d7bf17c52b9cadd18c17..7c53f48f66352d1f9000a1c22f895a8d8f0f4809 100644
--- a/std/coff.zig
+++ b/std/coff.zig
@@ -120,7 +120,15 @@ pub const Coff = struct {
pub fn getPdbPath(self: *Coff, buffer: []u8) !usize {
try self.loadSections();
- const header = (self.getSection(".rdata") orelse return error.MissingCoffSection).header;
+ const header = blk: {
+ if (self.getSection(".buildid")) |section| {
+ break :blk section.header;
+ } else if (self.getSection(".rdata")) |section| {
+ break :blk section.header;
+ } else {
+ return error.MissingCoffSection;
+ }
+ };
// The linker puts a chunk that contains the .pdb path right after the
// debug_directory.
--
2.54.0
From 357fb4f1436fca4b68ca5adf14ba85f3b21b5dcf Mon Sep 17 00:00:00 2001
From: emekoi
Date: Sat, 27 Jul 2019 17:54:20 -0500
Subject: [PATCH 24/47] avoid passing -static to msvc when static linking
---
CMakeLists.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index debfb9392c4173b1d38192687495889e7df21c83..998da172fccdd002da61350ad34314beffce18e3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -521,7 +521,7 @@ if(ZIG_STATIC)
set(EXE_LDFLAGS "${EXE_LDFLAGS} -static-libgcc -static-libstdc++")
elseif(MINGW)
set(EXE_LDFLAGS "${EXE_LDFLAGS} -static-libgcc -static-libstdc++ -Wl,-Bstatic, -lwinpthread -lz3 -lz -lgomp")
- else()
+ elseif(NOT MSVC)
set(EXE_LDFLAGS "${EXE_LDFLAGS} -static")
endif()
else()
--
2.54.0
From a0ebfa64d9b8e98b31d37c80d118aab84f1a493e Mon Sep 17 00:00:00 2001
From: Evan Krause
Date: Sun, 28 Jul 2019 18:37:35 -0700
Subject: [PATCH 25/47] support zero-sized structs in zig.fmt.format
---
std/fmt.zig | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/std/fmt.zig b/std/fmt.zig
index 2e9527f4ca8ed03103c4e233b4cd78dd93626df3..479ea76e8cc860c677c2dbb260b642cbf30d3482 100644
--- a/std/fmt.zig
+++ b/std/fmt.zig
@@ -374,9 +374,10 @@ pub fn formatType(
return output(context, "{ ... }");
}
comptime var field_i = 0;
+ try output(context, "{");
inline while (field_i < @memberCount(T)) : (field_i += 1) {
if (field_i == 0) {
- try output(context, "{ .");
+ try output(context, " .");
} else {
try output(context, ", .");
}
@@ -1439,6 +1440,21 @@ test "struct.self-referential" {
try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", inst);
}
+test "struct.zero-size" {
+ const A = struct {
+ fn foo() void {}
+ };
+ const B = struct {
+ a: A,
+ c: i32,
+ };
+
+ const a = A{};
+ const b = B{ .a = a, .c = 0 };
+
+ try testFmt("B{ .a = A{ }, .c = 0 }", "{}", b);
+}
+
test "bytes.hex" {
const some_bytes = "\xCA\xFE\xBA\xBE";
try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", some_bytes);
--
2.54.0
From 7e436006be93d43a9e93206e29f9a08cbd8e109e Mon Sep 17 00:00:00 2001
From: Michael Dusan
Date: Sun, 28 Jul 2019 08:38:11 -0400
Subject: [PATCH 26/47] fix std.rb.Node.getParent to return optional
closes #2962
---
std/rb.zig | 3 ++-
std/std.zig | 1 +
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/std/rb.zig b/std/rb.zig
index 0b28550a131927573bbc5f89550727a3789ecbb6..b5935a2eacbf2ce116cba1e403c5026e534c5061 100644
--- a/std/rb.zig
+++ b/std/rb.zig
@@ -93,7 +93,8 @@ pub const Node = struct {
comptime {
assert(@alignOf(*Node) >= 2);
}
- return @intToPtr(*Node, node.parent_and_color & ~mask);
+ const maybe_ptr = node.parent_and_color & ~mask;
+ return if (maybe_ptr == 0) null else @intToPtr(*Node, maybe_ptr);
}
fn setColor(node: *Node, color: Color) void {
diff --git a/std/std.zig b/std/std.zig
index 350f0fb437897b1f1a243dc5e5673fbafbf9f585..e48586d8731691075bd943c7ffae0131959066a1 100644
--- a/std/std.zig
+++ b/std/std.zig
@@ -105,6 +105,7 @@ test "std" {
_ = @import("packed_int_array.zig");
_ = @import("priority_queue.zig");
_ = @import("rand.zig");
+ _ = @import("rb.zig");
_ = @import("sort.zig");
_ = @import("testing.zig");
_ = @import("thread.zig");
--
2.54.0
From 8736a5be2ac280db8fd34c86efd1b764a255f23c Mon Sep 17 00:00:00 2001
From: Nick Erdmann
Date: Fri, 26 Jul 2019 15:01:49 +0200
Subject: [PATCH 27/47] std/build.zig: fix stack checking option
---
std/build.zig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/std/build.zig b/std/build.zig
index 3a0c34c8d1ae2ad9dde4f4b304623b8067631ce6..6be88ae7ecddc20a26927b6795ad0d86c83cf3b8 100644
--- a/std/build.zig
+++ b/std/build.zig
@@ -1802,7 +1802,7 @@ pub const LibExeObjStep = struct {
try zig_args.append("--bundle-compiler-rt");
}
if (self.disable_stack_probing) {
- try zig_args.append("--disable-stack-probing");
+ try zig_args.append("-fno-stack-check");
}
switch (self.target) {
--
2.54.0
From bc982e65cf77aa6551029620ceaec8f3ae49202f Mon Sep 17 00:00:00 2001
From: Michael Dusan
Date: Thu, 25 Jul 2019 19:59:34 -0400
Subject: [PATCH 28/47] fix std.fmt to handle std.SegmentedList
- add guards for use of prealloc_exp in SegmentedList
- define prealloc_exp even when invalid because std.fmt comptime
triggers lazy-init
- fix std.fmt to print arrays of length 0 as style "[0]"
because "@address" is n/a without address
---
std/fmt.zig | 3 +++
std/segmented_list.zig | 31 +++++++++++++++++++------------
2 files changed, 22 insertions(+), 12 deletions(-)
diff --git a/std/fmt.zig b/std/fmt.zig
index 479ea76e8cc860c677c2dbb260b642cbf30d3482..7c08cd14ee48dea9c84d09d14d9344b88ccab060 100644
--- a/std/fmt.zig
+++ b/std/fmt.zig
@@ -426,6 +426,9 @@ pub fn formatType(
if (info.child == u8) {
return formatText(value, fmt, options, context, Errors, output);
}
+ if (value.len == 0) {
+ return format(context, Errors, output, "[0]{}", @typeName(T.Child));
+ }
return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));
},
.Fn => {
diff --git a/std/segmented_list.zig b/std/segmented_list.zig
index e0b84d5c0de9bd89fb27fa3645dc3a3505863714..3bbbde782e3e3ab8cfe669034e55e8ef582b7ccb 100644
--- a/std/segmented_list.zig
+++ b/std/segmented_list.zig
@@ -77,16 +77,20 @@ const Allocator = std.mem.Allocator;
pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type {
return struct {
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);
- assert(std.math.isPowerOfTwo(prealloc_item_count));
-
- const value = std.math.log2_int(usize, prealloc_item_count);
- break :blk @typeOf(1)(value);
- };
const ShelfIndex = std.math.Log2Int(usize);
+ const prealloc_exp: ShelfIndex = blk: {
+ // we don't use the prealloc_exp constant when prealloc_item_count is 0
+ // but lazy-init may still be triggered by other code so supply a value
+ if (prealloc_item_count == 0) {
+ break :blk 0;
+ } else {
+ assert(std.math.isPowerOfTwo(prealloc_item_count));
+ const value = std.math.log2_int(usize, prealloc_item_count);
+ break :blk value;
+ }
+ };
+
prealloc_segment: [prealloc_item_count]T,
dynamic_segments: [][*]T,
allocator: *Allocator,
@@ -157,11 +161,12 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
/// Grows or shrinks capacity to match usage.
pub fn setCapacity(self: *Self, new_capacity: usize) !void {
- if (new_capacity <= usize(1) << (prealloc_exp + self.dynamic_segments.len)) {
- return self.shrinkCapacity(new_capacity);
- } else {
- return self.growCapacity(new_capacity);
+ if (prealloc_item_count != 0) {
+ if (new_capacity <= usize(1) << (prealloc_exp + @intCast(ShelfIndex, self.dynamic_segments.len))) {
+ return self.shrinkCapacity(new_capacity);
+ }
}
+ return self.growCapacity(new_capacity);
}
/// Only grows capacity, or retains current capacity
@@ -399,4 +404,6 @@ fn testSegmentedList(comptime prealloc: usize, allocator: *Allocator) !void {
testing.expect(item == i);
list.shrinkCapacity(list.len);
}
+
+ try list.setCapacity(0);
}
--
2.54.0
From d08425a0a5b15fa903d379ea5547fbb5dfecda62 Mon Sep 17 00:00:00 2001
From: Sahnvour
Date: Sun, 28 Jul 2019 17:31:40 +0200
Subject: [PATCH 29/47] os: missing accessW since recent refactoring
---
std/os.zig | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/std/os.zig b/std/os.zig
index 190f02101e2c8672ea0b2560bf6641009ab1f6aa..9ff2e8f87f22a71d30d35ed834e70bc2e29e1a63 100644
--- a/std/os.zig
+++ b/std/os.zig
@@ -2053,6 +2053,22 @@ pub fn accessC(path: [*]const u8, mode: u32) AccessError!void {
}
}
+/// Call from Windows-specific code if you already have a UTF-16LE encoded, null terminated string.
+/// Otherwise use `access` or `accessC`.
+/// TODO currently this ignores `mode`.
+pub fn accessW(path: [*]const u16, mode: u32) windows.GetFileAttributesError!void {
+ const ret = try windows.GetFileAttributesW(path);
+ if (ret != windows.INVALID_FILE_ATTRIBUTES) {
+ return;
+ }
+ switch (windows.kernel32.GetLastError()) {
+ windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
+ windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
+ windows.ERROR.ACCESS_DENIED => return error.PermissionDenied,
+ else => |err| return windows.unexpectedError(err),
+ }
+}
+
pub const PipeError = error{
SystemFdQuotaExceeded,
ProcessFdQuotaExceeded,
--
2.54.0
From 05032c869378e7c7e3da3a2770161266058aa320 Mon Sep 17 00:00:00 2001
From: Sahnvour
Date: Sun, 28 Jul 2019 19:03:36 +0200
Subject: [PATCH 30/47] coff & pdb: improved correctness of our implementation,
it is now able to handle stage1's pdb and print its stack traces
---
std/coff.zig | 42 +++++++++++++++++---
std/debug.zig | 13 +++++--
std/pdb.zig | 103 ++++++++++++++++++++++++++++++++------------------
3 files changed, 113 insertions(+), 45 deletions(-)
diff --git a/std/coff.zig b/std/coff.zig
index 7c53f48f66352d1f9000a1c22f895a8d8f0f4809..3890151d09ac6606674532c96149fc193fe77619 100644
--- a/std/coff.zig
+++ b/std/coff.zig
@@ -19,6 +19,7 @@ const IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b;
const IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b;
const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
+const IMAGE_DEBUG_TYPE_CODEVIEW = 2;
const DEBUG_DIRECTORY = 6;
pub const CoffError = error{
@@ -28,6 +29,7 @@ pub const CoffError = error{
MissingCoffSection,
};
+// Official documentation of the format: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
pub const Coff = struct {
in_file: File,
allocator: *mem.Allocator,
@@ -120,6 +122,7 @@ pub const Coff = struct {
pub fn getPdbPath(self: *Coff, buffer: []u8) !usize {
try self.loadSections();
+
const header = blk: {
if (self.getSection(".buildid")) |section| {
break :blk section.header;
@@ -130,14 +133,32 @@ pub const Coff = struct {
}
};
- // The linker puts a chunk that contains the .pdb path right after the
- // debug_directory.
const debug_dir = &self.pe_header.data_directory[DEBUG_DIRECTORY];
const file_offset = debug_dir.virtual_address - header.virtual_address + header.pointer_to_raw_data;
- try self.in_file.seekTo(file_offset + debug_dir.size);
var file_stream = self.in_file.inStream();
const in = &file_stream.stream;
+ try self.in_file.seekTo(file_offset);
+
+ // Find the correct DebugDirectoryEntry, and where its data is stored.
+ // It can be in any section.
+ const debug_dir_entry_count = debug_dir.size / @sizeOf(DebugDirectoryEntry);
+ var i: u32 = 0;
+ blk: while (i < debug_dir_entry_count) : (i += 1) {
+ const debug_dir_entry = try in.readStruct(DebugDirectoryEntry);
+ if (debug_dir_entry.type == IMAGE_DEBUG_TYPE_CODEVIEW) {
+ for (self.sections.toSlice()) |*section| {
+ const section_start = section.header.virtual_address;
+ const section_size = section.header.misc.virtual_size;
+ const rva = debug_dir_entry.address_of_raw_data;
+ const offset = rva - section_start;
+ if (section_start <= rva and offset < section_size and debug_dir_entry.size_of_data <= section_size - offset) {
+ try self.in_file.seekTo(section.header.pointer_to_raw_data + offset);
+ break :blk;
+ }
+ }
+ }
+ }
var cv_signature: [4]u8 = undefined; // CodeView signature
try in.readNoEof(cv_signature[0..]);
@@ -149,7 +170,7 @@ pub const Coff = struct {
// Finally read the null-terminated string.
var byte = try in.readByte();
- var i: usize = 0;
+ i = 0;
while (byte != 0 and i < buffer.len) : (i += 1) {
buffer[i] = byte;
byte = try in.readByte();
@@ -178,7 +199,7 @@ pub const Coff = struct {
try self.sections.append(Section{
.header = SectionHeader{
.name = name,
- .misc = SectionHeader.Misc{ .physical_address = try in.readIntLittle(u32) },
+ .misc = SectionHeader.Misc{ .virtual_size = try in.readIntLittle(u32) },
.virtual_address = try in.readIntLittle(u32),
.size_of_raw_data = try in.readIntLittle(u32),
.pointer_to_raw_data = try in.readIntLittle(u32),
@@ -222,6 +243,17 @@ const OptionalHeader = struct {
data_directory: [IMAGE_NUMBEROF_DIRECTORY_ENTRIES]DataDirectory,
};
+const DebugDirectoryEntry = packed struct {
+ characteristiccs: u32,
+ time_date_stamp: u32,
+ major_version: u16,
+ minor_version: u16,
+ @"type": u32,
+ size_of_data: u32,
+ address_of_raw_data: u32,
+ pointer_to_raw_data: u32,
+};
+
pub const Section = struct {
header: SectionHeader,
};
diff --git a/std/debug.zig b/std/debug.zig
index 7d1fd6ce47d79be5840cfb412a8428f8a73d37fd..32f96d3e1559cf4cf7f08a8e21b4789367191e6f 100644
--- a/std/debug.zig
+++ b/std/debug.zig
@@ -375,7 +375,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres
const obj_basename = fs.path.basename(mod.obj_file_name);
var symbol_i: usize = 0;
- const symbol_name = while (symbol_i != mod.symbols.len) {
+ const symbol_name = if (!mod.populated) "???" else while (symbol_i != mod.symbols.len) {
const prefix = @ptrCast(*pdb.RecordPrefix, &mod.symbols[symbol_i]);
if (prefix.RecordLen < 2)
return error.InvalidDebugInfo;
@@ -858,8 +858,10 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
const age = try pdb_stream.stream.readIntLittle(u32);
var guid: [16]u8 = undefined;
try pdb_stream.stream.readNoEof(guid[0..]);
+ if (version != 20000404) // VC70, only value observed by LLVM team
+ return error.UnknownPDBVersion;
if (!mem.eql(u8, di.coff.guid, guid) or di.coff.age != age)
- return error.InvalidDebugInfo;
+ return error.PDBMismatch;
// We validated the executable and pdb match.
const string_table_index = str_tab_index: {
@@ -903,13 +905,18 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
return error.MissingDebugInfo;
};
- di.pdb.string_table = di.pdb.getStreamById(string_table_index) orelse return error.InvalidDebugInfo;
+ di.pdb.string_table = di.pdb.getStreamById(string_table_index) orelse return error.MissingDebugInfo;
di.pdb.dbi = di.pdb.getStream(pdb.StreamType.Dbi) orelse return error.MissingDebugInfo;
const dbi = di.pdb.dbi;
// Dbi Header
const dbi_stream_header = try dbi.stream.readStruct(pdb.DbiStreamHeader);
+ if (dbi_stream_header.VersionHeader != 19990903) // V70, only value observed by LLVM team
+ return error.UnknownPDBVersion;
+ if (dbi_stream_header.Age != age)
+ return error.UnmatchingPDB;
+
const mod_info_size = dbi_stream_header.ModInfoSize;
const section_contrib_size = dbi_stream_header.SectionContributionSize;
diff --git a/std/pdb.zig b/std/pdb.zig
index ffe21202960412a44f306f13df27ad370ba1c99f..39f304afb59d2fe00f18b521727b2eea9d49752e 100644
--- a/std/pdb.zig
+++ b/std/pdb.zig
@@ -499,45 +499,78 @@ const Msf = struct {
const superblock = try in.readStruct(SuperBlock);
+ // Sanity checks
if (!mem.eql(u8, superblock.FileMagic, SuperBlock.file_magic))
return error.InvalidDebugInfo;
-
+ if (superblock.FreeBlockMapBlock != 1 and superblock.FreeBlockMapBlock != 2)
+ return error.InvalidDebugInfo;
+ if (superblock.NumBlocks * superblock.BlockSize != try file.getEndPos())
+ return error.InvalidDebugInfo;
switch (superblock.BlockSize) {
// llvm only supports 4096 but we can handle any of these values
512, 1024, 2048, 4096 => {},
else => return error.InvalidDebugInfo,
}
- if (superblock.NumBlocks * superblock.BlockSize != try file.getEndPos())
- return error.InvalidDebugInfo;
+ const dir_block_count = blockCountFromSize(superblock.NumDirectoryBytes, superblock.BlockSize);
+ if (dir_block_count > superblock.BlockSize / @sizeOf(u32))
+ return error.UnhandledBigDirectoryStream; // cf. BlockMapAddr comment.
- self.directory = try MsfStream.init(
+ try file.seekTo(superblock.BlockSize * superblock.BlockMapAddr);
+ var dir_blocks = try allocator.alloc(u32, dir_block_count);
+ for (dir_blocks) |*b| {
+ b.* = try in.readIntLittle(u32);
+ }
+ self.directory = MsfStream.init(
superblock.BlockSize,
- blockCountFromSize(superblock.NumDirectoryBytes, superblock.BlockSize),
- superblock.BlockSize * superblock.BlockMapAddr,
file,
- allocator,
+ dir_blocks,
);
+ const begin = self.directory.pos;
const stream_count = try self.directory.stream.readIntLittle(u32);
-
const stream_sizes = try allocator.alloc(u32, stream_count);
- for (stream_sizes) |*s| {
+ defer allocator.free(stream_sizes);
+
+ // Microsoft's implementation uses u32(-1) for inexistant streams.
+ // These streams are not used, but still participate in the file
+ // and must be taken into account when resolving stream indices.
+ const Nil = 0xFFFFFFFF;
+ for (stream_sizes) |*s, i| {
const size = try self.directory.stream.readIntLittle(u32);
- s.* = blockCountFromSize(size, superblock.BlockSize);
+ s.* = if (size == Nil) 0 else blockCountFromSize(size, superblock.BlockSize);
}
self.streams = try allocator.alloc(MsfStream, stream_count);
for (self.streams) |*stream, i| {
- stream.* = try MsfStream.init(
- superblock.BlockSize,
- stream_sizes[i],
- // MsfStream.init expects the file to be at the part where it reads [N]u32
- try file.getPos(),
- file,
- allocator,
- );
+ const size = stream_sizes[i];
+ if (size == 0) {
+ stream.* = MsfStream{
+ .blocks = [_]u32{},
+ };
+ } else {
+ var blocks = try allocator.alloc(u32, size);
+ var j: u32 = 0;
+ while (j < size) : (j += 1) {
+ const block_id = try self.directory.stream.readIntLittle(u32);
+ const n = (block_id % superblock.BlockSize);
+ // 0 is for SuperBlock, 1 and 2 for FPMs.
+ if (block_id == 0 or n == 1 or n == 2 or block_id * superblock.BlockSize > try file.getEndPos())
+ return error.InvalidBlockIndex;
+ blocks[j] = block_id;
+ }
+
+ stream.* = MsfStream.init(
+ superblock.BlockSize,
+ file,
+ blocks,
+ );
+ }
}
+
+ const end = self.directory.pos;
+ if (end - begin != superblock.NumDirectoryBytes)
+ return error.InvalidStreamDirectory;
}
};
@@ -574,7 +607,6 @@ const SuperBlock = packed struct {
NumDirectoryBytes: u32,
Unknown: u32,
-
/// The index of a block within the MSF file. At this block is an array of
/// ulittle32_t’s listing the blocks that the stream directory resides on.
/// For large MSF files, the stream directory (which describes the block
@@ -584,45 +616,41 @@ const SuperBlock = packed struct {
/// and the stream directory itself can be stitched together accordingly.
/// The number of ulittle32_t’s in this array is given by
/// ceil(NumDirectoryBytes / BlockSize).
+ // Note: microsoft-pdb code actually suggests this is a variable-length
+ // array. If the indices of blocks occupied by the Stream Directory didn't
+ // fit in one page, there would be other u32 following it.
+ // This would mean the Stream Directory is bigger than BlockSize / sizeof(u32)
+ // blocks. We're not even close to this with a 1GB pdb file, and LLVM didn't
+ // implement it so we're kind of safe making this assumption for now.
BlockMapAddr: u32,
};
const MsfStream = struct {
- in_file: File,
- pos: u64,
- blocks: []u32,
- block_size: u32,
+ in_file: File = undefined,
+ pos: u64 = undefined,
+ blocks: []u32 = undefined,
+ block_size: u32 = undefined,
/// Implementation of InStream trait for Pdb.MsfStream
- stream: Stream,
+ stream: Stream = undefined,
pub const Error = @typeOf(read).ReturnType.ErrorSet;
pub const Stream = io.InStream(Error);
- fn init(block_size: u32, block_count: u32, pos: u64, file: File, allocator: *mem.Allocator) !MsfStream {
- var stream = MsfStream{
+ fn init(block_size: u32, file: File, blocks: []u32) MsfStream {
+ const stream = MsfStream{
.in_file = file,
.pos = 0,
- .blocks = try allocator.alloc(u32, block_count),
+ .blocks = blocks,
.block_size = block_size,
.stream = Stream{ .readFn = readFn },
};
- var file_stream = file.inStream();
- const in = &file_stream.stream;
- try file.seekTo(pos);
-
- var i: u32 = 0;
- while (i < block_count) : (i += 1) {
- stream.blocks[i] = try in.readIntLittle(u32);
- }
-
return stream;
}
fn readNullTermString(self: *MsfStream, allocator: *mem.Allocator) ![]u8 {
var list = ArrayList(u8).init(allocator);
- defer list.deinit();
while (true) {
const byte = try self.stream.readByte();
if (byte == 0) {
@@ -633,6 +661,7 @@ const MsfStream = struct {
}
fn read(self: *MsfStream, buffer: []u8) !usize {
+
var block_id = @intCast(usize, self.pos / self.block_size);
var block = self.blocks[block_id];
var offset = self.pos % self.block_size;
--
2.54.0
From c087525edae2db147c89c83513a0778f87bee30d Mon Sep 17 00:00:00 2001
From: Sahnvour
Date: Sun, 28 Jul 2019 18:46:40 +0200
Subject: [PATCH 31/47] pdb: improved stream reading performance, printing
stack trace from a stage1 crash is now 10x faster
---
std/pdb.zig | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/std/pdb.zig b/std/pdb.zig
index 39f304afb59d2fe00f18b521727b2eea9d49752e..7a2b2c6b6b0ded59816da570f04ba6b00388fbc6 100644
--- a/std/pdb.zig
+++ b/std/pdb.zig
@@ -661,7 +661,6 @@ const MsfStream = struct {
}
fn read(self: *MsfStream, buffer: []u8) !usize {
-
var block_id = @intCast(usize, self.pos / self.block_size);
var block = self.blocks[block_id];
var offset = self.pos % self.block_size;
@@ -671,11 +670,12 @@ const MsfStream = struct {
const in = &file_stream.stream;
var size: usize = 0;
- for (buffer) |*byte| {
- byte.* = try in.readByte();
-
- offset += 1;
- size += 1;
+ var rem_buffer = buffer;
+ while (size < buffer.len) {
+ const size_to_read = math.min(self.block_size - offset, rem_buffer.len);
+ size += try in.read(rem_buffer[0..size_to_read]);
+ rem_buffer = buffer[size..];
+ offset += size_to_read;
// If we're at the end of a block, go to the next one.
if (offset == self.block_size) {
@@ -686,8 +686,8 @@ const MsfStream = struct {
}
}
- self.pos += size;
- return size;
+ self.pos += buffer.len;
+ return buffer.len;
}
fn seekBy(self: *MsfStream, len: i64) !void {
--
2.54.0
From e40513e97ff57960165b30a6b9fecfaad95bd1aa Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Wed, 31 Jul 2019 21:26:39 -0500
Subject: [PATCH 32/47] Add builder.findProgram test and fix references
---
std/build.zig | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/std/build.zig b/std/build.zig
index 3a0c34c8d1ae2ad9dde4f4b304623b8067631ce6..acd3a1e33bdcc502d990eb95d528ea972de749d4 100644
--- a/std/build.zig
+++ b/std/build.zig
@@ -805,7 +805,7 @@ pub const Builder = struct {
return name;
}
const full_path = try fs.path.join(self.allocator, [_][]const u8{ search_prefix, "bin", self.fmt("{}{}", name, exe_extension) });
- if (fs.path.real(self.allocator, full_path)) |real_path| {
+ if (fs.realpathAlloc(self.allocator, full_path)) |real_path| {
return real_path;
} else |_| {
continue;
@@ -817,10 +817,10 @@ pub const Builder = struct {
if (fs.path.isAbsolute(name)) {
return name;
}
- var it = mem.tokenize(PATH, []u8{fs.path.delimiter});
+ var it = mem.tokenize(PATH, [_]u8{fs.path.delimiter});
while (it.next()) |path| {
const full_path = try fs.path.join(self.allocator, [_][]const u8{ path, self.fmt("{}{}", name, exe_extension) });
- if (fs.path.real(self.allocator, full_path)) |real_path| {
+ if (fs.realpathAlloc(self.allocator, full_path)) |real_path| {
return real_path;
} else |_| {
continue;
@@ -834,7 +834,7 @@ pub const Builder = struct {
}
for (paths) |path| {
const full_path = try fs.path.join(self.allocator, [_][]const u8{ path, self.fmt("{}{}", name, exe_extension) });
- if (fs.path.real(self.allocator, full_path)) |real_path| {
+ if (fs.realpathAlloc(self.allocator, full_path)) |real_path| {
return real_path;
} else |_| {
continue;
@@ -904,6 +904,15 @@ pub const Builder = struct {
}
};
+test "builder.findProgram compiles" {
+ //allocator: *Allocator,
+ //zig_exe: []const u8,
+ //build_root: []const u8,
+ //cache_root: []const u8,
+ const builder = try Builder.create(std.heap.direct_allocator, "zig", "zig-cache", "zig-cache");
+ _ = builder.findProgram([_][]const u8{}, [_][]const u8{}) catch null;
+}
+
pub const Version = struct {
major: u32,
minor: u32,
--
2.54.0
From 327abdba0b5de1f1eeef32e19b6a16ec4c7ec323 Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Wed, 31 Jul 2019 21:28:25 -0500
Subject: [PATCH 33/47] More current style for error handling
---
std/build.zig | 18 +++---------------
1 file changed, 3 insertions(+), 15 deletions(-)
diff --git a/std/build.zig b/std/build.zig
index acd3a1e33bdcc502d990eb95d528ea972de749d4..997e2ab9014c0b6183cf414a2b58133c38f16d32 100644
--- a/std/build.zig
+++ b/std/build.zig
@@ -805,11 +805,7 @@ pub const Builder = struct {
return name;
}
const full_path = try fs.path.join(self.allocator, [_][]const u8{ search_prefix, "bin", self.fmt("{}{}", name, exe_extension) });
- if (fs.realpathAlloc(self.allocator, full_path)) |real_path| {
- return real_path;
- } else |_| {
- continue;
- }
+ return fs.realpathAlloc(self.allocator, full_path) catch continue;
}
}
if (self.env_map.get("PATH")) |PATH| {
@@ -820,11 +816,7 @@ pub const Builder = struct {
var it = mem.tokenize(PATH, [_]u8{fs.path.delimiter});
while (it.next()) |path| {
const full_path = try fs.path.join(self.allocator, [_][]const u8{ path, self.fmt("{}{}", name, exe_extension) });
- if (fs.realpathAlloc(self.allocator, full_path)) |real_path| {
- return real_path;
- } else |_| {
- continue;
- }
+ return fs.realpathAlloc(self.allocator, full_path) catch continue;
}
}
}
@@ -834,11 +826,7 @@ pub const Builder = struct {
}
for (paths) |path| {
const full_path = try fs.path.join(self.allocator, [_][]const u8{ path, self.fmt("{}{}", name, exe_extension) });
- if (fs.realpathAlloc(self.allocator, full_path)) |real_path| {
- return real_path;
- } else |_| {
- continue;
- }
+ return fs.realpathAlloc(self.allocator, full_path) catch continue;
}
}
return error.FileNotFound;
--
2.54.0
From 723aea8369375d17d19bc1e6d02dbf6eb4d9ba49 Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Wed, 31 Jul 2019 22:07:17 -0500
Subject: [PATCH 34/47] Default wasm-lib prefix to empty
---
std/build.zig | 3 +++
1 file changed, 3 insertions(+)
diff --git a/std/build.zig b/std/build.zig
index 997e2ab9014c0b6183cf414a2b58133c38f16d32..d63e1ae8998e644084b01a4af49de63f6c9582da 100644
--- a/std/build.zig
+++ b/std/build.zig
@@ -1119,6 +1119,9 @@ pub const Target = union(enum) {
}
pub fn libPrefix(self: Target) []const u8 {
+ if (self.isWasm()) {
+ return "";
+ }
switch (self.getAbi()) {
.msvc => return "",
else => return "lib",
--
2.54.0
From 38b5812c4895eb0157f99348f51c40bbd17c3b94 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 1 Aug 2019 02:37:22 -0400
Subject: [PATCH 35/47] allow 128 bit cmpxchg on x86_64
---
src/ir.cpp | 7 ++--
src/target.cpp | 66 ++++++++++++++++++++++++++++++++
src/target.hpp | 1 +
test/stage1/behavior/atomics.zig | 20 ++++++++++
4 files changed, 91 insertions(+), 3 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index be7a8e2e5124b054cfb96ea3b9268e4c21d05d66..f34c840496e30180ddf4873b16df4c1761ee1edf 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -24735,10 +24735,11 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op
operand_type->data.integral.bit_count));
return ira->codegen->builtin_types.entry_invalid;
}
- if (operand_type->data.integral.bit_count > ira->codegen->pointer_size_bytes * 8) {
+ uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch);
+ if (operand_type->data.integral.bit_count > max_atomic_bits) {
ir_add_error(ira, op,
- buf_sprintf("expected integer type pointer size or smaller, found %" PRIu32 "-bit integer type",
- operand_type->data.integral.bit_count));
+ buf_sprintf("expected %" PRIu32 "-bit integer type or smaller, found %" PRIu32 "-bit integer type",
+ max_atomic_bits, operand_type->data.integral.bit_count));
return ira->codegen->builtin_types.entry_invalid;
}
if (!is_power_of_2(operand_type->data.integral.bit_count)) {
diff --git a/src/target.cpp b/src/target.cpp
index 6a949270aefa274a2daefc69cc053616109cbdeb..7bb248a35fa30f2824c68f32cc356d3550c1da90 100644
--- a/src/target.cpp
+++ b/src/target.cpp
@@ -863,6 +863,71 @@ uint32_t target_arch_pointer_bit_width(ZigLLVM_ArchType arch) {
zig_unreachable();
}
+uint32_t target_arch_largest_atomic_bits(ZigLLVM_ArchType arch) {
+ switch (arch) {
+ case ZigLLVM_UnknownArch:
+ zig_unreachable();
+
+ case ZigLLVM_avr:
+ case ZigLLVM_msp430:
+ return 16;
+
+ case ZigLLVM_arc:
+ case ZigLLVM_arm:
+ case ZigLLVM_armeb:
+ case ZigLLVM_hexagon:
+ case ZigLLVM_le32:
+ case ZigLLVM_mips:
+ case ZigLLVM_mipsel:
+ case ZigLLVM_nvptx:
+ case ZigLLVM_ppc:
+ case ZigLLVM_r600:
+ case ZigLLVM_riscv32:
+ case ZigLLVM_sparc:
+ case ZigLLVM_sparcel:
+ case ZigLLVM_tce:
+ case ZigLLVM_tcele:
+ case ZigLLVM_thumb:
+ case ZigLLVM_thumbeb:
+ case ZigLLVM_x86:
+ case ZigLLVM_xcore:
+ case ZigLLVM_amdil:
+ case ZigLLVM_hsail:
+ case ZigLLVM_spir:
+ case ZigLLVM_kalimba:
+ case ZigLLVM_lanai:
+ case ZigLLVM_shave:
+ case ZigLLVM_wasm32:
+ case ZigLLVM_renderscript32:
+ return 32;
+
+ case ZigLLVM_aarch64:
+ case ZigLLVM_aarch64_be:
+ case ZigLLVM_amdgcn:
+ case ZigLLVM_bpfel:
+ case ZigLLVM_bpfeb:
+ case ZigLLVM_le64:
+ case ZigLLVM_mips64:
+ case ZigLLVM_mips64el:
+ case ZigLLVM_nvptx64:
+ case ZigLLVM_ppc64:
+ case ZigLLVM_ppc64le:
+ case ZigLLVM_riscv64:
+ case ZigLLVM_sparcv9:
+ case ZigLLVM_systemz:
+ case ZigLLVM_amdil64:
+ case ZigLLVM_hsail64:
+ case ZigLLVM_spir64:
+ case ZigLLVM_wasm64:
+ case ZigLLVM_renderscript64:
+ return 64;
+
+ case ZigLLVM_x86_64:
+ return 128;
+ }
+ zig_unreachable();
+}
+
uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
switch (target->os) {
case OsFreestanding:
@@ -1693,3 +1758,4 @@ bool target_supports_libunwind(const ZigTarget *target) {
}
return true;
}
+
diff --git a/src/target.hpp b/src/target.hpp
index fcda9955b978eff6bd442b783f9b4127acd0f80e..985a4c11b4d1bde35c90723e51a496a33188afb8 100644
--- a/src/target.hpp
+++ b/src/target.hpp
@@ -192,6 +192,7 @@ const char *target_arch_musl_name(ZigLLVM_ArchType arch);
bool target_supports_libunwind(const ZigTarget *target);
uint32_t target_arch_pointer_bit_width(ZigLLVM_ArchType arch);
+uint32_t target_arch_largest_atomic_bits(ZigLLVM_ArchType arch);
size_t target_libc_count(void);
void target_libc_enum(size_t index, ZigTarget *out_target);
diff --git a/test/stage1/behavior/atomics.zig b/test/stage1/behavior/atomics.zig
index daa463fd451df90e7d2cd2e85077fce536ac500d..3d1caaaa15f70bbb694a9dd8f6614441cb287856 100644
--- a/test/stage1/behavior/atomics.zig
+++ b/test/stage1/behavior/atomics.zig
@@ -69,3 +69,23 @@ test "cmpxchg with ptr" {
expect(@cmpxchgStrong(*i32, &x, &data3, &data2, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
expect(x == &data2);
}
+
+test "128-bit cmpxchg" {
+ if (builtin.arch != .x86_64) {
+ return error.SkipZigTest;
+ }
+ var x: u128 align(16) = 1234; // TODO: https://github.com/ziglang/zig/issues/2987
+ if (@cmpxchgWeak(u128, &x, 99, 5678, .SeqCst, .SeqCst)) |x1| {
+ expect(x1 == 1234);
+ } else {
+ @panic("cmpxchg should have failed");
+ }
+
+ while (@cmpxchgWeak(u128, &x, 1234, 5678, .SeqCst, .SeqCst)) |x1| {
+ expect(x1 == 1234);
+ }
+ expect(x == 5678);
+
+ expect(@cmpxchgStrong(u128, &x, 5678, 42, .SeqCst, .SeqCst) == null);
+ expect(x == 42);
+}
--
2.54.0
From 6cb4cac5cd1c68f41c62a3c23b09513988337c8d Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 1 Aug 2019 03:36:03 -0400
Subject: [PATCH 36/47] disable behavior test for 128-bit cmpxchg
once #2883 is done this can be revisited
---
test/stage1/behavior/atomics.zig | 39 ++++++++++++++++----------------
1 file changed, 20 insertions(+), 19 deletions(-)
diff --git a/test/stage1/behavior/atomics.zig b/test/stage1/behavior/atomics.zig
index 3d1caaaa15f70bbb694a9dd8f6614441cb287856..a97467e416b7b282667e42162ae7b8fa93846037 100644
--- a/test/stage1/behavior/atomics.zig
+++ b/test/stage1/behavior/atomics.zig
@@ -70,22 +70,23 @@ test "cmpxchg with ptr" {
expect(x == &data2);
}
-test "128-bit cmpxchg" {
- if (builtin.arch != .x86_64) {
- return error.SkipZigTest;
- }
- var x: u128 align(16) = 1234; // TODO: https://github.com/ziglang/zig/issues/2987
- if (@cmpxchgWeak(u128, &x, 99, 5678, .SeqCst, .SeqCst)) |x1| {
- expect(x1 == 1234);
- } else {
- @panic("cmpxchg should have failed");
- }
-
- while (@cmpxchgWeak(u128, &x, 1234, 5678, .SeqCst, .SeqCst)) |x1| {
- expect(x1 == 1234);
- }
- expect(x == 5678);
-
- expect(@cmpxchgStrong(u128, &x, 5678, 42, .SeqCst, .SeqCst) == null);
- expect(x == 42);
-}
+// TODO this test is disabled until this issue is resolved:
+// https://github.com/ziglang/zig/issues/2883
+// otherwise cross compiling will result in:
+// lld: error: undefined symbol: __sync_val_compare_and_swap_16
+//test "128-bit cmpxchg" {
+// var x: u128 align(16) = 1234; // TODO: https://github.com/ziglang/zig/issues/2987
+// if (@cmpxchgWeak(u128, &x, 99, 5678, .SeqCst, .SeqCst)) |x1| {
+// expect(x1 == 1234);
+// } else {
+// @panic("cmpxchg should have failed");
+// }
+//
+// while (@cmpxchgWeak(u128, &x, 1234, 5678, .SeqCst, .SeqCst)) |x1| {
+// expect(x1 == 1234);
+// }
+// expect(x == 5678);
+//
+// expect(@cmpxchgStrong(u128, &x, 5678, 42, .SeqCst, .SeqCst) == null);
+// expect(x == 42);
+//}
--
2.54.0
From c0c228b758150e017185dc280ef020ec3b7efdcf Mon Sep 17 00:00:00 2001
From: Euan Torano
Date: Fri, 2 Aug 2019 13:19:49 +0100
Subject: [PATCH 37/47] Check if /dev/urandom is a character device
---
std/os.zig | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/std/os.zig b/std/os.zig
index 9ff2e8f87f22a71d30d35ed834e70bc2e29e1a63..da1d71d6fcb204291d12dd99876a2fcd781e76e6 100644
--- a/std/os.zig
+++ b/std/os.zig
@@ -133,6 +133,11 @@ fn getRandomBytesDevURandom(buf: []u8) !void {
const fd = try openC(c"/dev/urandom", O_RDONLY | O_CLOEXEC, 0);
defer close(fd);
+ const st = try fstat(fd);
+ if (!S_ISCHR(st.mode)) {
+ return OpenError.Unexpected;
+ }
+
const stream = &std.fs.File.openHandle(fd).inStream().stream;
stream.readNoEof(buf) catch return error.Unexpected;
}
--
2.54.0
From 1583efda69622b9c7809419a4320f4e8ea6fd4e3 Mon Sep 17 00:00:00 2001
From: Euan Torano
Date: Fri, 2 Aug 2019 15:44:58 +0100
Subject: [PATCH 38/47] Fix call to S_ISCHR and implement for Mac
---
std/os.zig | 4 ++--
std/os/bits/darwin.zig | 50 ++++++++++++++++++++++++++++++++++++++++++
std/os/darwin.zig | 1 +
3 files changed, 53 insertions(+), 2 deletions(-)
diff --git a/std/os.zig b/std/os.zig
index da1d71d6fcb204291d12dd99876a2fcd781e76e6..ce240bb95646a3068dc6003461669a6f406d2865 100644
--- a/std/os.zig
+++ b/std/os.zig
@@ -134,8 +134,8 @@ fn getRandomBytesDevURandom(buf: []u8) !void {
defer close(fd);
const st = try fstat(fd);
- if (!S_ISCHR(st.mode)) {
- return OpenError.Unexpected;
+ if (!system.S_ISCHR(st.mode)) {
+ return error.Unexpected;
}
const stream = &std.fs.File.openHandle(fd).inStream().stream;
diff --git a/std/os/bits/darwin.zig b/std/os/bits/darwin.zig
index b8d229dbe95f17c0b37f86362de9001173844130..dd4d46287e61dedf704c91398178eedf9b08ebe4 100644
--- a/std/os/bits/darwin.zig
+++ b/std/os/bits/darwin.zig
@@ -1116,3 +1116,53 @@ pub const stack_t = extern struct {
ss_size: isize,
ss_flags: i32,
};
+
+pub const S_IFMT = 0o170000;
+
+pub const S_IFIFO = 0o010000;
+pub const S_IFCHR = 0o020000;
+pub const S_IFDIR = 0o040000;
+pub const S_IFBLK = 0o060000;
+pub const S_IFREG = 0o100000;
+pub const S_IFLNK = 0o120000;
+pub const S_IFSOCK = 0o140000;
+pub const S_IFWHT = 0o160000;
+
+pub const S_ISUID = 0o4000;
+pub const S_ISGID = 0o2000;
+pub const S_ISVTX = 0o1000;
+pub const S_IRUSR = 0o400;
+pub const S_IWUSR = 0o200;
+pub const S_IXUSR = 0o100;
+
+pub fn S_ISFIFO(m: u32) bool {
+ return m & S_IFMT == S_IFIFO;
+}
+
+pub fn S_ISCHR(m: u32) bool {
+ return m & S_IFMT == S_IFCHR;
+}
+
+pub fn S_ISDIR(m: u32) bool {
+ return m & S_IFMT == S_IFDIR;
+}
+
+pub fn S_ISBLK(m: u32) bool {
+ return m & S_IFMT == S_IFBLK;
+}
+
+pub fn S_ISREG(m: u32) bool {
+ return m & S_IFMT == S_IFREG;
+}
+
+pub fn S_ISLNK(m: u32) bool {
+ return m & S_IFMT == S_IFLNK;
+}
+
+pub fn S_ISSOCK(m: u32) bool {
+ return m & S_IFMT == S_IFSOCK;
+}
+
+pub fn S_IWHT(m: u32) bool {
+ return m & S_IFMT == S_IFWHT;
+}
diff --git a/std/os/darwin.zig b/std/os/darwin.zig
index 67ce9a06cff54ead18902b8f3e69611128130466..c2b6801e22fa6cc6dc2a1ccce3b97631f62b0031 100644
--- a/std/os/darwin.zig
+++ b/std/os/darwin.zig
@@ -5,3 +5,4 @@ pub const is_the_target = switch (builtin.os) {
else => false,
};
pub usingnamespace std.c;
+pub usingnamespace @import("bits.zig");
\ No newline at end of file
--
2.54.0
From 24fbd1f1d58125f34ca2ae52a592028f39412aa9 Mon Sep 17 00:00:00 2001
From: Euan Torano
Date: Fri, 2 Aug 2019 15:59:40 +0100
Subject: [PATCH 39/47] Add S_* values for freebsd.
---
std/os/bits/darwin.zig | 9 +++++++
std/os/bits/freebsd.zig | 59 +++++++++++++++++++++++++++++++++++++++++
std/os/freebsd.zig | 1 +
3 files changed, 69 insertions(+)
diff --git a/std/os/bits/darwin.zig b/std/os/bits/darwin.zig
index dd4d46287e61dedf704c91398178eedf9b08ebe4..483d4cda908f157d9a585339ee07cfaa7b6ad9b0 100644
--- a/std/os/bits/darwin.zig
+++ b/std/os/bits/darwin.zig
@@ -1131,9 +1131,18 @@ pub const S_IFWHT = 0o160000;
pub const S_ISUID = 0o4000;
pub const S_ISGID = 0o2000;
pub const S_ISVTX = 0o1000;
+pub const S_IRWXU = 0o700;
pub const S_IRUSR = 0o400;
pub const S_IWUSR = 0o200;
pub const S_IXUSR = 0o100;
+pub const S_IRWXG = 0o070;
+pub const S_IRGRP = 0o040;
+pub const S_IWGRP = 0o020;
+pub const S_IXGRP = 0o010;
+pub const S_IRWXO = 0o007;
+pub const S_IROTH = 0o004;
+pub const S_IWOTH = 0o002;
+pub const S_IXOTH = 0o001;
pub fn S_ISFIFO(m: u32) bool {
return m & S_IFMT == S_IFIFO;
diff --git a/std/os/bits/freebsd.zig b/std/os/bits/freebsd.zig
index 198857983e67a837657081c39edbad953a3f8d1c..45432a6c076d82ac2845651a70e0f10ce89d8408 100644
--- a/std/os/bits/freebsd.zig
+++ b/std/os/bits/freebsd.zig
@@ -876,3 +876,62 @@ pub const stack_t = extern struct {
ss_size: isize,
ss_flags: i32,
};
+
+pub const S_IFMT = 0o170000;
+
+pub const S_IFIFO = 0o010000;
+pub const S_IFCHR = 0o020000;
+pub const S_IFDIR = 0o040000;
+pub const S_IFBLK = 0o060000;
+pub const S_IFREG = 0o100000;
+pub const S_IFLNK = 0o120000;
+pub const S_IFSOCK = 0o140000;
+pub const S_IFWHT = 0o160000;
+
+pub const S_ISUID = 0o4000;
+pub const S_ISGID = 0o2000;
+pub const S_ISVTX = 0o1000;
+pub const S_IRWXU = 0o700;
+pub const S_IRUSR = 0o400;
+pub const S_IWUSR = 0o200;
+pub const S_IXUSR = 0o100;
+pub const S_IRWXG = 0o070;
+pub const S_IRGRP = 0o040;
+pub const S_IWGRP = 0o020;
+pub const S_IXGRP = 0o010;
+pub const S_IRWXO = 0o007;
+pub const S_IROTH = 0o004;
+pub const S_IWOTH = 0o002;
+pub const S_IXOTH = 0o001;
+
+pub fn S_ISFIFO(m: u32) bool {
+ return m & S_IFMT == S_IFIFO;
+}
+
+pub fn S_ISCHR(m: u32) bool {
+ return m & S_IFMT == S_IFCHR;
+}
+
+pub fn S_ISDIR(m: u32) bool {
+ return m & S_IFMT == S_IFDIR;
+}
+
+pub fn S_ISBLK(m: u32) bool {
+ return m & S_IFMT == S_IFBLK;
+}
+
+pub fn S_ISREG(m: u32) bool {
+ return m & S_IFMT == S_IFREG;
+}
+
+pub fn S_ISLNK(m: u32) bool {
+ return m & S_IFMT == S_IFLNK;
+}
+
+pub fn S_ISSOCK(m: u32) bool {
+ return m & S_IFMT == S_IFSOCK;
+}
+
+pub fn S_IWHT(m: u32) bool {
+ return m & S_IFMT == S_IFWHT;
+}
diff --git a/std/os/freebsd.zig b/std/os/freebsd.zig
index d418ccd415b8bf97788e6128ddb56943048479ef..e9efe6492060895796bc897b9eb62f38ff335847 100644
--- a/std/os/freebsd.zig
+++ b/std/os/freebsd.zig
@@ -2,3 +2,4 @@ const std = @import("../std.zig");
const builtin = @import("builtin");
pub const is_the_target = builtin.os == .freebsd;
pub usingnamespace std.c;
+pub usingnamespace @import("bits.zig");
\ No newline at end of file
--
2.54.0
From a5cb0f77d11bdcc504fe3e6afa928c88de821518 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 2 Aug 2019 13:54:58 -0400
Subject: [PATCH 40/47] assignment participates in result location
fix one regression with optionals but there are more
---
src/ir.cpp | 21 +++++++++++++++------
test/stage1/behavior/eval.zig | 10 ++++++++++
2 files changed, 25 insertions(+), 6 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index f34c840496e30180ddf4873b16df4c1761ee1edf..8a46fec7c94ace7f310b5ba579522d4c0b456b33 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -4001,12 +4001,20 @@ static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *no
static IrInstruction *ir_gen_assign(IrBuilder *irb, Scope *scope, AstNode *node) {
IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValPtr, nullptr);
- IrInstruction *rvalue = ir_gen_node(irb, node->data.bin_op_expr.op2, scope);
+ if (lvalue == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
+
+ ResultLocInstruction *result_loc_inst = allocate(1);
+ result_loc_inst->base.id = ResultLocIdInstruction;
+ result_loc_inst->base.source_instruction = lvalue;
+ ir_ref_instruction(lvalue, irb->current_basic_block);
+ ir_build_reset_result(irb, scope, node, &result_loc_inst->base);
- if (lvalue == irb->codegen->invalid_instruction || rvalue == irb->codegen->invalid_instruction)
+ IrInstruction *rvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op2, scope, LValNone,
+ &result_loc_inst->base);
+ if (rvalue == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- ir_build_store_ptr(irb, scope, node, lvalue, rvalue);
return ir_build_const_void(irb, scope, node);
}
@@ -17477,6 +17485,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
return result;
} else if (is_slice(array_type)) {
ConstExprValue *ptr_field = &array_ptr_val->data.x_struct.fields[slice_ptr_index];
+ ir_assert(ptr_field != nullptr, &elem_ptr_instruction->base);
if (ptr_field->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
IrInstruction *result = ir_build_elem_ptr(&ira->new_irb, elem_ptr_instruction->base.scope,
elem_ptr_instruction->base.source_node, array_ptr, casted_elem_index, false,
@@ -17663,7 +17672,7 @@ static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction
return ira->codegen->invalid_instruction;
if (type_is_invalid(struct_val->type))
return ira->codegen->invalid_instruction;
- if (struct_val->special == ConstValSpecialUndef && initializing) {
+ if (initializing && struct_val->special == ConstValSpecialUndef) {
struct_val->data.x_struct.fields = create_const_vals(struct_type->data.structure.src_field_count);
struct_val->special = ConstValSpecialStatic;
for (size_t i = 0; i < struct_type->data.structure.src_field_count; i += 1) {
@@ -18764,7 +18773,7 @@ static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstr
if (optional_val == nullptr)
return ira->codegen->invalid_instruction;
- if (initializing && optional_val->special == ConstValSpecialUndef) {
+ if (initializing) {
switch (type_has_one_possible_value(ira->codegen, child_type)) {
case OnePossibleValueInvalid:
return ira->codegen->invalid_instruction;
@@ -23260,7 +23269,7 @@ static IrInstruction *ir_analyze_unwrap_error_payload(IrAnalyze *ira, IrInstruct
ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_instr->source_node);
if (err_union_val == nullptr)
return ira->codegen->invalid_instruction;
- if (err_union_val->special == ConstValSpecialUndef && initializing) {
+ if (initializing && err_union_val->special == ConstValSpecialUndef) {
ConstExprValue *vals = create_const_vals(2);
ConstExprValue *err_set_val = &vals[0];
ConstExprValue *payload_val = &vals[1];
diff --git a/test/stage1/behavior/eval.zig b/test/stage1/behavior/eval.zig
index 97d3a269cc385ccbbcf622d15e42fc4e2aa4fb57..58d662d76879cd71053ec02cda56927225da7544 100644
--- a/test/stage1/behavior/eval.zig
+++ b/test/stage1/behavior/eval.zig
@@ -1,5 +1,6 @@
const std = @import("std");
const expect = std.testing.expect;
+const expectEqual = std.testing.expectEqual;
const builtin = @import("builtin");
test "compile time recursion" {
@@ -794,3 +795,12 @@ test "no undeclared identifier error in unanalyzed branches" {
lol_this_doesnt_exist = nonsense;
}
}
+
+test "comptime assign int to optional int" {
+ comptime {
+ var x: ?i32 = null;
+ x = 2;
+ x.? *= 10;
+ expectEqual(20, x.?);
+ }
+}
--
2.54.0
From 90e64bc620edc3f3c3a2c16d01b7ca2eefc02429 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 2 Aug 2019 14:47:26 -0400
Subject: [PATCH 41/47] fix cmpxchg with discarded result
---
src/codegen.cpp | 8 +++++++-
test/stage1/behavior/atomics.zig | 10 ++++++++++
2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 0ac945e8c21bd375de4fc4e82dcd13e5859d5954..ef24716dff4149382be8ad70199a5b2da37d9ada 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -4458,8 +4458,14 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn
return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(get_llvm_type(g, child_type)), payload_val, "");
}
+ // When the cmpxchg is discarded, the result location will have no bits.
+ if (!type_has_bits(instruction->result_loc->value.type)) {
+ return nullptr;
+ }
+
LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc);
- assert(type_has_bits(child_type));
+ src_assert(result_loc != nullptr, instruction->base.source_node);
+ src_assert(type_has_bits(child_type), instruction->base.source_node);
LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, result_loc, maybe_child_index, "");
diff --git a/test/stage1/behavior/atomics.zig b/test/stage1/behavior/atomics.zig
index a97467e416b7b282667e42162ae7b8fa93846037..1a941cf21c133a37da81d1d723fe20dc1c314461 100644
--- a/test/stage1/behavior/atomics.zig
+++ b/test/stage1/behavior/atomics.zig
@@ -1,5 +1,6 @@
const std = @import("std");
const expect = std.testing.expect;
+const expectEqual = std.testing.expectEqual;
const builtin = @import("builtin");
const AtomicRmwOp = builtin.AtomicRmwOp;
const AtomicOrder = builtin.AtomicOrder;
@@ -90,3 +91,12 @@ test "cmpxchg with ptr" {
// expect(@cmpxchgStrong(u128, &x, 5678, 42, .SeqCst, .SeqCst) == null);
// expect(x == 42);
//}
+
+test "cmpxchg with ignored result" {
+ var x: i32 = 1234;
+ var ptr = &x;
+
+ _ = @cmpxchgStrong(i32, &x, 1234, 5678, .Monotonic, .Monotonic);
+
+ expectEqual(i32(5678), x);
+}
--
2.54.0
From 9069ee957cb8c9069028b325af5b862bbf8f66af Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 2 Aug 2019 15:17:02 -0400
Subject: [PATCH 42/47] fix discarding function call results
---
src/ir.cpp | 65 ++++++++++++++++++++++---------------
test/stage1/behavior/fn.zig | 19 +++++++++++
2 files changed, 58 insertions(+), 26 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 8a46fec7c94ace7f310b5ba579522d4c0b456b33..de2e4e1654127256fe7133a16c843835201e1a66 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -189,7 +189,8 @@ static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_
static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspend_source_instr,
ResultLoc *result_loc, ZigType *value_type, IrInstruction *value, bool force_runtime, bool non_null_comptime);
static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_source_instr,
- ResultLoc *result_loc, ZigType *value_type, IrInstruction *value, bool force_runtime, bool non_null_comptime);
+ ResultLoc *result_loc, ZigType *value_type, IrInstruction *value, bool force_runtime,
+ bool non_null_comptime, bool allow_discard);
static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr,
IrInstruction *base_ptr, bool safety_check_on, bool initializing);
static IrInstruction *ir_analyze_unwrap_error_payload(IrAnalyze *ira, IrInstruction *source_instr,
@@ -11163,7 +11164,8 @@ static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruc
}
if (result_loc == nullptr) result_loc = no_result_loc();
- IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false);
+ IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true,
+ false, true);
if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) {
return result_loc_inst;
}
@@ -11623,7 +11625,7 @@ static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *so
}
IrInstruction *result_loc_inst = nullptr;
if (result_loc != nullptr) {
- result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false);
+ result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false, true);
if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) {
return result_loc_inst;
}
@@ -11666,7 +11668,7 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction
IrInstruction *result_loc_inst;
if (handle_is_ptr(wanted_type)) {
if (result_loc == nullptr) result_loc = no_result_loc();
- result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false);
+ result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false, true);
if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) {
return result_loc_inst;
}
@@ -11751,7 +11753,7 @@ static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *so
IrInstruction *result_loc_inst;
if (handle_is_ptr(wanted_type)) {
if (result_loc == nullptr) result_loc = no_result_loc();
- result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false);
+ result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false, true);
if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) {
return result_loc_inst;
}
@@ -11824,7 +11826,8 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi
IrInstruction *result_loc;
if (type_has_bits(ptr_type) && !handle_is_ptr(value->value.type)) {
- result_loc = ir_resolve_result(ira, source_instruction, no_result_loc(), value->value.type, nullptr, true, false);
+ result_loc = ir_resolve_result(ira, source_instruction, no_result_loc(), value->value.type, nullptr, true,
+ false, true);
} else {
result_loc = nullptr;
}
@@ -11868,7 +11871,8 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
if (!array_ptr) array_ptr = ir_get_ref(ira, source_instr, array, true, false);
if (result_loc == nullptr) result_loc = no_result_loc();
- IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false);
+ IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr,
+ true, false, true);
if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) {
return result_loc_inst;
}
@@ -12524,7 +12528,8 @@ static IrInstruction *ir_analyze_vector_to_array(IrAnalyze *ira, IrInstruction *
if (result_loc == nullptr) {
result_loc = no_result_loc();
}
- IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, array_type, nullptr, true, false);
+ IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, array_type, nullptr,
+ true, false, true);
if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) {
return result_loc_inst;
}
@@ -13105,7 +13110,8 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
IrInstruction *result_loc_inst;
if (type_entry->data.pointer.host_int_bytes != 0 && handle_is_ptr(child_type)) {
if (result_loc == nullptr) result_loc = no_result_loc();
- result_loc_inst = ir_resolve_result(ira, source_instruction, result_loc, child_type, nullptr, true, false);
+ result_loc_inst = ir_resolve_result(ira, source_instruction, result_loc, child_type, nullptr,
+ true, false, true);
if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) {
return result_loc_inst;
}
@@ -15360,7 +15366,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
if (peer_parent->peers.length == 1) {
IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, peer_parent->parent,
- value_type, value, force_runtime, non_null_comptime);
+ value_type, value, force_runtime, non_null_comptime, true);
result_peer->suspend_pos.basic_block_index = SIZE_MAX;
result_peer->suspend_pos.instruction_index = SIZE_MAX;
if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) ||
@@ -15380,7 +15386,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
if (peer_parent->skipped) {
if (non_null_comptime) {
return ir_resolve_result(ira, suspend_source_instr, peer_parent->parent,
- value_type, value, force_runtime, non_null_comptime);
+ value_type, value, force_runtime, non_null_comptime, true);
}
return nullptr;
}
@@ -15398,7 +15404,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
}
IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, peer_parent->parent,
- peer_parent->resolved_type, nullptr, force_runtime, non_null_comptime);
+ peer_parent->resolved_type, nullptr, force_runtime, non_null_comptime, true);
if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) ||
parent_result_loc->value.type->id == ZigTypeIdUnreachable)
{
@@ -15448,7 +15454,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
}
IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, result_bit_cast->parent,
- dest_type, bitcasted_value, force_runtime, non_null_comptime);
+ dest_type, bitcasted_value, force_runtime, non_null_comptime, true);
if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) ||
parent_result_loc->value.type->id == ZigTypeIdUnreachable)
{
@@ -15477,8 +15483,15 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_source_instr,
ResultLoc *result_loc_pass1, ZigType *value_type, IrInstruction *value, bool force_runtime,
- bool non_null_comptime)
+ bool non_null_comptime, bool allow_discard)
{
+ if (!allow_discard && result_loc_pass1->id == ResultLocIdInstruction &&
+ instr_is_comptime(result_loc_pass1->source_instruction) &&
+ result_loc_pass1->source_instruction->value.type->id == ZigTypeIdPointer &&
+ result_loc_pass1->source_instruction->value.data.x_ptr.special == ConstPtrSpecialDiscard)
+ {
+ result_loc_pass1 = no_result_loc();
+ }
IrInstruction *result_loc = ir_resolve_result_raw(ira, suspend_source_instr, result_loc_pass1, value_type,
value, force_runtime, non_null_comptime);
if (result_loc == nullptr || (instr_is_unreachable(result_loc) || type_is_invalid(result_loc->value.type)))
@@ -15533,7 +15546,7 @@ static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrIn
if (type_is_invalid(implicit_elem_type))
return ira->codegen->invalid_instruction;
IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc,
- implicit_elem_type, nullptr, false, true);
+ implicit_elem_type, nullptr, false, true, true);
if (result_loc != nullptr)
return result_loc;
@@ -15542,7 +15555,7 @@ static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrIn
instruction->result_loc->id == ResultLocIdReturn)
{
result_loc = ir_resolve_result(ira, &instruction->base, no_result_loc(),
- implicit_elem_type, nullptr, false, true);
+ implicit_elem_type, nullptr, false, true, true);
if (result_loc != nullptr &&
(type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)))
{
@@ -15631,7 +15644,7 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc
ZigType *async_return_type = get_error_union_type(ira->codegen, alloc_fn_error_set_type, promise_type);
IrInstruction *result_loc = ir_resolve_result(ira, &call_instruction->base, no_result_loc(),
- async_return_type, nullptr, true, true);
+ async_return_type, nullptr, true, true, false);
if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) {
return result_loc;
}
@@ -16390,7 +16403,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
IrInstruction *result_loc;
if (handle_is_ptr(impl_fn_type_id->return_type)) {
result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc,
- impl_fn_type_id->return_type, nullptr, true, true);
+ impl_fn_type_id->return_type, nullptr, true, true, false);
if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) ||
instr_is_unreachable(result_loc)))
{
@@ -16512,7 +16525,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
IrInstruction *result_loc;
if (handle_is_ptr(return_type)) {
result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc,
- return_type, nullptr, true, true);
+ return_type, nullptr, true, true, false);
if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) {
return result_loc;
}
@@ -17028,7 +17041,7 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh
// In case resolving the parent activates a suspend, do it now
IrInstruction *parent_result_loc = ir_resolve_result(ira, &phi_instruction->base, peer_parent->parent,
- peer_parent->resolved_type, nullptr, false, false);
+ peer_parent->resolved_type, nullptr, false, false, true);
if (parent_result_loc != nullptr &&
(type_is_invalid(parent_result_loc->value.type) || instr_is_unreachable(parent_result_loc)))
{
@@ -21541,7 +21554,7 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi
IrInstruction *result_loc;
if (handle_is_ptr(result_type)) {
result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc,
- result_type, nullptr, true, false);
+ result_type, nullptr, true, false, true);
if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) {
return result_loc;
}
@@ -21798,7 +21811,7 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru
}
IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc,
- dest_slice_type, nullptr, true, false);
+ dest_slice_type, nullptr, true, false, true);
if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) {
return result_loc;
}
@@ -21875,7 +21888,7 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct
}
IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc,
- dest_slice_type, nullptr, true, false);
+ dest_slice_type, nullptr, true, false, true);
if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) {
return result_loc;
}
@@ -22617,7 +22630,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
}
IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc,
- return_type, nullptr, true, false);
+ return_type, nullptr, true, false, true);
if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) {
return result_loc;
}
@@ -25397,7 +25410,7 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct
bool was_written = instruction->result_loc->written;
IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc,
- value->value.type, value, false, false);
+ value->value.type, value, false, false, true);
if (result_loc != nullptr) {
if (type_is_invalid(result_loc->value.type))
return ira->codegen->invalid_instruction;
@@ -25429,7 +25442,7 @@ static IrInstruction *ir_analyze_instruction_bit_cast_src(IrAnalyze *ira, IrInst
return operand;
IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base,
- &instruction->result_loc_bit_cast->base, operand->value.type, operand, false, false);
+ &instruction->result_loc_bit_cast->base, operand->value.type, operand, false, false, true);
if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)))
return result_loc;
diff --git a/test/stage1/behavior/fn.zig b/test/stage1/behavior/fn.zig
index d6d670b09b4dda4132e85160302039e54a3eb584..6b9c8b8fe7fc2f4d5540291e29876e3b1879eb08 100644
--- a/test/stage1/behavior/fn.zig
+++ b/test/stage1/behavior/fn.zig
@@ -228,3 +228,22 @@ test "implicit cast fn call result to optional in field result" {
S.entry();
comptime S.entry();
}
+
+test "discard the result of a function that returns a struct" {
+ const S = struct {
+ fn entry() void {
+ _ = func();
+ }
+
+ fn func() Foo {
+ return undefined;
+ }
+
+ const Foo = struct {
+ a: u64,
+ b: u64,
+ };
+ };
+ S.entry();
+ comptime S.entry();
+}
--
2.54.0
From d105769926fd5360a5309be3e202cc65d32ce604 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 2 Aug 2019 16:09:40 -0400
Subject: [PATCH 43/47] fix regressions regarding writing through const
pointers
---
src/all_types.hpp | 2 ++
src/ir.cpp | 34 ++++++++++++++++++----------------
test/compile_errors.zig | 16 ++++++++--------
3 files changed, 28 insertions(+), 24 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index a6b2bc51c3e727b2286d11adda163eff83bc13ee..4c3aeade9e00aec9660ca521ed29155ad0bfc1bc 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -2543,6 +2543,7 @@ struct IrInstructionLoadPtrGen {
struct IrInstructionStorePtr {
IrInstruction base;
+ bool allow_write_through_const;
IrInstruction *ptr;
IrInstruction *value;
};
@@ -3707,6 +3708,7 @@ enum ResultLocId {
struct ResultLoc {
ResultLocId id;
bool written;
+ bool allow_write_through_const;
IrInstruction *resolved_loc; // result ptr
IrInstruction *source_instruction;
IrInstruction *gen_instruction; // value to store to the result loc
diff --git a/src/ir.cpp b/src/ir.cpp
index de2e4e1654127256fe7133a16c843835201e1a66..65a21a418d899c047b26f6a3de733779f6535106 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -198,7 +198,7 @@ static IrInstruction *ir_analyze_unwrap_error_payload(IrAnalyze *ira, IrInstruct
static IrInstruction *ir_analyze_unwrap_err_code(IrAnalyze *ira, IrInstruction *source_instr,
IrInstruction *base_ptr, bool initializing);
static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
- IrInstruction *ptr, IrInstruction *uncasted_value);
+ IrInstruction *ptr, IrInstruction *uncasted_value, bool allow_write_through_const);
static IrInstruction *ir_gen_union_init_expr(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *union_type, IrInstruction *field_name, AstNode *expr_node,
LVal lval, ResultLoc *parent_result_loc);
@@ -1613,7 +1613,7 @@ static IrInstruction *ir_build_unreachable(IrBuilder *irb, Scope *scope, AstNode
return &unreachable_instruction->base;
}
-static IrInstruction *ir_build_store_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
+static IrInstructionStorePtr *ir_build_store_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *ptr, IrInstruction *value)
{
IrInstructionStorePtr *instruction = ir_build_instruction(irb, scope, source_node);
@@ -1625,7 +1625,7 @@ static IrInstruction *ir_build_store_ptr(IrBuilder *irb, Scope *scope, AstNode *
ir_ref_instruction(ptr, irb->current_basic_block);
ir_ref_instruction(value, irb->current_basic_block);
- return &instruction->base;
+ return instruction;
}
static IrInstruction *ir_build_var_decl_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
@@ -6051,6 +6051,7 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A
ResultLocInstruction *result_loc_inst = allocate(1);
result_loc_inst->base.id = ResultLocIdInstruction;
result_loc_inst->base.source_instruction = field_ptr;
+ result_loc_inst->base.allow_write_through_const = true;
ir_ref_instruction(field_ptr, irb->current_basic_block);
ir_build_reset_result(irb, scope, expr_node, &result_loc_inst->base);
@@ -6089,6 +6090,7 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A
ResultLocInstruction *result_loc_inst = allocate(1);
result_loc_inst->base.id = ResultLocIdInstruction;
result_loc_inst->base.source_instruction = elem_ptr;
+ result_loc_inst->base.allow_write_through_const = true;
ir_ref_instruction(elem_ptr, irb->current_basic_block);
ir_build_reset_result(irb, scope, expr_node, &result_loc_inst->base);
@@ -6646,7 +6648,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
ir_set_cursor_at_end_and_append_block(irb, continue_block);
IrInstruction *new_index_val = ir_build_bin_op(irb, child_scope, node, IrBinOpAdd, index_val, one, false);
- ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, index_ptr, new_index_val));
+ ir_build_store_ptr(irb, child_scope, node, index_ptr, new_index_val)->allow_write_through_const = true;
ir_build_br(irb, child_scope, node, cond_block, is_comptime);
IrInstruction *else_result = nullptr;
@@ -14848,7 +14850,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
// instruction.
assert(deref->value.special != ConstValSpecialRuntime);
var_ptr->value.special = ConstValSpecialRuntime;
- ir_analyze_store_ptr(ira, var_ptr, var_ptr, deref);
+ ir_analyze_store_ptr(ira, var_ptr, var_ptr, deref, false);
}
if (var_ptr->value.special == ConstValSpecialStatic && var->mem_slot_index != SIZE_MAX) {
@@ -15862,7 +15864,7 @@ no_mem_slot:
}
static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
- IrInstruction *ptr, IrInstruction *uncasted_value)
+ IrInstruction *ptr, IrInstruction *uncasted_value, bool allow_write_through_const)
{
assert(ptr->value.type->id == ZigTypeIdPointer);
@@ -15878,7 +15880,7 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
ZigType *child_type = ptr->value.type->data.pointer.child_type;
- if (ptr->value.type->data.pointer.is_const && !source_instr->is_gen) {
+ if (ptr->value.type->data.pointer.is_const && !allow_write_through_const) {
ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
return ira->codegen->invalid_instruction;
}
@@ -15957,10 +15959,9 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
break;
}
- IrInstruction *result = ir_build_store_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node,
- ptr, value);
- result->value.type = ira->codegen->builtin_types.entry_void;
- return result;
+ IrInstructionStorePtr *store_ptr = ir_build_store_ptr(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, ptr, value);
+ return &store_ptr->base;
}
static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction,
@@ -18283,7 +18284,7 @@ static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstruc
if (type_is_invalid(value->value.type))
return ira->codegen->invalid_instruction;
- return ir_analyze_store_ptr(ira, &instruction->base, ptr, value);
+ return ir_analyze_store_ptr(ira, &instruction->base, ptr, value, instruction->allow_write_through_const);
}
static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *instruction) {
@@ -19691,7 +19692,7 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
IrInstruction *field_ptr = ir_analyze_struct_field_ptr(ira, instruction, field, result_loc,
container_type, true);
- ir_analyze_store_ptr(ira, instruction, field_ptr, runtime_inst);
+ ir_analyze_store_ptr(ira, instruction, field_ptr, runtime_inst, false);
if (instr_is_comptime(field_ptr) && field_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) {
const_ptrs.append(field_ptr);
} else {
@@ -19708,7 +19709,7 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
IrInstruction *field_result_loc = const_ptrs.at(i);
IrInstruction *deref = ir_get_deref(ira, field_result_loc, field_result_loc, nullptr);
field_result_loc->value.special = ConstValSpecialRuntime;
- ir_analyze_store_ptr(ira, field_result_loc, field_result_loc, deref);
+ ir_analyze_store_ptr(ira, field_result_loc, field_result_loc, deref, false);
}
}
}
@@ -19835,7 +19836,7 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira,
assert(elem_result_loc->value.special == ConstValSpecialStatic);
IrInstruction *deref = ir_get_deref(ira, elem_result_loc, elem_result_loc, nullptr);
elem_result_loc->value.special = ConstValSpecialRuntime;
- ir_analyze_store_ptr(ira, elem_result_loc, elem_result_loc, deref);
+ ir_analyze_store_ptr(ira, elem_result_loc, elem_result_loc, deref, false);
}
}
}
@@ -25418,7 +25419,8 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct
return result_loc;
if (!was_written) {
- IrInstruction *store_ptr = ir_analyze_store_ptr(ira, &instruction->base, result_loc, value);
+ IrInstruction *store_ptr = ir_analyze_store_ptr(ira, &instruction->base, result_loc, value,
+ instruction->result_loc->allow_write_through_const);
if (type_is_invalid(store_ptr->value.type)) {
return ira->codegen->invalid_instruction;
}
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 40ce8d304b91ff8aa4c21c7a15705c7ef59c760a..a4bc2a66f02d2fd975b0b1dacdb2774ac7af2bd5 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -201,7 +201,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return error.OutOfMemory;
\\}
,
- "tmp.zig:2:7: error: error is discarded",
+ "tmp.zig:2:12: error: error is discarded",
);
cases.add(
@@ -2740,7 +2740,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ 3 = 3;
\\}
,
- "tmp.zig:2:7: error: cannot assign to constant",
+ "tmp.zig:2:9: error: cannot assign to constant",
);
cases.add(
@@ -2750,7 +2750,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a = 4;
\\}
,
- "tmp.zig:3:7: error: cannot assign to constant",
+ "tmp.zig:3:9: error: cannot assign to constant",
);
cases.add(
@@ -2820,7 +2820,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\export fn entry() void { f(); }
,
- "tmp.zig:3:7: error: cannot assign to constant",
+ "tmp.zig:3:9: error: cannot assign to constant",
);
cases.add(
@@ -3883,7 +3883,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(a)); }
,
- "tmp.zig:6:24: error: unable to evaluate constant expression",
+ "tmp.zig:6:26: error: unable to evaluate constant expression",
"tmp.zig:4:17: note: called from here",
);
@@ -4133,7 +4133,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ cstr[0] = 'W';
\\}
,
- "tmp.zig:3:11: error: cannot assign to constant",
+ "tmp.zig:3:13: error: cannot assign to constant",
);
cases.add(
@@ -4143,7 +4143,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ cstr[0] = 'W';
\\}
,
- "tmp.zig:3:11: error: cannot assign to constant",
+ "tmp.zig:3:13: error: cannot assign to constant",
);
cases.add(
@@ -4291,7 +4291,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ f.field = 0;
\\}
,
- "tmp.zig:6:13: error: cannot assign to constant",
+ "tmp.zig:6:15: error: cannot assign to constant",
);
cases.add(
--
2.54.0
From e68fee39847712f9316628e6efe8daa8fc13a5a5 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 2 Aug 2019 18:53:56 -0400
Subject: [PATCH 44/47] docs: add atomicrmw operations list
---
doc/langref.html.in | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/doc/langref.html.in b/doc/langref.html.in
index b5fe464c35d7ad06062503eee9d63b2eaea600b9..ac381e00b28323619b42dd25ba11184d7628243c 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -6330,6 +6330,22 @@ comptime {
TODO right now bool is not accepted. Also I think we could make non powers of 2 work fine, maybe
we can remove this restriction
+
+ Supported operations:
+
+
+ - {#syntax#}.Xchg{#endsyntax#} - stores the operand unmodified.
+ - {#syntax#}.Add{#endsyntax#} - for integers, twos complement wraparound addition.
+ Also supports {#link|Floats#}.
+ - {#syntax#}.Sub{#endsyntax#} - for integers, twos complement wraparound subtraction.
+ Also supports {#link|Floats#}.
+ - {#syntax#}.And{#endsyntax#} - bitwise and
+ - {#syntax#}.Nand{#endsyntax#} - bitwise nand
+ - {#syntax#}.Or{#endsyntax#} - bitwise or
+ - {#syntax#}.Xor{#endsyntax#} - bitwise xor
+ - {#syntax#}.Max{#endsyntax#} - stores the operand if it is larger. Supports integers and floats.
+ - {#syntax#}.Min{#endsyntax#} - stores the operand if it is smaller. Supports integers and floats.
+
{#header_close#}
{#header_open|@bitCast#}
{#syntax#}@bitCast(comptime DestType: type, value: var) DestType{#endsyntax#}
--
2.54.0
From 57830e43ee79dd0ceafc96fdad6c52e73edf1420 Mon Sep 17 00:00:00 2001
From: Christoffer Rasmussen
Date: Wed, 31 Jul 2019 15:17:09 +0200
Subject: [PATCH 45/47] Fix public function lookup
Previously it did not work, as lookup did not pass a correct parent type
to doLookup. Expected *?*Node, got ?*Node.
---
std/rb.zig | 51 +++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 49 insertions(+), 2 deletions(-)
diff --git a/std/rb.zig b/std/rb.zig
index b5935a2eacbf2ce116cba1e403c5026e534c5061..0b84950544fe4defb9ba2994487c377803447f79 100644
--- a/std/rb.zig
+++ b/std/rb.zig
@@ -234,10 +234,13 @@ pub const Tree = struct {
return null;
}
+ /// lookup searches for the value of key, using binary search. It will
+ /// return a pointer to the node if it is there, otherwise it will return null.
+ /// Complexity guaranteed O(log n), where n is the number of nodes book-kept
+ /// by tree.
pub fn lookup(tree: *Tree, key: *Node) ?*Node {
- var parent: *Node = undefined;
+ var parent: ?*Node = undefined;
var is_left: bool = undefined;
-
return doLookup(key, tree, &parent, &is_left);
}
@@ -545,3 +548,47 @@ test "rb" {
num = testGetNumber(num.node.next().?);
}
}
+
+
+test "inserting and looking up" {
+ var tree: Tree = undefined;
+ tree.init(testCompare);
+ var number: testNumber = undefined;
+ number.value = 1000;
+ _ = tree.insert(&number.node);
+ var dup: testNumber = undefined;
+ //Assert that tuples with identical value fields finds the same pointer
+ dup.value = 1000;
+ assert(tree.lookup(&dup.node) == &number.node);
+ //Assert that tuples with identical values do not clobber when inserted.
+ _ = tree.insert(&dup.node);
+ assert(tree.lookup(&dup.node) == &number.node);
+ assert(tree.lookup(&number.node) != &dup.node);
+ assert(testGetNumber(tree.lookup(&dup.node).?).value == testGetNumber(&dup.node).value);
+ //Assert that if looking for a non-existing value, return null.
+ var non_existing_value: testNumber = undefined;
+ non_existing_value.value = 1234;
+ assert(tree.lookup(&non_existing_value.node) == null);
+}
+
+test "multiple inserts, followed by calling first and last" {
+ var tree: Tree = undefined;
+ tree.init(testCompare);
+ var zeroth: testNumber = undefined;
+ zeroth.value = 0;
+ var first: testNumber = undefined;
+ first.value = 1;
+ var second: testNumber = undefined;
+ second.value = 2;
+ var third: testNumber = undefined;
+ third.value = 3;
+ _ = tree.insert(&zeroth.node);
+ _ = tree.insert(&first.node);
+ _ = tree.insert(&second.node);
+ _ = tree.insert(&third.node);
+ assert(testGetNumber(tree.first().?).value == 0);
+ assert(testGetNumber(tree.last().?).value == 3);
+ var lookupNode: testNumber = undefined;
+ lookupNode.value = 3;
+ assert(tree.lookup(&lookupNode.node) == &third.node);
+}
--
2.54.0
From 8e157ccb23885b2a9a8a5d66c3955fc560fd0074 Mon Sep 17 00:00:00 2001
From: Euan T
Date: Sat, 3 Aug 2019 07:50:30 +0100
Subject: [PATCH 46/47] Update returned error return when not a character
device.
Co-Authored-By: Andrew Kelley
---
std/os.zig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/std/os.zig b/std/os.zig
index ce240bb95646a3068dc6003461669a6f406d2865..2caab634d66b4b495c9270cbcb3b5e38e234daee 100644
--- a/std/os.zig
+++ b/std/os.zig
@@ -135,7 +135,7 @@ fn getRandomBytesDevURandom(buf: []u8) !void {
const st = try fstat(fd);
if (!system.S_ISCHR(st.mode)) {
- return error.Unexpected;
+ return error.NoDevice;
}
const stream = &std.fs.File.openHandle(fd).inStream().stream;
--
2.54.0
From 08251fbc544aa03c77d4c311e267689592432282 Mon Sep 17 00:00:00 2001
From: Euan T
Date: Sat, 3 Aug 2019 07:51:36 +0100
Subject: [PATCH 47/47] Omit system namespace.
Co-Authored-By: Andrew Kelley
---
std/os.zig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/std/os.zig b/std/os.zig
index 2caab634d66b4b495c9270cbcb3b5e38e234daee..c2010bf6a95b6df6dafcd3591d67d3f5ad9a32b9 100644
--- a/std/os.zig
+++ b/std/os.zig
@@ -134,7 +134,7 @@ fn getRandomBytesDevURandom(buf: []u8) !void {
defer close(fd);
const st = try fstat(fd);
- if (!system.S_ISCHR(st.mode)) {
+ if (!S_ISCHR(st.mode)) {
return error.NoDevice;
}
--
2.54.0