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 b39c6e1196..c74e8c43be 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,
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 804c421618..6a949270ae 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:
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 1fa33b30f9..1248635de9 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 9d03b592fd..de17404f2e 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];
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 5193a63ec4..579875dc3c 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;
}
}
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 f4e9c2b53b..fc0786094d 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));
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 79ade39ef7..a6b2bc51c3 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 797451c8f8..de4d64f5d6 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 a6ad92110e..b9e9f2df7d 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 154803f884..fe131ab65f 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 579875dc3c..be7a8e2e51 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 0783d4ec10..fe1f89ac92 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 fd365235d8..40ce8d304b 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 db8fdcf368..71af5586ed 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 0000000000..fb45a9392d
--- /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);
+}
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 7bd5c537d3..df39c04f91 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;
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 79d1ae8dad..72a5234f61 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 4f3fb76b54..0daa9f35a8 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 {
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 72a5234f61..f648ced943 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();
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 bff110449c..831241de0f 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",
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 831241de0f..3d3dcba76d 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 f648ced943..38bd94339f 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 0daa9f35a8..59acf99890 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 df39c04f91..4539e1e5b2 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;
},
'=' => {
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 fc0786094d..e6e7143f06 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.?,
};
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 e6e7143f06..3a0c34c8d1 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.?,
};
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 de4d64f5d6..0af1baec35 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;
}
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 | 62 +++++---
std/os/windows/kernel32.zig | 1 +
std/special/start.zig | 14 +-
6 files changed, 192 insertions(+), 172 deletions(-)
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 188c5ccc8d..be694b19f9 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 5de36c1aab..cdff61a26f 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 ce68e53d85..42d0850046 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 d81e62901a..7d1fd6ce47 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),
- };
-
- os.sigaction(os.SIGSEGV, &act, null);
- },
- .windows => {
- _ = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);
- },
- else => unreachable,
+ 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);
}
-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.
+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.
+ 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 e4edc349ab..2ae73ad45a 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 30298669e3..f8a018e0ae 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();
}
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 07041d026f..011f742d82 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 5064e9db29..a5bbefa1db 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 d5b2778a34..477ce2cb98 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 0000000000..7a955120f5
--- /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 0000000000..db4daf1e1e
--- /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 d94c012ac1..c8aea33591 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;
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 fe131ab65f..af134d29b5 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 d2a5b72b2b..672075e3b6 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() {}
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 f6f3363bf6..66da3d7328 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 b85c11c6ac..6739db4285 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);
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 be694b19f9..0ac945e8c2 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,
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 70b47c4590..431e3fe272 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;
+}
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 f8a018e0ae..3427ff422d 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 => {
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 d8cf0c507d..debfb9392c 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()
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 9fdc368878..7c53f48f66 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.
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 debfb9392c..998da172fc 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()
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 2e9527f4ca..479ea76e8c 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);
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 0b28550a13..b5935a2eac 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 350f0fb437..e48586d873 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");
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 3a0c34c8d1..6be88ae7ec 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) {
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 479ea76e8c..7c08cd14ee 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 e0b84d5c0d..3bbbde782e 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);
}
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 190f02101e..9ff2e8f87f 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,
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 7c53f48f66..3890151d09 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 7d1fd6ce47..32f96d3e15 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 ffe2120296..39f304afb5 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;
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 39f304afb5..7a2b2c6b6b 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 {
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 3a0c34c8d1..acd3a1e33b 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,
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 acd3a1e33b..997e2ab901 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;
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 997e2ab901..d63e1ae899 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",
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 be7a8e2e51..f34c840496 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 6a949270ae..7bb248a35f 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 fcda9955b9..985a4c11b4 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 daa463fd45..3d1caaaa15 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);
+}
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 3d1caaaa15..a97467e416 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);
+//}
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 9ff2e8f87f..da1d71d6fc 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;
}
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 da1d71d6fc..ce240bb956 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 b8d229dbe9..dd4d46287e 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 67ce9a06cf..c2b6801e22 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
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 dd4d46287e..483d4cda90 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 198857983e..45432a6c07 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 d418ccd415..e9efe64920 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
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 | 23 ++++++++++++++++-------
test/stage1/behavior/eval.zig | 10 ++++++++++
2 files changed, 26 insertions(+), 7 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index f34c840496..8a46fec7c9 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 || rvalue == irb->codegen->invalid_instruction)
+ 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);
+
+ 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 97d3a269cc..58d662d768 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.?);
+ }
+}
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 0ac945e8c2..ef24716dff 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 a97467e416..1a941cf21c 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);
+}
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 8a46fec7c9..de2e4e1654 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 d6d670b09b..6b9c8b8fe7 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();
+}
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 a6b2bc51c3..4c3aeade9e 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 de2e4e1654..65a21a418d 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 40ce8d304b..a4bc2a66f0 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(
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 b5fe464c35..ac381e00b2 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#}
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 b5935a2eac..0b84950544 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);
+}
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 ce240bb956..2caab634d6 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;
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 2caab634d6..c2010bf6a9 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;
}