From 1aa978f32e88b4c83fde95f62938c97c7c22164c Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 14 Nov 2019 03:26:33 -0500
Subject: implement null terminated pointers
---
src/analyze.cpp | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
(limited to 'src/analyze.cpp')
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 0a8b32dca7..d84ba1d37c 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -460,6 +460,8 @@ static const char *ptr_len_to_star_str(PtrLen ptr_len) {
return "[*]";
case PtrLenC:
return "[*c]";
+ case PtrLenNull:
+ return "[*]null ";
}
zig_unreachable();
}
@@ -7032,7 +7034,7 @@ uint32_t type_id_hash(TypeId x) {
return hash_ptr(x.data.error_union.err_set_type) ^ hash_ptr(x.data.error_union.payload_type);
case ZigTypeIdPointer:
return hash_ptr(x.data.pointer.child_type) +
- ((x.data.pointer.ptr_len == PtrLenSingle) ? (uint32_t)1120226602 : (uint32_t)3200913342) +
+ (uint32_t)x.data.pointer.ptr_len * 1120226602u +
(x.data.pointer.is_const ? (uint32_t)2749109194 : (uint32_t)4047371087) +
(x.data.pointer.is_volatile ? (uint32_t)536730450 : (uint32_t)1685612214) +
(x.data.pointer.allow_zero ? (uint32_t)3324284834 : (uint32_t)3584904923) +
--
cgit v1.2.3
From 21f344b3b903b41fd4793faa82a4ac26ad2544aa Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sun, 17 Nov 2019 23:06:28 -0500
Subject: add null terminated pointers and arrays to self-hosted
as well as `@typeInfo` and `@Type`
---
lib/std/builtin.zig | 1 +
lib/std/zig/ast.zig | 16 +++-
lib/std/zig/parse.zig | 39 ++++++++--
lib/std/zig/parser_test.zig | 3 +
lib/std/zig/render.zig | 12 ++-
src-self-hosted/translate_c.zig | 1 +
src/all_types.hpp | 5 ++
src/analyze.cpp | 31 ++++----
src/analyze.hpp | 2 +-
src/codegen.cpp | 4 +-
src/ir.cpp | 67 +++++++++++------
test/stage1/behavior/if.zig | 4 +
test/stage1/behavior/type.zig | 147 +++++++++++++++++++++----------------
test/stage1/behavior/type_info.zig | 31 ++++++--
14 files changed, 240 insertions(+), 123 deletions(-)
(limited to 'src/analyze.cpp')
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig
index 9f1e52428c..56c3426d8b 100644
--- a/lib/std/builtin.zig
+++ b/lib/std/builtin.zig
@@ -161,6 +161,7 @@ pub const TypeInfo = union(enum) {
pub const Array = struct {
len: comptime_int,
child: type,
+ is_null_terminated: bool,
};
/// This data structure is used by the Zig language code generation and
diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig
index 0a7bfe2f56..9072626c86 100644
--- a/lib/std/zig/ast.zig
+++ b/lib/std/zig/ast.zig
@@ -137,6 +137,7 @@ pub const Error = union(enum) {
ExpectedCallOrFnProto: ExpectedCallOrFnProto,
ExpectedSliceOrRBracket: ExpectedSliceOrRBracket,
ExtraAlignQualifier: ExtraAlignQualifier,
+ ExtraNullQualifier: ExtraNullQualifier,
ExtraConstQualifier: ExtraConstQualifier,
ExtraVolatileQualifier: ExtraVolatileQualifier,
ExtraAllowZeroQualifier: ExtraAllowZeroQualifier,
@@ -184,6 +185,7 @@ pub const Error = union(enum) {
.ExpectedCallOrFnProto => |*x| return x.render(tokens, stream),
.ExpectedSliceOrRBracket => |*x| return x.render(tokens, stream),
.ExtraAlignQualifier => |*x| return x.render(tokens, stream),
+ .ExtraNullQualifier => |*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),
@@ -233,6 +235,7 @@ pub const Error = union(enum) {
.ExpectedCallOrFnProto => |x| return x.node.firstToken(),
.ExpectedSliceOrRBracket => |x| return x.token,
.ExtraAlignQualifier => |x| return x.token,
+ .ExtraNullQualifier => |x| return x.token,
.ExtraConstQualifier => |x| return x.token,
.ExtraVolatileQualifier => |x| return x.token,
.ExtraAllowZeroQualifier => |x| return x.token,
@@ -293,6 +296,7 @@ pub const Error = union(enum) {
pub const ExpectedPubItem = SimpleError("Expected function or variable declaration after pub");
pub const UnattachedDocComment = SimpleError("Unattached documentation comment");
pub const ExtraAlignQualifier = SimpleError("Extra align qualifier");
+ pub const ExtraNullQualifier = SimpleError("Extra null qualifier");
pub const ExtraConstQualifier = SimpleError("Extra const qualifier");
pub const ExtraVolatileQualifier = SimpleError("Extra volatile qualifier");
pub const ExtraAllowZeroQualifier = SimpleError("Extra allowzero qualifier");
@@ -1538,7 +1542,7 @@ pub const Node = struct {
pub const Op = union(enum) {
AddressOf,
- ArrayType: *Node,
+ ArrayType: ArrayInfo,
Await,
BitNot,
BoolNot,
@@ -1552,11 +1556,17 @@ pub const Node = struct {
Try,
};
+ pub const ArrayInfo = struct {
+ len_expr: *Node,
+ null_token: ?TokenIndex,
+ };
+
pub const PtrInfo = struct {
allowzero_token: ?TokenIndex,
align_info: ?Align,
const_token: ?TokenIndex,
volatile_token: ?TokenIndex,
+ null_token: ?TokenIndex,
pub const Align = struct {
node: *Node,
@@ -1588,8 +1598,8 @@ pub const Node = struct {
}
},
- Op.ArrayType => |size_expr| {
- if (i < 1) return size_expr;
+ Op.ArrayType => |array_info| {
+ if (i < 1) return array_info.len_expr;
i -= 1;
},
diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig
index 42dff71b2a..1190b89089 100644
--- a/lib/std/zig/parse.zig
+++ b/lib/std/zig/parse.zig
@@ -1085,7 +1085,7 @@ fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.Suf
const node = try arena.create(Node.SuffixOp);
node.* = Node.SuffixOp{
.base = Node{ .id = .SuffixOp },
- .lhs = .{.node = undefined}, // set by caller
+ .lhs = .{ .node = undefined }, // set by caller
.op = op,
.rtoken = try expectToken(it, tree, .RBrace),
};
@@ -1138,7 +1138,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
while (try parseSuffixOp(arena, it, tree)) |node| {
switch (node.id) {
- .SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{.node = res},
+ .SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{ .node = res },
.InfixOp => node.cast(Node.InfixOp).?.lhs = res,
else => unreachable,
}
@@ -1154,7 +1154,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const node = try arena.create(Node.SuffixOp);
node.* = Node.SuffixOp{
.base = Node{ .id = .SuffixOp },
- .lhs = .{.node = res},
+ .lhs = .{ .node = res },
.op = Node.SuffixOp.Op{
.Call = Node.SuffixOp.Op.Call{
.params = params.list,
@@ -1171,7 +1171,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
while (true) {
if (try parseSuffixOp(arena, it, tree)) |node| {
switch (node.id) {
- .SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{.node = res},
+ .SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{ .node = res },
.InfixOp => node.cast(Node.InfixOp).?.lhs = res,
else => unreachable,
}
@@ -1182,7 +1182,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const call = try arena.create(Node.SuffixOp);
call.* = Node.SuffixOp{
.base = Node{ .id = .SuffixOp },
- .lhs = .{.node = res},
+ .lhs = .{ .node = res },
.op = Node.SuffixOp.Op{
.Call = Node.SuffixOp.Op.Call{
.params = params.list,
@@ -1531,7 +1531,7 @@ fn parseAnonLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
// anon container literal
if (try parseInitList(arena, it, tree)) |node| {
- node.lhs = .{.dot = dot};
+ node.lhs = .{ .dot = dot };
return &node.base;
}
@@ -2252,6 +2252,16 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
.SliceType => |*slice_type| {
// Collect pointer qualifiers in any order, but disallow duplicates
while (true) {
+ if (eatToken(it, .Keyword_null)) |null_token| {
+ if (slice_type.null_token != null) {
+ try tree.errors.push(AstError{
+ .ExtraNullQualifier = AstError.ExtraNullQualifier{ .token = it.index },
+ });
+ return error.ParseError;
+ }
+ slice_type.null_token = null_token;
+ continue;
+ }
if (try parseByteAlign(arena, it, tree)) |align_expr| {
if (slice_type.align_info != null) {
try tree.errors.push(AstError{
@@ -2313,6 +2323,10 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
&prefix_op.op.PtrType;
while (true) {
+ if (eatToken(it, .Keyword_null)) |null_token| {
+ ptr_info.null_token = null_token;
+ continue;
+ }
if (eatToken(it, .Keyword_align)) |align_token| {
const lparen = try expectToken(it, tree, .LParen);
const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{
@@ -2460,9 +2474,15 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
const lbracket = eatToken(it, .LBracket) orelse return null;
const expr = try parseExpr(arena, it, tree);
const rbracket = try expectToken(it, tree, .RBracket);
+ const null_token = eatToken(it, .Keyword_null);
- const op = if (expr) |element_type|
- Node.PrefixOp.Op{ .ArrayType = element_type }
+ const op = if (expr) |len_expr|
+ Node.PrefixOp.Op{
+ .ArrayType = .{
+ .len_expr = len_expr,
+ .null_token = null_token,
+ },
+ }
else
Node.PrefixOp.Op{
.SliceType = Node.PrefixOp.PtrInfo{
@@ -2470,6 +2490,7 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
.align_info = null,
.const_token = null,
.volatile_token = null,
+ .null_token = null,
},
};
@@ -2505,6 +2526,7 @@ fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
.align_info = null,
.const_token = null,
.volatile_token = null,
+ .null_token = null,
},
},
.rhs = undefined, // set by caller
@@ -2522,6 +2544,7 @@ fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
.align_info = null,
.const_token = null,
.volatile_token = null,
+ .null_token = null,
},
},
.rhs = undefined, // set by caller
diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig
index 2f420768bf..0f9d0a59cf 100644
--- a/lib/std/zig/parser_test.zig
+++ b/lib/std/zig/parser_test.zig
@@ -1552,6 +1552,7 @@ test "zig fmt: pointer attributes" {
\\extern fn f2(s: **align(1) *const *volatile u8) c_int;
\\extern fn f3(s: *align(1) const *align(1) volatile *const volatile u8) c_int;
\\extern fn f4(s: *align(1) const volatile u8) c_int;
+ \\extern fn f5(s: [*]null align(1) const volatile u8) c_int;
\\
);
}
@@ -1562,6 +1563,7 @@ test "zig fmt: slice attributes" {
\\extern fn f2(s: **align(1) *const *volatile u8) c_int;
\\extern fn f3(s: *align(1) const *align(1) volatile *const volatile u8) c_int;
\\extern fn f4(s: *align(1) const volatile u8) c_int;
+ \\extern fn f5(s: [*]null align(1) const volatile u8) c_int;
\\
);
}
@@ -1889,6 +1891,7 @@ test "zig fmt: arrays" {
\\ 2,
\\ };
\\ const a: [0]u8 = []u8{};
+ \\ const x: [4]null u8 = undefined;
\\}
\\
);
diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig
index 258a5493de..dab2d66319 100644
--- a/lib/std/zig/render.zig
+++ b/lib/std/zig/render.zig
@@ -423,6 +423,9 @@ fn renderExpression(
else => @as(usize, 0),
};
try renderTokenOffset(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None, star_offset); // *
+ if (ptr_info.null_token) |null_token| {
+ try renderToken(tree, stream, null_token, indent, start_col, Space.Space); // null
+ }
if (ptr_info.allowzero_token) |allowzero_token| {
try renderToken(tree, stream, allowzero_token, indent, start_col, Space.Space); // allowzero
}
@@ -499,9 +502,9 @@ fn renderExpression(
}
},
- ast.Node.PrefixOp.Op.ArrayType => |array_index| {
+ ast.Node.PrefixOp.Op.ArrayType => |array_info| {
const lbracket = prefix_op_node.op_token;
- const rbracket = tree.nextToken(array_index.lastToken());
+ const rbracket = tree.nextToken(array_info.len_expr.lastToken());
try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
@@ -509,7 +512,7 @@ fn renderExpression(
const ends_with_comment = tree.tokens.at(rbracket - 1).id == .LineComment;
const new_indent = if (ends_with_comment) indent + indent_delta else indent;
const new_space = if (ends_with_comment) Space.Newline else Space.None;
- try renderExpression(allocator, stream, tree, new_indent, start_col, array_index, new_space);
+ try renderExpression(allocator, stream, tree, new_indent, start_col, array_info.len_expr, new_space);
if (starts_with_comment) {
try stream.writeByte('\n');
}
@@ -517,6 +520,9 @@ fn renderExpression(
try stream.writeByteNTimes(' ', indent);
}
try renderToken(tree, stream, rbracket, indent, start_col, Space.None); // ]
+ if (array_info.null_token) |null_token| {
+ try renderToken(tree, stream, null_token, indent, start_col, Space.Space); // null
+ }
},
ast.Node.PrefixOp.Op.BitNot,
ast.Node.PrefixOp.Op.BoolNot,
diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig
index e919977116..daa60fcb25 100644
--- a/src-self-hosted/translate_c.zig
+++ b/src-self-hosted/translate_c.zig
@@ -1118,6 +1118,7 @@ fn transCreateNodePtrType(
.align_info = null,
.const_token = if (is_const) try appendToken(c, .Keyword_const, "const") else null,
.volatile_token = if (is_volatile) try appendToken(c, .Keyword_volatile, "volatile") else null,
+ .null_token = null,
},
},
.rhs = undefined, // translate and set afterward
diff --git a/src/all_types.hpp b/src/all_types.hpp
index f5c9c67414..0fe43eaa3e 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -358,6 +358,7 @@ struct LazyValueSliceType {
bool is_const;
bool is_volatile;
bool is_allowzero;
+ bool is_null_terminated;
};
struct LazyValuePtrType {
@@ -1234,6 +1235,7 @@ struct ZigTypeFloat {
struct ZigTypeArray {
ZigType *child_type;
uint64_t len;
+ bool is_null_terminated;
};
struct TypeStructField {
@@ -1775,6 +1777,7 @@ struct TypeId {
struct {
ZigType *child_type;
uint64_t size;
+ bool is_null_terminated;
} array;
struct {
bool is_signed;
@@ -2986,6 +2989,7 @@ struct IrInstructionArrayType {
IrInstruction *size;
IrInstruction *child_type;
+ bool is_null_terminated;
};
struct IrInstructionPtrType {
@@ -3015,6 +3019,7 @@ struct IrInstructionSliceType {
bool is_const;
bool is_volatile;
bool is_allow_zero;
+ bool is_null_terminated;
};
struct IrInstructionGlobalAsm {
diff --git a/src/analyze.cpp b/src/analyze.cpp
index d84ba1d37c..f67c4a035e 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -752,11 +752,12 @@ ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payloa
return entry;
}
-ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size) {
+ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, bool is_null_terminated) {
TypeId type_id = {};
type_id.id = ZigTypeIdArray;
type_id.data.array.child_type = child_type;
type_id.data.array.size = array_size;
+ type_id.data.array.is_null_terminated = is_null_terminated;
auto existing_entry = g->type_table.maybe_get(type_id);
if (existing_entry) {
return existing_entry->value;
@@ -769,12 +770,14 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size) {
buf_resize(&entry->name, 0);
buf_appendf(&entry->name, "[%" ZIG_PRI_u64 "]%s", array_size, buf_ptr(&child_type->name));
- entry->size_in_bits = child_type->size_in_bits * array_size;
+ size_t full_array_size = array_size + (is_null_terminated ? 1 : 0);
+ entry->size_in_bits = child_type->size_in_bits * full_array_size;
entry->abi_align = child_type->abi_align;
- entry->abi_size = child_type->abi_size * array_size;
+ entry->abi_size = child_type->abi_size * full_array_size;
entry->data.array.child_type = child_type;
entry->data.array.len = array_size;
+ entry->data.array.is_null_terminated = is_null_terminated;
g->type_table.put(type_id, entry);
return entry;
@@ -782,7 +785,7 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size) {
ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
assert(ptr_type->id == ZigTypeIdPointer);
- assert(ptr_type->data.pointer.ptr_len == PtrLenUnknown);
+ assert(ptr_type->data.pointer.ptr_len == PtrLenUnknown || ptr_type->data.pointer.ptr_len == PtrLenNull);
ZigType **parent_pointer = &ptr_type->data.pointer.slice_parent;
if (*parent_pointer) {
@@ -5615,7 +5618,7 @@ void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
}
const_val->special = ConstValSpecialStatic;
- const_val->type = get_array_type(g, g->builtin_types.entry_u8, buf_len(str));
+ const_val->type = get_array_type(g, g->builtin_types.entry_u8, buf_len(str), false);
const_val->data.x_array.special = ConstArraySpecialBuf;
const_val->data.x_array.data.s_buf = str;
@@ -5633,7 +5636,7 @@ void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
size_t len_with_null = buf_len(str) + 1;
ConstExprValue *array_val = create_const_vals(1);
array_val->special = ConstValSpecialStatic;
- array_val->type = get_array_type(g, g->builtin_types.entry_u8, len_with_null);
+ array_val->type = get_array_type(g, g->builtin_types.entry_u8, len_with_null, false);
// TODO buf optimization
array_val->data.x_array.data.s_none.elements = create_const_vals(len_with_null);
for (size_t i = 0; i < buf_len(str); i += 1) {
@@ -6071,7 +6074,7 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
fields.append({"@stack_trace", get_stack_trace_type(g), 0});
fields.append({"@instruction_addresses",
- get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count), 0});
+ get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count, false), 0});
}
frame_type->data.frame.locals_struct = get_struct_type(g, buf_ptr(&frame_type->name),
@@ -6279,7 +6282,7 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
if (codegen_fn_has_err_ret_tracing_stack(g, fn, true)) {
fields.append({"@stack_trace", get_stack_trace_type(g), 0});
fields.append({"@instruction_addresses",
- get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count), 0});
+ get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count, false), 0});
}
for (size_t alloca_i = 0; alloca_i < fn->alloca_gen_list.length; alloca_i += 1) {
@@ -7043,8 +7046,9 @@ uint32_t type_id_hash(TypeId x) {
(((uint32_t)x.data.pointer.vector_index) ^ (uint32_t)0x19199716) +
(((uint32_t)x.data.pointer.host_int_bytes) ^ (uint32_t)529908881);
case ZigTypeIdArray:
- return hash_ptr(x.data.array.child_type) +
- ((uint32_t)x.data.array.size ^ (uint32_t)2122979968);
+ return hash_ptr(x.data.array.child_type) *
+ ((uint32_t)x.data.array.size ^ (uint32_t)2122979968) *
+ ((uint32_t)x.data.array.is_null_terminated ^ (uint32_t)2048352596);
case ZigTypeIdInt:
return (x.data.integer.is_signed ? (uint32_t)2652528194 : (uint32_t)163929201) +
(((uint32_t)x.data.integer.bit_count) ^ (uint32_t)2998081557);
@@ -7106,7 +7110,8 @@ bool type_id_eql(TypeId a, TypeId b) {
);
case ZigTypeIdArray:
return a.data.array.child_type == b.data.array.child_type &&
- a.data.array.size == b.data.array.size;
+ a.data.array.size == b.data.array.size &&
+ a.data.array.is_null_terminated == b.data.array.is_null_terminated;
case ZigTypeIdInt:
return a.data.integer.is_signed == b.data.integer.is_signed &&
a.data.integer.bit_count == b.data.integer.bit_count;
@@ -8292,7 +8297,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta
size_t padding_bytes = union_type->data.unionation.union_abi_size - most_aligned_union_member->type_entry->abi_size;
if (padding_bytes > 0) {
ZigType *u8_type = get_int_type(g, false, 8);
- ZigType *padding_array = get_array_type(g, u8_type, padding_bytes);
+ ZigType *padding_array = get_array_type(g, u8_type, padding_bytes, false);
LLVMTypeRef union_element_types[] = {
most_aligned_union_member->type_entry->llvm_type,
get_llvm_type(g, padding_array),
@@ -8326,7 +8331,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta
union_type_ref = get_llvm_type(g, most_aligned_union_member->type_entry);
} else {
ZigType *u8_type = get_int_type(g, false, 8);
- ZigType *padding_array = get_array_type(g, u8_type, padding_bytes);
+ ZigType *padding_array = get_array_type(g, u8_type, padding_bytes, false);
LLVMTypeRef union_element_types[] = {
get_llvm_type(g, most_aligned_union_member->type_entry),
get_llvm_type(g, padding_array),
diff --git a/src/analyze.hpp b/src/analyze.hpp
index ddfb31c286..a1e38a43d7 100644
--- a/src/analyze.hpp
+++ b/src/analyze.hpp
@@ -33,7 +33,7 @@ ZigType **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type);
ZigType *get_c_int_type(CodeGen *g, CIntType c_int_type);
ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id);
ZigType *get_optional_type(CodeGen *g, ZigType *child_type);
-ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size);
+ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, bool is_null_terminated);
ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type);
ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind,
AstNode *decl_node, const char *full_name, Buf *bare_name, ContainerLayout layout);
diff --git a/src/codegen.cpp b/src/codegen.cpp
index a288f397fd..5def04575e 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -7465,7 +7465,7 @@ static void do_code_gen(CodeGen *g) {
!is_async && !have_err_ret_trace_arg;
LLVMValueRef err_ret_array_val = nullptr;
if (have_err_ret_trace_stack) {
- ZigType *array_type = get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count);
+ ZigType *array_type = get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count, false);
err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", get_abi_alignment(g, array_type));
(void)get_llvm_type(g, get_stack_trace_type(g));
@@ -9067,7 +9067,7 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
zig_unreachable();
ConstExprValue *test_fn_array = create_const_vals(1);
- test_fn_array->type = get_array_type(g, struct_type, g->test_fns.length);
+ test_fn_array->type = get_array_type(g, struct_type, g->test_fns.length, false);
test_fn_array->special = ConstValSpecialStatic;
test_fn_array->data.x_array.data.s_none.elements = create_const_vals(g->test_fns.length);
diff --git a/src/ir.cpp b/src/ir.cpp
index 77fc1307ca..c910d4800d 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -1772,11 +1772,12 @@ static IrInstruction *ir_build_set_float_mode(IrBuilder *irb, Scope *scope, AstN
}
static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *size,
- IrInstruction *child_type)
+ IrInstruction *child_type, bool is_null_terminated)
{
IrInstructionArrayType *instruction = ir_build_instruction(irb, scope, source_node);
instruction->size = size;
instruction->child_type = child_type;
+ instruction->is_null_terminated = is_null_terminated;
ir_ref_instruction(size, irb->current_basic_block);
ir_ref_instruction(child_type, irb->current_basic_block);
@@ -1795,7 +1796,8 @@ static IrInstruction *ir_build_anyframe_type(IrBuilder *irb, Scope *scope, AstNo
return &instruction->base;
}
static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value, bool is_allow_zero)
+ IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value, bool is_allow_zero,
+ bool is_null_terminated)
{
IrInstructionSliceType *instruction = ir_build_instruction(irb, scope, source_node);
instruction->is_const = is_const;
@@ -1803,6 +1805,7 @@ static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode
instruction->child_type = child_type;
instruction->align_value = align_value;
instruction->is_allow_zero = is_allow_zero;
+ instruction->is_null_terminated = is_null_terminated;
ir_ref_instruction(child_type, irb->current_basic_block);
if (align_value) ir_ref_instruction(align_value, irb->current_basic_block);
@@ -6216,7 +6219,7 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A
return elem_type;
size_t item_count = container_init_expr->entries.length;
IrInstruction *item_count_inst = ir_build_const_usize(irb, scope, node, item_count);
- container_type = ir_build_array_type(irb, scope, node, item_count_inst, elem_type);
+ container_type = ir_build_array_type(irb, scope, node, item_count_inst, elem_type, false);
} else {
container_type = ir_gen_node(irb, container_init_expr->type, scope);
if (container_type == irb->codegen->invalid_instruction)
@@ -6944,6 +6947,7 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
bool is_const = node->data.array_type.is_const;
bool is_volatile = node->data.array_type.is_volatile;
bool is_allow_zero = node->data.array_type.allow_zero_token != nullptr;
+ bool is_null_terminated = node->data.array_type.is_null_terminated;
AstNode *align_expr = node->data.array_type.align_expr;
Scope *comptime_scope = create_comptime_scope(irb->codegen, node, scope);
@@ -6973,7 +6977,7 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
if (child_type == irb->codegen->invalid_instruction)
return child_type;
- return ir_build_array_type(irb, scope, node, size_value, child_type);
+ return ir_build_array_type(irb, scope, node, size_value, child_type, is_null_terminated);
} else {
IrInstruction *align_value;
if (align_expr != nullptr) {
@@ -6988,7 +6992,8 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
if (child_type == irb->codegen->invalid_instruction)
return child_type;
- return ir_build_slice_type(irb, scope, node, child_type, is_const, is_volatile, align_value, is_allow_zero);
+ return ir_build_slice_type(irb, scope, node, child_type, is_const, is_volatile, align_value, is_allow_zero,
+ is_null_terminated);
}
}
@@ -10631,6 +10636,7 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
// *[N]T to []T
// *[N]T to E![]T
if (cur_type->id == ZigTypeIdPointer &&
+ cur_type->data.pointer.ptr_len == PtrLenSingle &&
cur_type->data.pointer.child_type->id == ZigTypeIdArray &&
((prev_type->id == ZigTypeIdErrorUnion && is_slice(prev_type->data.error_union.payload_type)) ||
is_slice(prev_type)))
@@ -10639,7 +10645,8 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
ZigType *slice_type = (prev_type->id == ZigTypeIdErrorUnion) ?
prev_type->data.error_union.payload_type : prev_type;
ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry;
- if ((slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0) &&
+ if ((slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 ||
+ !cur_type->data.pointer.is_const) &&
types_match_const_cast_only(ira,
slice_ptr_type->data.pointer.child_type,
array_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk)
@@ -10653,6 +10660,7 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
// *[N]T to E![]T
if (prev_type->id == ZigTypeIdPointer &&
prev_type->data.pointer.child_type->id == ZigTypeIdArray &&
+ prev_type->data.pointer.ptr_len == PtrLenSingle &&
((cur_type->id == ZigTypeIdErrorUnion && is_slice(cur_type->data.error_union.payload_type)) ||
is_slice(cur_type)))
{
@@ -10660,7 +10668,8 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
ZigType *slice_type = (cur_type->id == ZigTypeIdErrorUnion) ?
cur_type->data.error_union.payload_type : cur_type;
ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry;
- if ((slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0) &&
+ if ((slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 ||
+ !prev_type->data.pointer.is_const) &&
types_match_const_cast_only(ira,
slice_ptr_type->data.pointer.child_type,
array_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk)
@@ -14893,7 +14902,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
ConstExprValue *out_array_val;
size_t new_len = (op1_array_end - op1_array_index) + (op2_array_end - op2_array_index);
if (op1_type->id == ZigTypeIdArray || op2_type->id == ZigTypeIdArray) {
- result->value.type = get_array_type(ira->codegen, child_type, new_len);
+ result->value.type = get_array_type(ira->codegen, child_type, new_len, false);
out_array_val = out_val;
} else if (is_slice(op1_type) || is_slice(op2_type)) {
@@ -14902,7 +14911,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
result->value.type = get_slice_type(ira->codegen, ptr_type);
out_array_val = create_const_vals(1);
out_array_val->special = ConstValSpecialStatic;
- out_array_val->type = get_array_type(ira->codegen, child_type, new_len);
+ out_array_val->type = get_array_type(ira->codegen, child_type, new_len, false);
out_val->data.x_struct.fields = alloc_const_vals_ptrs(2);
@@ -14923,7 +14932,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
out_array_val = create_const_vals(1);
out_array_val->special = ConstValSpecialStatic;
- out_array_val->type = get_array_type(ira->codegen, child_type, new_len);
+ out_array_val->type = get_array_type(ira->codegen, child_type, new_len, false);
out_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
out_val->data.x_ptr.data.base_array.is_cstr = true;
out_val->data.x_ptr.data.base_array.array_val = out_array_val;
@@ -14994,7 +15003,7 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp *
ZigType *child_type = array_type->data.array.child_type;
IrInstruction *result = ir_const(ira, &instruction->base,
- get_array_type(ira->codegen, child_type, new_array_len));
+ get_array_type(ira->codegen, child_type, new_array_len, false));
ConstExprValue *out_val = &result->value;
if (array_val->data.x_array.special == ConstArraySpecialUndef) {
out_val->data.x_array.special = ConstArraySpecialUndef;
@@ -19311,6 +19320,7 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
lazy_slice_type->is_const = slice_type_instruction->is_const;
lazy_slice_type->is_volatile = slice_type_instruction->is_volatile;
lazy_slice_type->is_allowzero = slice_type_instruction->is_allow_zero;
+ lazy_slice_type->is_null_terminated = slice_type_instruction->is_null_terminated;
return result;
}
@@ -19420,7 +19430,8 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,
{
if ((err = type_resolve(ira->codegen, child_type, ResolveStatusSizeKnown)))
return ira->codegen->invalid_instruction;
- ZigType *result_type = get_array_type(ira->codegen, child_type, size);
+ ZigType *result_type = get_array_type(ira->codegen, child_type, size,
+ array_type_instruction->is_null_terminated);
return ir_const_type(ira, &array_type_instruction->base, result_type);
}
}
@@ -20496,7 +20507,7 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira,
if (container_type->id == ZigTypeIdArray) {
ZigType *child_type = container_type->data.array.child_type;
if (container_type->data.array.len != elem_count) {
- ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count);
+ ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count, false);
ir_add_error(ira, &instruction->base,
buf_sprintf("expected %s literal, found %s literal",
@@ -20983,7 +20994,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr
ConstExprValue *declaration_array = create_const_vals(1);
declaration_array->special = ConstValSpecialStatic;
- declaration_array->type = get_array_type(ira->codegen, type_info_declaration_type, declaration_count);
+ declaration_array->type = get_array_type(ira->codegen, type_info_declaration_type, declaration_count, false);
declaration_array->data.x_array.special = ConstArraySpecialNone;
declaration_array->data.x_array.data.s_none.elements = create_const_vals(declaration_count);
init_const_slice(ira->codegen, out_val, declaration_array, 0, declaration_count, false);
@@ -21128,7 +21139,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr
ConstExprValue *fn_arg_name_array = create_const_vals(1);
fn_arg_name_array->special = ConstValSpecialStatic;
fn_arg_name_array->type = get_array_type(ira->codegen,
- get_slice_type(ira->codegen, u8_ptr), fn_arg_count);
+ get_slice_type(ira->codegen, u8_ptr), fn_arg_count, false);
fn_arg_name_array->data.x_array.special = ConstArraySpecialNone;
fn_arg_name_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count);
@@ -21376,7 +21387,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
result->special = ConstValSpecialStatic;
result->type = ir_type_info_get_type(ira, "Array", nullptr);
- ConstExprValue **fields = alloc_const_vals_ptrs(2);
+ ConstExprValue **fields = alloc_const_vals_ptrs(3);
result->data.x_struct.fields = fields;
// len: usize
@@ -21389,6 +21400,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
fields[1]->special = ConstValSpecialStatic;
fields[1]->type = ira->codegen->builtin_types.entry_type;
fields[1]->data.x_type = type_entry->data.array.child_type;
+ // is_null_terminated: bool
+ ensure_field_index(result->type, "is_null_terminated", 2);
+ fields[2]->special = ConstValSpecialStatic;
+ fields[2]->type = ira->codegen->builtin_types.entry_bool;
+ fields[2]->data.x_bool = type_entry->data.array.is_null_terminated;
break;
}
@@ -21476,7 +21492,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
ConstExprValue *enum_field_array = create_const_vals(1);
enum_field_array->special = ConstValSpecialStatic;
- enum_field_array->type = get_array_type(ira->codegen, type_info_enum_field_type, enum_field_count);
+ enum_field_array->type = get_array_type(ira->codegen, type_info_enum_field_type, enum_field_count, false);
enum_field_array->data.x_array.special = ConstArraySpecialNone;
enum_field_array->data.x_array.data.s_none.elements = create_const_vals(enum_field_count);
@@ -21524,7 +21540,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
uint32_t error_count = type_entry->data.error_set.err_count;
ConstExprValue *error_array = create_const_vals(1);
error_array->special = ConstValSpecialStatic;
- error_array->type = get_array_type(ira->codegen, type_info_error_type, error_count);
+ error_array->type = get_array_type(ira->codegen, type_info_error_type, error_count, false);
error_array->data.x_array.special = ConstArraySpecialNone;
error_array->data.x_array.data.s_none.elements = create_const_vals(error_count);
@@ -21620,7 +21636,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
ConstExprValue *union_field_array = create_const_vals(1);
union_field_array->special = ConstValSpecialStatic;
- union_field_array->type = get_array_type(ira->codegen, type_info_union_field_type, union_field_count);
+ union_field_array->type = get_array_type(ira->codegen, type_info_union_field_type, union_field_count, false);
union_field_array->data.x_array.special = ConstArraySpecialNone;
union_field_array->data.x_array.data.s_none.elements = create_const_vals(union_field_count);
@@ -21700,7 +21716,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
ConstExprValue *struct_field_array = create_const_vals(1);
struct_field_array->special = ConstValSpecialStatic;
- struct_field_array->type = get_array_type(ira->codegen, type_info_struct_field_type, struct_field_count);
+ struct_field_array->type = get_array_type(ira->codegen, type_info_struct_field_type, struct_field_count, false);
struct_field_array->data.x_array.special = ConstArraySpecialNone;
struct_field_array->data.x_array.data.s_none.elements = create_const_vals(struct_field_count);
@@ -21803,7 +21819,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
ConstExprValue *fn_arg_array = create_const_vals(1);
fn_arg_array->special = ConstValSpecialStatic;
- fn_arg_array->type = get_array_type(ira->codegen, type_info_fn_arg_type, fn_arg_count);
+ fn_arg_array->type = get_array_type(ira->codegen, type_info_fn_arg_type, fn_arg_count, false);
fn_arg_array->data.x_array.special = ConstArraySpecialNone;
fn_arg_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count);
@@ -21983,7 +21999,8 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInstruction *instruction, Zi
assert(payload->type == ir_type_info_get_type(ira, "Array", nullptr));
return get_array_type(ira->codegen,
get_const_field_meta_type(ira, payload, "child", 1),
- bigint_as_u64(get_const_field_lit_int(ira, payload, "len", 0))
+ bigint_as_u64(get_const_field_lit_int(ira, payload, "len", 0)),
+ get_const_field_bool(ira, payload, "is_null_terminated", 2)
);
case ZigTypeIdComptimeFloat:
return ira->codegen->builtin_types.entry_num_lit_float;
@@ -22366,7 +22383,7 @@ static IrInstruction *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstru
}
ZigType *result_type = get_array_type(ira->codegen,
- ira->codegen->builtin_types.entry_u8, buf_len(file_contents));
+ ira->codegen->builtin_types.entry_u8, buf_len(file_contents), false);
IrInstruction *result = ir_const(ira, &instruction->base, result_type);
init_const_str_lit(ira->codegen, &result->value, file_contents);
return result;
@@ -27581,7 +27598,9 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {
if ((err = type_resolve(ira->codegen, elem_type, needed_status)))
return err;
ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, elem_type,
- lazy_slice_type->is_const, lazy_slice_type->is_volatile, PtrLenUnknown, align_bytes,
+ lazy_slice_type->is_const, lazy_slice_type->is_volatile,
+ lazy_slice_type->is_null_terminated ? PtrLenNull : PtrLenUnknown,
+ align_bytes,
0, 0, lazy_slice_type->is_allowzero);
val->special = ConstValSpecialStatic;
assert(val->type->id == ZigTypeIdMetaType);
diff --git a/test/stage1/behavior/if.zig b/test/stage1/behavior/if.zig
index 9e93ceb656..63c31fb03e 100644
--- a/test/stage1/behavior/if.zig
+++ b/test/stage1/behavior/if.zig
@@ -81,6 +81,10 @@ test "if prongs cast to expected type instead of peer type resolution" {
var x: i32 = 0;
x = if (f) 1 else 2;
expect(x == 2);
+
+ var b = true;
+ const y: i32 = if (b) 1 else 2;
+ expect(y == 1);
}
};
S.doTheTest(false);
diff --git a/test/stage1/behavior/type.zig b/test/stage1/behavior/type.zig
index b84369a164..b1bb2e85bd 100644
--- a/test/stage1/behavior/type.zig
+++ b/test/stage1/behavior/type.zig
@@ -11,103 +11,122 @@ fn testTypes(comptime types: []const type) void {
}
test "Type.MetaType" {
- testing.expect(type == @Type(TypeInfo { .Type = undefined }));
- testTypes([_]type {type});
+ testing.expect(type == @Type(TypeInfo{ .Type = undefined }));
+ testTypes([_]type{type});
}
test "Type.Void" {
- testing.expect(void == @Type(TypeInfo { .Void = undefined }));
- testTypes([_]type {void});
+ testing.expect(void == @Type(TypeInfo{ .Void = undefined }));
+ testTypes([_]type{void});
}
test "Type.Bool" {
- testing.expect(bool == @Type(TypeInfo { .Bool = undefined }));
- testTypes([_]type {bool});
+ testing.expect(bool == @Type(TypeInfo{ .Bool = undefined }));
+ testTypes([_]type{bool});
}
test "Type.NoReturn" {
- testing.expect(noreturn == @Type(TypeInfo { .NoReturn = undefined }));
- testTypes([_]type {noreturn});
+ testing.expect(noreturn == @Type(TypeInfo{ .NoReturn = undefined }));
+ testTypes([_]type{noreturn});
}
test "Type.Int" {
- testing.expect(u1 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = false, .bits = 1 } }));
- testing.expect(i1 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = true, .bits = 1 } }));
- testing.expect(u8 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = false, .bits = 8 } }));
- testing.expect(i8 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = true, .bits = 8 } }));
- testing.expect(u64 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = false, .bits = 64 } }));
- testing.expect(i64 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = true, .bits = 64 } }));
- testTypes([_]type {u8,u32,i64});
+ testing.expect(u1 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .is_signed = false, .bits = 1 } }));
+ testing.expect(i1 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .is_signed = true, .bits = 1 } }));
+ testing.expect(u8 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .is_signed = false, .bits = 8 } }));
+ testing.expect(i8 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .is_signed = true, .bits = 8 } }));
+ testing.expect(u64 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .is_signed = false, .bits = 64 } }));
+ testing.expect(i64 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .is_signed = true, .bits = 64 } }));
+ testTypes([_]type{ u8, u32, i64 });
}
test "Type.Float" {
- testing.expect(f16 == @Type(TypeInfo { .Float = TypeInfo.Float { .bits = 16 } }));
- testing.expect(f32 == @Type(TypeInfo { .Float = TypeInfo.Float { .bits = 32 } }));
- testing.expect(f64 == @Type(TypeInfo { .Float = TypeInfo.Float { .bits = 64 } }));
- testing.expect(f128 == @Type(TypeInfo { .Float = TypeInfo.Float { .bits = 128 } }));
- testTypes([_]type {f16, f32, f64, f128});
+ testing.expect(f16 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 16 } }));
+ testing.expect(f32 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 32 } }));
+ testing.expect(f64 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 64 } }));
+ testing.expect(f128 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 128 } }));
+ testTypes([_]type{ f16, f32, f64, f128 });
}
test "Type.Pointer" {
- testTypes([_]type {
+ testTypes([_]type{
// One Value Pointer Types
- *u8, *const u8,
- *volatile u8, *const volatile u8,
- *align(4) u8, *const align(4) u8,
- *volatile align(4) u8, *const volatile align(4) u8,
- *align(8) u8, *const align(8) u8,
- *volatile align(8) u8, *const volatile align(8) u8,
- *allowzero u8, *const allowzero u8,
- *volatile allowzero u8, *const volatile allowzero u8,
- *align(4) allowzero u8, *const align(4) allowzero u8,
- *volatile align(4) allowzero u8, *const volatile align(4) allowzero u8,
+ *u8, *const u8,
+ *volatile u8, *const volatile u8,
+ *align(4) u8, *align(4) const u8,
+ *align(4) volatile u8, *align(4) const volatile u8,
+ *align(8) u8, *align(8) const u8,
+ *align(8) volatile u8, *align(8) const volatile u8,
+ *allowzero u8, *allowzero const u8,
+ *allowzero volatile u8, *allowzero const volatile u8,
+ *allowzero align(4) u8, *allowzero align(4) const u8,
+ *allowzero align(4) volatile u8, *allowzero align(4) const volatile u8,
// Many Values Pointer Types
- [*]u8, [*]const u8,
- [*]volatile u8, [*]const volatile u8,
- [*]align(4) u8, [*]const align(4) u8,
- [*]volatile align(4) u8, [*]const volatile align(4) u8,
- [*]align(8) u8, [*]const align(8) u8,
- [*]volatile align(8) u8, [*]const volatile align(8) u8,
- [*]allowzero u8, [*]const allowzero u8,
- [*]volatile allowzero u8, [*]const volatile allowzero u8,
- [*]align(4) allowzero u8, [*]const align(4) allowzero u8,
- [*]volatile align(4) allowzero u8, [*]const volatile align(4) allowzero u8,
+ [*]u8, [*]const u8,
+ [*]volatile u8, [*]const volatile u8,
+ [*]align(4) u8, [*]align(4) const u8,
+ [*]align(4) volatile u8, [*]align(4) const volatile u8,
+ [*]align(8) u8, [*]align(8) const u8,
+ [*]align(8) volatile u8, [*]align(8) const volatile u8,
+ [*]allowzero u8, [*]allowzero const u8,
+ [*]allowzero volatile u8, [*]allowzero const volatile u8,
+ [*]allowzero align(4) u8, [*]allowzero align(4) const u8,
+ [*]allowzero align(4) volatile u8, [*]allowzero align(4) const volatile u8,
// Slice Types
- []u8, []const u8,
- []volatile u8, []const volatile u8,
- []align(4) u8, []const align(4) u8,
- []volatile align(4) u8, []const volatile align(4) u8,
- []align(8) u8, []const align(8) u8,
- []volatile align(8) u8, []const volatile align(8) u8,
- []allowzero u8, []const allowzero u8,
- []volatile allowzero u8, []const volatile allowzero u8,
- []align(4) allowzero u8, []const align(4) allowzero u8,
- []volatile align(4) allowzero u8, []const volatile align(4) allowzero u8,
+ []u8, []const u8,
+ []volatile u8, []const volatile u8,
+ []align(4) u8, []align(4) const u8,
+ []align(4) volatile u8, []align(4) const volatile u8,
+ []align(8) u8, []align(8) const u8,
+ []align(8) volatile u8, []align(8) const volatile u8,
+ []allowzero u8, []allowzero const u8,
+ []allowzero volatile u8, []allowzero const volatile u8,
+ []allowzero align(4) u8, []allowzero align(4) const u8,
+ []allowzero align(4) volatile u8, []allowzero align(4) const volatile u8,
// C Pointer Types
- [*c]u8, [*c]const u8,
- [*c]volatile u8, [*c]const volatile u8,
- [*c]align(4) u8, [*c]const align(4) u8,
- [*c]volatile align(4) u8, [*c]const volatile align(4) u8,
- [*c]align(8) u8, [*c]const align(8) u8,
- [*c]volatile align(8) u8, [*c]const volatile align(8) u8,
+ [*c]u8, [*c]const u8,
+ [*c]volatile u8, [*c]const volatile u8,
+ [*c]align(4) u8, [*c]align(4) const u8,
+ [*c]align(4) volatile u8, [*c]align(4) const volatile u8,
+ [*c]align(8) u8, [*c]align(8) const u8,
+ [*c]align(8) volatile u8, [*c]align(8) const volatile u8,
});
}
test "Type.Array" {
- testing.expect([123]u8 == @Type(TypeInfo { .Array = TypeInfo.Array { .len = 123, .child = u8 } }));
- testing.expect([2]u32 == @Type(TypeInfo { .Array = TypeInfo.Array { .len = 2, .child = u32 } }));
- testTypes([_]type {[1]u8, [30]usize, [7]bool});
+ testing.expect([123]u8 == @Type(TypeInfo{
+ .Array = TypeInfo.Array{
+ .len = 123,
+ .child = u8,
+ .is_null_terminated = false,
+ },
+ }));
+ testing.expect([2]u32 == @Type(TypeInfo{
+ .Array = TypeInfo.Array{
+ .len = 2,
+ .child = u32,
+ .is_null_terminated = false,
+ },
+ }));
+ testing.expect([2]null u32 == @Type(TypeInfo{
+ .Array = TypeInfo.Array{
+ .len = 2,
+ .child = u32,
+ .is_null_terminated = true,
+ },
+ }));
+ testTypes([_]type{ [1]u8, [30]usize, [7]bool });
}
test "Type.ComptimeFloat" {
- testTypes([_]type {comptime_float});
+ testTypes([_]type{comptime_float});
}
test "Type.ComptimeInt" {
- testTypes([_]type {comptime_int});
+ testTypes([_]type{comptime_int});
}
test "Type.Undefined" {
- testTypes([_]type {@typeOf(undefined)});
+ testTypes([_]type{@typeOf(undefined)});
}
test "Type.Null" {
- testTypes([_]type {@typeOf(null)});
+ testTypes([_]type{@typeOf(null)});
}
diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig
index ed64e3e430..4da2bb3ca2 100644
--- a/test/stage1/behavior/type_info.zig
+++ b/test/stage1/behavior/type_info.zig
@@ -46,6 +46,7 @@ fn testPointer() void {
expect(u32_ptr_info.Pointer.is_volatile == false);
expect(u32_ptr_info.Pointer.alignment == @alignOf(u32));
expect(u32_ptr_info.Pointer.child == u32);
+ expect(u32_ptr_info.Pointer.is_null_terminated == false);
}
test "type info: unknown length pointer type info" {
@@ -55,14 +56,34 @@ test "type info: unknown length pointer type info" {
fn testUnknownLenPtr() void {
const u32_ptr_info = @typeInfo([*]const volatile f64);
- expect(@as(TypeId,u32_ptr_info) == TypeId.Pointer);
+ expect(@as(TypeId, u32_ptr_info) == TypeId.Pointer);
expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
expect(u32_ptr_info.Pointer.is_const == true);
expect(u32_ptr_info.Pointer.is_volatile == true);
+ expect(u32_ptr_info.Pointer.is_null_terminated == false);
expect(u32_ptr_info.Pointer.alignment == @alignOf(f64));
expect(u32_ptr_info.Pointer.child == f64);
}
+test "type info: null terminated pointer type info" {
+ testNullTerminatedPtr();
+ comptime testNullTerminatedPtr();
+}
+
+fn testNullTerminatedPtr() void {
+ const ptr_info = @typeInfo([*]null u8);
+ expect(@as(TypeId, ptr_info) == TypeId.Pointer);
+ expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
+ expect(ptr_info.Pointer.is_const == false);
+ expect(ptr_info.Pointer.is_volatile == false);
+ expect(ptr_info.Pointer.is_null_terminated == true);
+
+ expect(@typeInfo([]null u8).Pointer.is_null_terminated == true);
+ expect(@typeInfo([10]null u8).Array.is_null_terminated == true);
+ expect(@typeInfo([10]null u8).Array.len == 10);
+ expect(@sizeOf([10]null u8) == 11);
+}
+
test "type info: C pointer type info" {
testCPtr();
comptime testCPtr();
@@ -70,7 +91,7 @@ test "type info: C pointer type info" {
fn testCPtr() void {
const ptr_info = @typeInfo([*c]align(4) const i8);
- expect(@as(TypeId,ptr_info) == TypeId.Pointer);
+ expect(@as(TypeId, ptr_info) == TypeId.Pointer);
expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.C);
expect(ptr_info.Pointer.is_const);
expect(!ptr_info.Pointer.is_volatile);
@@ -288,13 +309,13 @@ test "type info: anyframe and anyframe->T" {
fn testAnyFrame() void {
{
const anyframe_info = @typeInfo(anyframe->i32);
- expect(@as(TypeId,anyframe_info) == .AnyFrame);
+ expect(@as(TypeId, anyframe_info) == .AnyFrame);
expect(anyframe_info.AnyFrame.child.? == i32);
}
{
const anyframe_info = @typeInfo(anyframe);
- expect(@as(TypeId,anyframe_info) == .AnyFrame);
+ expect(@as(TypeId, anyframe_info) == .AnyFrame);
expect(anyframe_info.AnyFrame.child == null);
}
}
@@ -334,7 +355,7 @@ test "type info: extern fns with and without lib names" {
if (std.mem.eql(u8, decl.name, "bar1")) {
expect(decl.data.Fn.lib_name == null);
} else {
- std.testing.expectEqual(@as([]const u8,"cool"), decl.data.Fn.lib_name.?);
+ std.testing.expectEqual(@as([]const u8, "cool"), decl.data.Fn.lib_name.?);
}
}
}
--
cgit v1.2.3
From 47f06be36943f808aa9798c19172363afe6ae35c Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 19 Nov 2019 20:29:08 -0500
Subject: string literals are now null terminated
this also deletes C string literals from the language, and then makes
the std lib changes and compiler changes necessary to get the behavior
tests and std lib tests passing again.
---
lib/std/child_process.zig | 2 +-
lib/std/crypto/x25519.zig | 12 +-
lib/std/cstr.zig | 4 +-
lib/std/fmt.zig | 112 ++++----
lib/std/fs.zig | 6 +-
lib/std/fs/file.zig | 2 +-
lib/std/fs/path.zig | 2 +-
lib/std/hash/siphash.zig | 256 ++++++++---------
lib/std/io/test.zig | 4 +-
lib/std/mem.zig | 18 +-
lib/std/meta.zig | 13 +-
lib/std/meta/trait.zig | 2 -
lib/std/net.zig | 16 +-
lib/std/os.zig | 4 +-
lib/std/os/linux.zig | 2 +-
lib/std/os/linux/test.zig | 4 +-
lib/std/process.zig | 16 +-
lib/std/special/c.zig | 10 +-
lib/std/thread.zig | 2 +-
lib/std/valgrind/memcheck.zig | 2 +-
src-self-hosted/codegen.zig | 6 +-
src-self-hosted/compilation.zig | 4 +-
src-self-hosted/ir.zig | 12 +-
src-self-hosted/link.zig | 126 ++++----
src-self-hosted/stage1.zig | 2 +-
src-self-hosted/value.zig | 2 +-
src/all_types.hpp | 9 +-
src/analyze.cpp | 141 +++++----
src/analyze.hpp | 9 +-
src/ast_render.cpp | 3 -
src/codegen.cpp | 61 ++--
src/ir.cpp | 448 +++++++++++++++++++++--------
src/parser.cpp | 1 -
src/tokenizer.cpp | 53 +---
src/tokenizer.hpp | 1 -
src/translate_c.cpp | 18 +-
test/compare_output.zig | 72 ++---
test/compile_errors.zig | 10 +-
test/stage1/behavior/array.zig | 39 ++-
test/stage1/behavior/bugs/1076.zig | 16 +-
test/stage1/behavior/cast.zig | 110 +++++--
test/stage1/behavior/const_slice_child.zig | 9 +-
test/stage1/behavior/eval.zig | 2 +-
test/stage1/behavior/misc.zig | 17 +-
test/stage1/behavior/pointers.zig | 2 +-
test/stage1/behavior/ptrcast.zig | 2 +-
test/stage1/behavior/slice.zig | 2 +-
test/stage1/behavior/struct.zig | 2 +-
test/stage2/compare_output.zig | 4 +-
test/standalone/hello_world/hello_libc.zig | 2 +-
test/translate_c.zig | 28 +-
51 files changed, 986 insertions(+), 716 deletions(-)
(limited to 'src/analyze.cpp')
diff --git a/lib/std/child_process.zig b/lib/std/child_process.zig
index d329855c03..50479016ac 100644
--- a/lib/std/child_process.zig
+++ b/lib/std/child_process.zig
@@ -328,7 +328,7 @@ pub const ChildProcess = struct {
const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);
const dev_null_fd = if (any_ignore)
- os.openC(c"/dev/null", os.O_RDWR, 0) catch |err| switch (err) {
+ os.openC("/dev/null", os.O_RDWR, 0) catch |err| switch (err) {
error.PathAlreadyExists => unreachable,
error.NoSpaceLeft => unreachable,
error.FileTooBig => unreachable,
diff --git a/lib/std/crypto/x25519.zig b/lib/std/crypto/x25519.zig
index cd908b0868..73e0f033f2 100644
--- a/lib/std/crypto/x25519.zig
+++ b/lib/std/crypto/x25519.zig
@@ -610,8 +610,8 @@ test "x25519 rfc7748 vector2" {
}
test "x25519 rfc7748 one iteration" {
- const initial_value = "\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
- const expected_output = "\x42\x2c\x8e\x7a\x62\x27\xd7\xbc\xa1\x35\x0b\x3e\x2b\xb7\x27\x9f\x78\x97\xb8\x7b\xb6\x85\x4b\x78\x3c\x60\xe8\x03\x11\xae\x30\x79";
+ const initial_value = "\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".*;
+ const expected_output = "\x42\x2c\x8e\x7a\x62\x27\xd7\xbc\xa1\x35\x0b\x3e\x2b\xb7\x27\x9f\x78\x97\xb8\x7b\xb6\x85\x4b\x78\x3c\x60\xe8\x03\x11\xae\x30\x79".*;
var k: [32]u8 = initial_value;
var u: [32]u8 = initial_value;
@@ -634,8 +634,8 @@ test "x25519 rfc7748 1,000 iterations" {
return error.SkipZigTest;
}
- const initial_value = "\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
- const expected_output = "\x68\x4c\xf5\x9b\xa8\x33\x09\x55\x28\x00\xef\x56\x6f\x2f\x4d\x3c\x1c\x38\x87\xc4\x93\x60\xe3\x87\x5f\x2e\xb9\x4d\x99\x53\x2c\x51";
+ const initial_value = "\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".*;
+ const expected_output = "\x68\x4c\xf5\x9b\xa8\x33\x09\x55\x28\x00\xef\x56\x6f\x2f\x4d\x3c\x1c\x38\x87\xc4\x93\x60\xe3\x87\x5f\x2e\xb9\x4d\x99\x53\x2c\x51".*;
var k: [32]u8 = initial_value;
var u: [32]u8 = initial_value;
@@ -657,8 +657,8 @@ test "x25519 rfc7748 1,000,000 iterations" {
return error.SkipZigTest;
}
- const initial_value = "\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
- const expected_output = "\x7c\x39\x11\xe0\xab\x25\x86\xfd\x86\x44\x97\x29\x7e\x57\x5e\x6f\x3b\xc6\x01\xc0\x88\x3c\x30\xdf\x5f\x4d\xd2\xd2\x4f\x66\x54\x24";
+ const initial_value = "\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".*;
+ const expected_output = "\x7c\x39\x11\xe0\xab\x25\x86\xfd\x86\x44\x97\x29\x7e\x57\x5e\x6f\x3b\xc6\x01\xc0\x88\x3c\x30\xdf\x5f\x4d\xd2\xd2\x4f\x66\x54\x24".*;
var k: [32]u8 = initial_value;
var u: [32]u8 = initial_value;
diff --git a/lib/std/cstr.zig b/lib/std/cstr.zig
index dd28e50449..4229ff3ed5 100644
--- a/lib/std/cstr.zig
+++ b/lib/std/cstr.zig
@@ -27,8 +27,8 @@ test "cstr fns" {
}
fn testCStrFnsImpl() void {
- testing.expect(cmp(c"aoeu", c"aoez") == -1);
- testing.expect(mem.len(u8, c"123456789") == 9);
+ testing.expect(cmp("aoeu", "aoez") == -1);
+ testing.expect(mem.len(u8, "123456789") == 9);
}
/// Returns a mutable slice with 1 more byte of length which is a null byte.
diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig
index 743ca4d920..cbb11cba36 100644
--- a/lib/std/fmt.zig
+++ b/lib/std/fmt.zig
@@ -1,8 +1,6 @@
const std = @import("std.zig");
const math = std.math;
-const debug = std.debug;
-const assert = debug.assert;
-const testing = std.testing;
+const assert = std.debug.assert;
const mem = std.mem;
const builtin = @import("builtin");
const errol = @import("fmt/errol.zig");
@@ -36,7 +34,7 @@ fn nextArg(comptime used_pos_args: *u32, comptime maybe_pos_arg: ?comptime_int,
fn peekIsAlign(comptime fmt: []const u8) bool {
// Should only be called during a state transition to the format segment.
- std.debug.assert(fmt[0] == ':');
+ comptime assert(fmt[0] == ':');
inline for (([_]u8{ 1, 2 })[0..]) |i| {
if (fmt.len > i and (fmt[i] == '<' or fmt[i] == '^' or fmt[i] == '>')) {
@@ -1009,13 +1007,13 @@ pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {
}
test "parseInt" {
- testing.expect((parseInt(i32, "-10", 10) catch unreachable) == -10);
- testing.expect((parseInt(i32, "+10", 10) catch unreachable) == 10);
- testing.expect(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidCharacter);
- testing.expect(if (parseInt(i32, "10 ", 10)) |_| false else |err| err == error.InvalidCharacter);
- testing.expect(if (parseInt(u32, "-10", 10)) |_| false else |err| err == error.InvalidCharacter);
- testing.expect((parseInt(u8, "255", 10) catch unreachable) == 255);
- testing.expect(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow);
+ std.testing.expect((parseInt(i32, "-10", 10) catch unreachable) == -10);
+ std.testing.expect((parseInt(i32, "+10", 10) catch unreachable) == 10);
+ std.testing.expect(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidCharacter);
+ std.testing.expect(if (parseInt(i32, "10 ", 10)) |_| false else |err| err == error.InvalidCharacter);
+ std.testing.expect(if (parseInt(u32, "-10", 10)) |_| false else |err| err == error.InvalidCharacter);
+ std.testing.expect((parseInt(u8, "255", 10) catch unreachable) == 255);
+ std.testing.expect(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow);
}
const ParseUnsignedError = error{
@@ -1040,30 +1038,30 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned
}
test "parseUnsigned" {
- testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124);
- testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535);
- testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10));
+ std.testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124);
+ std.testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535);
+ std.testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10));
- testing.expect((try parseUnsigned(u64, "0ffffffffffffffff", 16)) == 0xffffffffffffffff);
- testing.expectError(error.Overflow, parseUnsigned(u64, "10000000000000000", 16));
+ std.testing.expect((try parseUnsigned(u64, "0ffffffffffffffff", 16)) == 0xffffffffffffffff);
+ std.testing.expectError(error.Overflow, parseUnsigned(u64, "10000000000000000", 16));
- testing.expect((try parseUnsigned(u32, "DeadBeef", 16)) == 0xDEADBEEF);
+ std.testing.expect((try parseUnsigned(u32, "DeadBeef", 16)) == 0xDEADBEEF);
- testing.expect((try parseUnsigned(u7, "1", 10)) == 1);
- testing.expect((try parseUnsigned(u7, "1000", 2)) == 8);
+ std.testing.expect((try parseUnsigned(u7, "1", 10)) == 1);
+ std.testing.expect((try parseUnsigned(u7, "1000", 2)) == 8);
- testing.expectError(error.InvalidCharacter, parseUnsigned(u32, "f", 10));
- testing.expectError(error.InvalidCharacter, parseUnsigned(u8, "109", 8));
+ std.testing.expectError(error.InvalidCharacter, parseUnsigned(u32, "f", 10));
+ std.testing.expectError(error.InvalidCharacter, parseUnsigned(u8, "109", 8));
- testing.expect((try parseUnsigned(u32, "NUMBER", 36)) == 1442151747);
+ std.testing.expect((try parseUnsigned(u32, "NUMBER", 36)) == 1442151747);
// these numbers should fit even though the radix itself doesn't fit in the destination type
- testing.expect((try parseUnsigned(u1, "0", 10)) == 0);
- testing.expect((try parseUnsigned(u1, "1", 10)) == 1);
- testing.expectError(error.Overflow, parseUnsigned(u1, "2", 10));
- testing.expect((try parseUnsigned(u1, "001", 16)) == 1);
- testing.expect((try parseUnsigned(u2, "3", 16)) == 3);
- testing.expectError(error.Overflow, parseUnsigned(u2, "4", 16));
+ std.testing.expect((try parseUnsigned(u1, "0", 10)) == 0);
+ std.testing.expect((try parseUnsigned(u1, "1", 10)) == 1);
+ std.testing.expectError(error.Overflow, parseUnsigned(u1, "2", 10));
+ std.testing.expect((try parseUnsigned(u1, "001", 16)) == 1);
+ std.testing.expect((try parseUnsigned(u2, "3", 16)) == 3);
+ std.testing.expectError(error.Overflow, parseUnsigned(u2, "4", 16));
}
pub const parseFloat = @import("fmt/parse_float.zig").parseFloat;
@@ -1134,19 +1132,19 @@ fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
test "bufPrintInt" {
var buffer: [100]u8 = undefined;
const buf = buffer[0..];
- testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(i32, -12345678), 2, false, FormatOptions{}), "-101111000110000101001110"));
- testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(i32, -12345678), 10, false, FormatOptions{}), "-12345678"));
- testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(i32, -12345678), 16, false, FormatOptions{}), "-bc614e"));
- testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(i32, -12345678), 16, true, FormatOptions{}), "-BC614E"));
+ std.testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(i32, -12345678), 2, false, FormatOptions{}), "-101111000110000101001110"));
+ std.testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(i32, -12345678), 10, false, FormatOptions{}), "-12345678"));
+ std.testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(i32, -12345678), 16, false, FormatOptions{}), "-bc614e"));
+ std.testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(i32, -12345678), 16, true, FormatOptions{}), "-BC614E"));
- testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(u32, 12345678), 10, true, FormatOptions{}), "12345678"));
+ std.testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(u32, 12345678), 10, true, FormatOptions{}), "12345678"));
- testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(u32, 666), 10, false, FormatOptions{ .width = 6 }), " 666"));
- testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(u32, 0x1234), 16, false, FormatOptions{ .width = 6 }), " 1234"));
- testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(u32, 0x1234), 16, false, FormatOptions{ .width = 1 }), "1234"));
+ std.testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(u32, 666), 10, false, FormatOptions{ .width = 6 }), " 666"));
+ std.testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(u32, 0x1234), 16, false, FormatOptions{ .width = 6 }), " 1234"));
+ std.testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(u32, 0x1234), 16, false, FormatOptions{ .width = 1 }), "1234"));
- testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(i32, 42), 10, false, FormatOptions{ .width = 3 }), "+42"));
- testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(i32, -42), 10, false, FormatOptions{ .width = 3 }), "-42"));
+ std.testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(i32, 42), 10, false, FormatOptions{ .width = 3 }), "+42"));
+ std.testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(i32, -42), 10, false, FormatOptions{ .width = 3 }), "-42"));
}
fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, options: FormatOptions) []u8 {
@@ -1163,7 +1161,7 @@ test "parse u64 digit too big" {
test "parse unsigned comptime" {
comptime {
- testing.expect((try parseUnsigned(usize, "2", 10)) == 2);
+ std.testing.expect((try parseUnsigned(usize, "2", 10)) == 2);
}
}
@@ -1218,23 +1216,23 @@ test "buffer" {
var context = BufPrintContext{ .remaining = buf1[0..] };
try formatType(1234, "", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
var res = buf1[0 .. buf1.len - context.remaining.len];
- testing.expect(mem.eql(u8, res, "1234"));
+ std.testing.expect(mem.eql(u8, res, "1234"));
context = BufPrintContext{ .remaining = buf1[0..] };
try formatType('a', "c", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
res = buf1[0 .. buf1.len - context.remaining.len];
- testing.expect(mem.eql(u8, res, "a"));
+ std.testing.expect(mem.eql(u8, res, "a"));
context = BufPrintContext{ .remaining = buf1[0..] };
try formatType(0b1100, "b", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
res = buf1[0 .. buf1.len - context.remaining.len];
- testing.expect(mem.eql(u8, res, "1100"));
+ std.testing.expect(mem.eql(u8, res, "1100"));
}
}
test "array" {
{
- const value: [3]u8 = "abc";
+ const value: [3]u8 = "abc".*;
try testFmt("array: abc\n", "array: {}\n", value);
try testFmt("array: abc\n", "array: {}\n", &value);
@@ -1278,8 +1276,8 @@ test "pointer" {
}
test "cstr" {
- try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C");
- try testFmt("cstr: Test C \n", "cstr: {s:10}\n", c"Test C");
+ try testFmt("cstr: Test C\n", "cstr: {s}\n", "Test C");
+ try testFmt("cstr: Test C \n", "cstr: {s:10}\n", "Test C");
}
test "filesize" {
@@ -1479,10 +1477,10 @@ test "union" {
var buf: [100]u8 = undefined;
const uu_result = try bufPrint(buf[0..], "{}", uu_inst);
- testing.expect(mem.eql(u8, uu_result[0..3], "UU@"));
+ std.testing.expect(mem.eql(u8, uu_result[0..3], "UU@"));
const eu_result = try bufPrint(buf[0..], "{}", eu_inst);
- testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));
+ std.testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));
}
test "enum" {
@@ -1569,11 +1567,11 @@ pub fn trim(buf: []const u8) []const u8 {
}
test "trim" {
- testing.expect(mem.eql(u8, "abc", trim("\n abc \t")));
- testing.expect(mem.eql(u8, "", trim(" ")));
- testing.expect(mem.eql(u8, "", trim("")));
- testing.expect(mem.eql(u8, "abc", trim(" abc")));
- testing.expect(mem.eql(u8, "abc", trim("abc ")));
+ std.testing.expect(mem.eql(u8, "abc", trim("\n abc \t")));
+ std.testing.expect(mem.eql(u8, "", trim(" ")));
+ std.testing.expect(mem.eql(u8, "", trim("")));
+ std.testing.expect(mem.eql(u8, "abc", trim(" abc")));
+ std.testing.expect(mem.eql(u8, "abc", trim("abc ")));
}
pub fn isWhiteSpace(byte: u8) bool {
@@ -1607,7 +1605,7 @@ test "formatIntValue with comptime_int" {
var buf = try std.Buffer.init(std.debug.global_allocator, "");
try formatIntValue(value, "", FormatOptions{}, &buf, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append);
- assert(mem.eql(u8, buf.toSlice(), "123456789123456789"));
+ std.testing.expect(mem.eql(u8, buf.toSlice(), "123456789123456789"));
}
test "formatType max_depth" {
@@ -1661,19 +1659,19 @@ test "formatType max_depth" {
var buf0 = try std.Buffer.init(std.debug.global_allocator, "");
try formatType(inst, "", FormatOptions{}, &buf0, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 0);
- assert(mem.eql(u8, buf0.toSlice(), "S{ ... }"));
+ std.testing.expect(mem.eql(u8, buf0.toSlice(), "S{ ... }"));
var buf1 = try std.Buffer.init(std.debug.global_allocator, "");
try formatType(inst, "", FormatOptions{}, &buf1, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 1);
- assert(mem.eql(u8, buf1.toSlice(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));
+ std.testing.expect(mem.eql(u8, buf1.toSlice(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));
var buf2 = try std.Buffer.init(std.debug.global_allocator, "");
try formatType(inst, "", FormatOptions{}, &buf2, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 2);
- assert(mem.eql(u8, buf2.toSlice(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }"));
+ std.testing.expect(mem.eql(u8, buf2.toSlice(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }"));
var buf3 = try std.Buffer.init(std.debug.global_allocator, "");
try formatType(inst, "", FormatOptions{}, &buf3, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 3);
- assert(mem.eql(u8, buf3.toSlice(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }"));
+ std.testing.expect(mem.eql(u8, buf3.toSlice(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }"));
}
test "positional" {
diff --git a/lib/std/fs.zig b/lib/std/fs.zig
index bc2c921d1e..0b9c6559d7 100644
--- a/lib/std/fs.zig
+++ b/lib/std/fs.zig
@@ -1240,7 +1240,7 @@ pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfE
pub fn openSelfExe() OpenSelfExeError!File {
if (builtin.os == .linux) {
- return File.openReadC(c"/proc/self/exe");
+ return File.openReadC("/proc/self/exe");
}
if (builtin.os == .windows) {
const wide_slice = selfExePathW();
@@ -1280,7 +1280,7 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]u8 {
return mem.toSlice(u8, out_buffer);
}
switch (builtin.os) {
- .linux => return os.readlinkC(c"/proc/self/exe", out_buffer),
+ .linux => return os.readlinkC("/proc/self/exe", out_buffer),
.freebsd, .dragonfly => {
var mib = [4]c_int{ os.CTL_KERN, os.KERN_PROC, os.KERN_PROC_PATHNAME, -1 };
var out_len: usize = out_buffer.len;
@@ -1326,7 +1326,7 @@ pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]const
// the file path looks something like `/a/b/c/exe (deleted)`
// This path cannot be opened, but it's valid for determining the directory
// the executable was in when it was run.
- const full_exe_path = try os.readlinkC(c"/proc/self/exe", out_buffer);
+ const full_exe_path = try os.readlinkC("/proc/self/exe", out_buffer);
// Assume that /proc/self/exe has an absolute path, and therefore dirname
// will not return null.
return path.dirname(full_exe_path).?;
diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig
index b25403fa02..cd50fcdece 100644
--- a/lib/std/fs/file.zig
+++ b/lib/std/fs/file.zig
@@ -172,7 +172,7 @@ pub const File = struct {
if (self.isTty()) {
if (self.handle == os.STDOUT_FILENO or self.handle == os.STDERR_FILENO) {
// Use getenvC to workaround https://github.com/ziglang/zig/issues/3511
- if (os.getenvC(c"TERM")) |term| {
+ if (os.getenvC("TERM")) |term| {
if (std.mem.eql(u8, term, "dumb"))
return false;
}
diff --git a/lib/std/fs/path.zig b/lib/std/fs/path.zig
index 6a24055667..e2f1b5ac65 100644
--- a/lib/std/fs/path.zig
+++ b/lib/std/fs/path.zig
@@ -394,7 +394,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
}
// determine which disk designator we will result with, if any
- var result_drive_buf = "_:";
+ var result_drive_buf = "_:".*;
var result_disk_designator: []const u8 = "";
var have_drive_kind = WindowsPath.Kind.None;
var have_abs_path = false;
diff --git a/lib/std/hash/siphash.zig b/lib/std/hash/siphash.zig
index c3a9184fa4..6b4cc2b16b 100644
--- a/lib/std/hash/siphash.zig
+++ b/lib/std/hash/siphash.zig
@@ -202,70 +202,70 @@ const test_key = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x
test "siphash64-2-4 sanity" {
const vectors = [_][8]u8{
- "\x31\x0e\x0e\xdd\x47\xdb\x6f\x72", // ""
- "\xfd\x67\xdc\x93\xc5\x39\xf8\x74", // "\x00"
- "\x5a\x4f\xa9\xd9\x09\x80\x6c\x0d", // "\x00\x01" ... etc
- "\x2d\x7e\xfb\xd7\x96\x66\x67\x85",
- "\xb7\x87\x71\x27\xe0\x94\x27\xcf",
- "\x8d\xa6\x99\xcd\x64\x55\x76\x18",
- "\xce\xe3\xfe\x58\x6e\x46\xc9\xcb",
- "\x37\xd1\x01\x8b\xf5\x00\x02\xab",
- "\x62\x24\x93\x9a\x79\xf5\xf5\x93",
- "\xb0\xe4\xa9\x0b\xdf\x82\x00\x9e",
- "\xf3\xb9\xdd\x94\xc5\xbb\x5d\x7a",
- "\xa7\xad\x6b\x22\x46\x2f\xb3\xf4",
- "\xfb\xe5\x0e\x86\xbc\x8f\x1e\x75",
- "\x90\x3d\x84\xc0\x27\x56\xea\x14",
- "\xee\xf2\x7a\x8e\x90\xca\x23\xf7",
- "\xe5\x45\xbe\x49\x61\xca\x29\xa1",
- "\xdb\x9b\xc2\x57\x7f\xcc\x2a\x3f",
- "\x94\x47\xbe\x2c\xf5\xe9\x9a\x69",
- "\x9c\xd3\x8d\x96\xf0\xb3\xc1\x4b",
- "\xbd\x61\x79\xa7\x1d\xc9\x6d\xbb",
- "\x98\xee\xa2\x1a\xf2\x5c\xd6\xbe",
- "\xc7\x67\x3b\x2e\xb0\xcb\xf2\xd0",
- "\x88\x3e\xa3\xe3\x95\x67\x53\x93",
- "\xc8\xce\x5c\xcd\x8c\x03\x0c\xa8",
- "\x94\xaf\x49\xf6\xc6\x50\xad\xb8",
- "\xea\xb8\x85\x8a\xde\x92\xe1\xbc",
- "\xf3\x15\xbb\x5b\xb8\x35\xd8\x17",
- "\xad\xcf\x6b\x07\x63\x61\x2e\x2f",
- "\xa5\xc9\x1d\xa7\xac\xaa\x4d\xde",
- "\x71\x65\x95\x87\x66\x50\xa2\xa6",
- "\x28\xef\x49\x5c\x53\xa3\x87\xad",
- "\x42\xc3\x41\xd8\xfa\x92\xd8\x32",
- "\xce\x7c\xf2\x72\x2f\x51\x27\x71",
- "\xe3\x78\x59\xf9\x46\x23\xf3\xa7",
- "\x38\x12\x05\xbb\x1a\xb0\xe0\x12",
- "\xae\x97\xa1\x0f\xd4\x34\xe0\x15",
- "\xb4\xa3\x15\x08\xbe\xff\x4d\x31",
- "\x81\x39\x62\x29\xf0\x90\x79\x02",
- "\x4d\x0c\xf4\x9e\xe5\xd4\xdc\xca",
- "\x5c\x73\x33\x6a\x76\xd8\xbf\x9a",
- "\xd0\xa7\x04\x53\x6b\xa9\x3e\x0e",
- "\x92\x59\x58\xfc\xd6\x42\x0c\xad",
- "\xa9\x15\xc2\x9b\xc8\x06\x73\x18",
- "\x95\x2b\x79\xf3\xbc\x0a\xa6\xd4",
- "\xf2\x1d\xf2\xe4\x1d\x45\x35\xf9",
- "\x87\x57\x75\x19\x04\x8f\x53\xa9",
- "\x10\xa5\x6c\xf5\xdf\xcd\x9a\xdb",
- "\xeb\x75\x09\x5c\xcd\x98\x6c\xd0",
- "\x51\xa9\xcb\x9e\xcb\xa3\x12\xe6",
- "\x96\xaf\xad\xfc\x2c\xe6\x66\xc7",
- "\x72\xfe\x52\x97\x5a\x43\x64\xee",
- "\x5a\x16\x45\xb2\x76\xd5\x92\xa1",
- "\xb2\x74\xcb\x8e\xbf\x87\x87\x0a",
- "\x6f\x9b\xb4\x20\x3d\xe7\xb3\x81",
- "\xea\xec\xb2\xa3\x0b\x22\xa8\x7f",
- "\x99\x24\xa4\x3c\xc1\x31\x57\x24",
- "\xbd\x83\x8d\x3a\xaf\xbf\x8d\xb7",
- "\x0b\x1a\x2a\x32\x65\xd5\x1a\xea",
- "\x13\x50\x79\xa3\x23\x1c\xe6\x60",
- "\x93\x2b\x28\x46\xe4\xd7\x06\x66",
- "\xe1\x91\x5f\x5c\xb1\xec\xa4\x6c",
- "\xf3\x25\x96\x5c\xa1\x6d\x62\x9f",
- "\x57\x5f\xf2\x8e\x60\x38\x1b\xe5",
- "\x72\x45\x06\xeb\x4c\x32\x8a\x95",
+ "\x31\x0e\x0e\xdd\x47\xdb\x6f\x72".*, // ""
+ "\xfd\x67\xdc\x93\xc5\x39\xf8\x74".*, // "\x00"
+ "\x5a\x4f\xa9\xd9\x09\x80\x6c\x0d".*, // "\x00\x01" ... etc
+ "\x2d\x7e\xfb\xd7\x96\x66\x67\x85".*,
+ "\xb7\x87\x71\x27\xe0\x94\x27\xcf".*,
+ "\x8d\xa6\x99\xcd\x64\x55\x76\x18".*,
+ "\xce\xe3\xfe\x58\x6e\x46\xc9\xcb".*,
+ "\x37\xd1\x01\x8b\xf5\x00\x02\xab".*,
+ "\x62\x24\x93\x9a\x79\xf5\xf5\x93".*,
+ "\xb0\xe4\xa9\x0b\xdf\x82\x00\x9e".*,
+ "\xf3\xb9\xdd\x94\xc5\xbb\x5d\x7a".*,
+ "\xa7\xad\x6b\x22\x46\x2f\xb3\xf4".*,
+ "\xfb\xe5\x0e\x86\xbc\x8f\x1e\x75".*,
+ "\x90\x3d\x84\xc0\x27\x56\xea\x14".*,
+ "\xee\xf2\x7a\x8e\x90\xca\x23\xf7".*,
+ "\xe5\x45\xbe\x49\x61\xca\x29\xa1".*,
+ "\xdb\x9b\xc2\x57\x7f\xcc\x2a\x3f".*,
+ "\x94\x47\xbe\x2c\xf5\xe9\x9a\x69".*,
+ "\x9c\xd3\x8d\x96\xf0\xb3\xc1\x4b".*,
+ "\xbd\x61\x79\xa7\x1d\xc9\x6d\xbb".*,
+ "\x98\xee\xa2\x1a\xf2\x5c\xd6\xbe".*,
+ "\xc7\x67\x3b\x2e\xb0\xcb\xf2\xd0".*,
+ "\x88\x3e\xa3\xe3\x95\x67\x53\x93".*,
+ "\xc8\xce\x5c\xcd\x8c\x03\x0c\xa8".*,
+ "\x94\xaf\x49\xf6\xc6\x50\xad\xb8".*,
+ "\xea\xb8\x85\x8a\xde\x92\xe1\xbc".*,
+ "\xf3\x15\xbb\x5b\xb8\x35\xd8\x17".*,
+ "\xad\xcf\x6b\x07\x63\x61\x2e\x2f".*,
+ "\xa5\xc9\x1d\xa7\xac\xaa\x4d\xde".*,
+ "\x71\x65\x95\x87\x66\x50\xa2\xa6".*,
+ "\x28\xef\x49\x5c\x53\xa3\x87\xad".*,
+ "\x42\xc3\x41\xd8\xfa\x92\xd8\x32".*,
+ "\xce\x7c\xf2\x72\x2f\x51\x27\x71".*,
+ "\xe3\x78\x59\xf9\x46\x23\xf3\xa7".*,
+ "\x38\x12\x05\xbb\x1a\xb0\xe0\x12".*,
+ "\xae\x97\xa1\x0f\xd4\x34\xe0\x15".*,
+ "\xb4\xa3\x15\x08\xbe\xff\x4d\x31".*,
+ "\x81\x39\x62\x29\xf0\x90\x79\x02".*,
+ "\x4d\x0c\xf4\x9e\xe5\xd4\xdc\xca".*,
+ "\x5c\x73\x33\x6a\x76\xd8\xbf\x9a".*,
+ "\xd0\xa7\x04\x53\x6b\xa9\x3e\x0e".*,
+ "\x92\x59\x58\xfc\xd6\x42\x0c\xad".*,
+ "\xa9\x15\xc2\x9b\xc8\x06\x73\x18".*,
+ "\x95\x2b\x79\xf3\xbc\x0a\xa6\xd4".*,
+ "\xf2\x1d\xf2\xe4\x1d\x45\x35\xf9".*,
+ "\x87\x57\x75\x19\x04\x8f\x53\xa9".*,
+ "\x10\xa5\x6c\xf5\xdf\xcd\x9a\xdb".*,
+ "\xeb\x75\x09\x5c\xcd\x98\x6c\xd0".*,
+ "\x51\xa9\xcb\x9e\xcb\xa3\x12\xe6".*,
+ "\x96\xaf\xad\xfc\x2c\xe6\x66\xc7".*,
+ "\x72\xfe\x52\x97\x5a\x43\x64\xee".*,
+ "\x5a\x16\x45\xb2\x76\xd5\x92\xa1".*,
+ "\xb2\x74\xcb\x8e\xbf\x87\x87\x0a".*,
+ "\x6f\x9b\xb4\x20\x3d\xe7\xb3\x81".*,
+ "\xea\xec\xb2\xa3\x0b\x22\xa8\x7f".*,
+ "\x99\x24\xa4\x3c\xc1\x31\x57\x24".*,
+ "\xbd\x83\x8d\x3a\xaf\xbf\x8d\xb7".*,
+ "\x0b\x1a\x2a\x32\x65\xd5\x1a\xea".*,
+ "\x13\x50\x79\xa3\x23\x1c\xe6\x60".*,
+ "\x93\x2b\x28\x46\xe4\xd7\x06\x66".*,
+ "\xe1\x91\x5f\x5c\xb1\xec\xa4\x6c".*,
+ "\xf3\x25\x96\x5c\xa1\x6d\x62\x9f".*,
+ "\x57\x5f\xf2\x8e\x60\x38\x1b\xe5".*,
+ "\x72\x45\x06\xeb\x4c\x32\x8a\x95".*,
};
const siphash = SipHash64(2, 4);
@@ -281,70 +281,70 @@ test "siphash64-2-4 sanity" {
test "siphash128-2-4 sanity" {
const vectors = [_][16]u8{
- "\xa3\x81\x7f\x04\xba\x25\xa8\xe6\x6d\xf6\x72\x14\xc7\x55\x02\x93",
- "\xda\x87\xc1\xd8\x6b\x99\xaf\x44\x34\x76\x59\x11\x9b\x22\xfc\x45",
- "\x81\x77\x22\x8d\xa4\xa4\x5d\xc7\xfc\xa3\x8b\xde\xf6\x0a\xff\xe4",
- "\x9c\x70\xb6\x0c\x52\x67\xa9\x4e\x5f\x33\xb6\xb0\x29\x85\xed\x51",
- "\xf8\x81\x64\xc1\x2d\x9c\x8f\xaf\x7d\x0f\x6e\x7c\x7b\xcd\x55\x79",
- "\x13\x68\x87\x59\x80\x77\x6f\x88\x54\x52\x7a\x07\x69\x0e\x96\x27",
- "\x14\xee\xca\x33\x8b\x20\x86\x13\x48\x5e\xa0\x30\x8f\xd7\xa1\x5e",
- "\xa1\xf1\xeb\xbe\xd8\xdb\xc1\x53\xc0\xb8\x4a\xa6\x1f\xf0\x82\x39",
- "\x3b\x62\xa9\xba\x62\x58\xf5\x61\x0f\x83\xe2\x64\xf3\x14\x97\xb4",
- "\x26\x44\x99\x06\x0a\xd9\xba\xab\xc4\x7f\x8b\x02\xbb\x6d\x71\xed",
- "\x00\x11\x0d\xc3\x78\x14\x69\x56\xc9\x54\x47\xd3\xf3\xd0\xfb\xba",
- "\x01\x51\xc5\x68\x38\x6b\x66\x77\xa2\xb4\xdc\x6f\x81\xe5\xdc\x18",
- "\xd6\x26\xb2\x66\x90\x5e\xf3\x58\x82\x63\x4d\xf6\x85\x32\xc1\x25",
- "\x98\x69\xe2\x47\xe9\xc0\x8b\x10\xd0\x29\x93\x4f\xc4\xb9\x52\xf7",
- "\x31\xfc\xef\xac\x66\xd7\xde\x9c\x7e\xc7\x48\x5f\xe4\x49\x49\x02",
- "\x54\x93\xe9\x99\x33\xb0\xa8\x11\x7e\x08\xec\x0f\x97\xcf\xc3\xd9",
- "\x6e\xe2\xa4\xca\x67\xb0\x54\xbb\xfd\x33\x15\xbf\x85\x23\x05\x77",
- "\x47\x3d\x06\xe8\x73\x8d\xb8\x98\x54\xc0\x66\xc4\x7a\xe4\x77\x40",
- "\xa4\x26\xe5\xe4\x23\xbf\x48\x85\x29\x4d\xa4\x81\xfe\xae\xf7\x23",
- "\x78\x01\x77\x31\xcf\x65\xfa\xb0\x74\xd5\x20\x89\x52\x51\x2e\xb1",
- "\x9e\x25\xfc\x83\x3f\x22\x90\x73\x3e\x93\x44\xa5\xe8\x38\x39\xeb",
- "\x56\x8e\x49\x5a\xbe\x52\x5a\x21\x8a\x22\x14\xcd\x3e\x07\x1d\x12",
- "\x4a\x29\xb5\x45\x52\xd1\x6b\x9a\x46\x9c\x10\x52\x8e\xff\x0a\xae",
- "\xc9\xd1\x84\xdd\xd5\xa9\xf5\xe0\xcf\x8c\xe2\x9a\x9a\xbf\x69\x1c",
- "\x2d\xb4\x79\xae\x78\xbd\x50\xd8\x88\x2a\x8a\x17\x8a\x61\x32\xad",
- "\x8e\xce\x5f\x04\x2d\x5e\x44\x7b\x50\x51\xb9\xea\xcb\x8d\x8f\x6f",
- "\x9c\x0b\x53\xb4\xb3\xc3\x07\xe8\x7e\xae\xe0\x86\x78\x14\x1f\x66",
- "\xab\xf2\x48\xaf\x69\xa6\xea\xe4\xbf\xd3\xeb\x2f\x12\x9e\xeb\x94",
- "\x06\x64\xda\x16\x68\x57\x4b\x88\xb9\x35\xf3\x02\x73\x58\xae\xf4",
- "\xaa\x4b\x9d\xc4\xbf\x33\x7d\xe9\x0c\xd4\xfd\x3c\x46\x7c\x6a\xb7",
- "\xea\x5c\x7f\x47\x1f\xaf\x6b\xde\x2b\x1a\xd7\xd4\x68\x6d\x22\x87",
- "\x29\x39\xb0\x18\x32\x23\xfa\xfc\x17\x23\xde\x4f\x52\xc4\x3d\x35",
- "\x7c\x39\x56\xca\x5e\xea\xfc\x3e\x36\x3e\x9d\x55\x65\x46\xeb\x68",
- "\x77\xc6\x07\x71\x46\xf0\x1c\x32\xb6\xb6\x9d\x5f\x4e\xa9\xff\xcf",
- "\x37\xa6\x98\x6c\xb8\x84\x7e\xdf\x09\x25\xf0\xf1\x30\x9b\x54\xde",
- "\xa7\x05\xf0\xe6\x9d\xa9\xa8\xf9\x07\x24\x1a\x2e\x92\x3c\x8c\xc8",
- "\x3d\xc4\x7d\x1f\x29\xc4\x48\x46\x1e\x9e\x76\xed\x90\x4f\x67\x11",
- "\x0d\x62\xbf\x01\xe6\xfc\x0e\x1a\x0d\x3c\x47\x51\xc5\xd3\x69\x2b",
- "\x8c\x03\x46\x8b\xca\x7c\x66\x9e\xe4\xfd\x5e\x08\x4b\xbe\xe7\xb5",
- "\x52\x8a\x5b\xb9\x3b\xaf\x2c\x9c\x44\x73\xcc\xe5\xd0\xd2\x2b\xd9",
- "\xdf\x6a\x30\x1e\x95\xc9\x5d\xad\x97\xae\x0c\xc8\xc6\x91\x3b\xd8",
- "\x80\x11\x89\x90\x2c\x85\x7f\x39\xe7\x35\x91\x28\x5e\x70\xb6\xdb",
- "\xe6\x17\x34\x6a\xc9\xc2\x31\xbb\x36\x50\xae\x34\xcc\xca\x0c\x5b",
- "\x27\xd9\x34\x37\xef\xb7\x21\xaa\x40\x18\x21\xdc\xec\x5a\xdf\x89",
- "\x89\x23\x7d\x9d\xed\x9c\x5e\x78\xd8\xb1\xc9\xb1\x66\xcc\x73\x42",
- "\x4a\x6d\x80\x91\xbf\x5e\x7d\x65\x11\x89\xfa\x94\xa2\x50\xb1\x4c",
- "\x0e\x33\xf9\x60\x55\xe7\xae\x89\x3f\xfc\x0e\x3d\xcf\x49\x29\x02",
- "\xe6\x1c\x43\x2b\x72\x0b\x19\xd1\x8e\xc8\xd8\x4b\xdc\x63\x15\x1b",
- "\xf7\xe5\xae\xf5\x49\xf7\x82\xcf\x37\x90\x55\xa6\x08\x26\x9b\x16",
- "\x43\x8d\x03\x0f\xd0\xb7\xa5\x4f\xa8\x37\xf2\xad\x20\x1a\x64\x03",
- "\xa5\x90\xd3\xee\x4f\xbf\x04\xe3\x24\x7e\x0d\x27\xf2\x86\x42\x3f",
- "\x5f\xe2\xc1\xa1\x72\xfe\x93\xc4\xb1\x5c\xd3\x7c\xae\xf9\xf5\x38",
- "\x2c\x97\x32\x5c\xbd\x06\xb3\x6e\xb2\x13\x3d\xd0\x8b\x3a\x01\x7c",
- "\x92\xc8\x14\x22\x7a\x6b\xca\x94\x9f\xf0\x65\x9f\x00\x2a\xd3\x9e",
- "\xdc\xe8\x50\x11\x0b\xd8\x32\x8c\xfb\xd5\x08\x41\xd6\x91\x1d\x87",
- "\x67\xf1\x49\x84\xc7\xda\x79\x12\x48\xe3\x2b\xb5\x92\x25\x83\xda",
- "\x19\x38\xf2\xcf\x72\xd5\x4e\xe9\x7e\x94\x16\x6f\xa9\x1d\x2a\x36",
- "\x74\x48\x1e\x96\x46\xed\x49\xfe\x0f\x62\x24\x30\x16\x04\x69\x8e",
- "\x57\xfc\xa5\xde\x98\xa9\xd6\xd8\x00\x64\x38\xd0\x58\x3d\x8a\x1d",
- "\x9f\xec\xde\x1c\xef\xdc\x1c\xbe\xd4\x76\x36\x74\xd9\x57\x53\x59",
- "\xe3\x04\x0c\x00\xeb\x28\xf1\x53\x66\xca\x73\xcb\xd8\x72\xe7\x40",
- "\x76\x97\x00\x9a\x6a\x83\x1d\xfe\xcc\xa9\x1c\x59\x93\x67\x0f\x7a",
- "\x58\x53\x54\x23\x21\xf5\x67\xa0\x05\xd5\x47\xa4\xf0\x47\x59\xbd",
- "\x51\x50\xd1\x77\x2f\x50\x83\x4a\x50\x3e\x06\x9a\x97\x3f\xbd\x7c",
+ "\xa3\x81\x7f\x04\xba\x25\xa8\xe6\x6d\xf6\x72\x14\xc7\x55\x02\x93".*,
+ "\xda\x87\xc1\xd8\x6b\x99\xaf\x44\x34\x76\x59\x11\x9b\x22\xfc\x45".*,
+ "\x81\x77\x22\x8d\xa4\xa4\x5d\xc7\xfc\xa3\x8b\xde\xf6\x0a\xff\xe4".*,
+ "\x9c\x70\xb6\x0c\x52\x67\xa9\x4e\x5f\x33\xb6\xb0\x29\x85\xed\x51".*,
+ "\xf8\x81\x64\xc1\x2d\x9c\x8f\xaf\x7d\x0f\x6e\x7c\x7b\xcd\x55\x79".*,
+ "\x13\x68\x87\x59\x80\x77\x6f\x88\x54\x52\x7a\x07\x69\x0e\x96\x27".*,
+ "\x14\xee\xca\x33\x8b\x20\x86\x13\x48\x5e\xa0\x30\x8f\xd7\xa1\x5e".*,
+ "\xa1\xf1\xeb\xbe\xd8\xdb\xc1\x53\xc0\xb8\x4a\xa6\x1f\xf0\x82\x39".*,
+ "\x3b\x62\xa9\xba\x62\x58\xf5\x61\x0f\x83\xe2\x64\xf3\x14\x97\xb4".*,
+ "\x26\x44\x99\x06\x0a\xd9\xba\xab\xc4\x7f\x8b\x02\xbb\x6d\x71\xed".*,
+ "\x00\x11\x0d\xc3\x78\x14\x69\x56\xc9\x54\x47\xd3\xf3\xd0\xfb\xba".*,
+ "\x01\x51\xc5\x68\x38\x6b\x66\x77\xa2\xb4\xdc\x6f\x81\xe5\xdc\x18".*,
+ "\xd6\x26\xb2\x66\x90\x5e\xf3\x58\x82\x63\x4d\xf6\x85\x32\xc1\x25".*,
+ "\x98\x69\xe2\x47\xe9\xc0\x8b\x10\xd0\x29\x93\x4f\xc4\xb9\x52\xf7".*,
+ "\x31\xfc\xef\xac\x66\xd7\xde\x9c\x7e\xc7\x48\x5f\xe4\x49\x49\x02".*,
+ "\x54\x93\xe9\x99\x33\xb0\xa8\x11\x7e\x08\xec\x0f\x97\xcf\xc3\xd9".*,
+ "\x6e\xe2\xa4\xca\x67\xb0\x54\xbb\xfd\x33\x15\xbf\x85\x23\x05\x77".*,
+ "\x47\x3d\x06\xe8\x73\x8d\xb8\x98\x54\xc0\x66\xc4\x7a\xe4\x77\x40".*,
+ "\xa4\x26\xe5\xe4\x23\xbf\x48\x85\x29\x4d\xa4\x81\xfe\xae\xf7\x23".*,
+ "\x78\x01\x77\x31\xcf\x65\xfa\xb0\x74\xd5\x20\x89\x52\x51\x2e\xb1".*,
+ "\x9e\x25\xfc\x83\x3f\x22\x90\x73\x3e\x93\x44\xa5\xe8\x38\x39\xeb".*,
+ "\x56\x8e\x49\x5a\xbe\x52\x5a\x21\x8a\x22\x14\xcd\x3e\x07\x1d\x12".*,
+ "\x4a\x29\xb5\x45\x52\xd1\x6b\x9a\x46\x9c\x10\x52\x8e\xff\x0a\xae".*,
+ "\xc9\xd1\x84\xdd\xd5\xa9\xf5\xe0\xcf\x8c\xe2\x9a\x9a\xbf\x69\x1c".*,
+ "\x2d\xb4\x79\xae\x78\xbd\x50\xd8\x88\x2a\x8a\x17\x8a\x61\x32\xad".*,
+ "\x8e\xce\x5f\x04\x2d\x5e\x44\x7b\x50\x51\xb9\xea\xcb\x8d\x8f\x6f".*,
+ "\x9c\x0b\x53\xb4\xb3\xc3\x07\xe8\x7e\xae\xe0\x86\x78\x14\x1f\x66".*,
+ "\xab\xf2\x48\xaf\x69\xa6\xea\xe4\xbf\xd3\xeb\x2f\x12\x9e\xeb\x94".*,
+ "\x06\x64\xda\x16\x68\x57\x4b\x88\xb9\x35\xf3\x02\x73\x58\xae\xf4".*,
+ "\xaa\x4b\x9d\xc4\xbf\x33\x7d\xe9\x0c\xd4\xfd\x3c\x46\x7c\x6a\xb7".*,
+ "\xea\x5c\x7f\x47\x1f\xaf\x6b\xde\x2b\x1a\xd7\xd4\x68\x6d\x22\x87".*,
+ "\x29\x39\xb0\x18\x32\x23\xfa\xfc\x17\x23\xde\x4f\x52\xc4\x3d\x35".*,
+ "\x7c\x39\x56\xca\x5e\xea\xfc\x3e\x36\x3e\x9d\x55\x65\x46\xeb\x68".*,
+ "\x77\xc6\x07\x71\x46\xf0\x1c\x32\xb6\xb6\x9d\x5f\x4e\xa9\xff\xcf".*,
+ "\x37\xa6\x98\x6c\xb8\x84\x7e\xdf\x09\x25\xf0\xf1\x30\x9b\x54\xde".*,
+ "\xa7\x05\xf0\xe6\x9d\xa9\xa8\xf9\x07\x24\x1a\x2e\x92\x3c\x8c\xc8".*,
+ "\x3d\xc4\x7d\x1f\x29\xc4\x48\x46\x1e\x9e\x76\xed\x90\x4f\x67\x11".*,
+ "\x0d\x62\xbf\x01\xe6\xfc\x0e\x1a\x0d\x3c\x47\x51\xc5\xd3\x69\x2b".*,
+ "\x8c\x03\x46\x8b\xca\x7c\x66\x9e\xe4\xfd\x5e\x08\x4b\xbe\xe7\xb5".*,
+ "\x52\x8a\x5b\xb9\x3b\xaf\x2c\x9c\x44\x73\xcc\xe5\xd0\xd2\x2b\xd9".*,
+ "\xdf\x6a\x30\x1e\x95\xc9\x5d\xad\x97\xae\x0c\xc8\xc6\x91\x3b\xd8".*,
+ "\x80\x11\x89\x90\x2c\x85\x7f\x39\xe7\x35\x91\x28\x5e\x70\xb6\xdb".*,
+ "\xe6\x17\x34\x6a\xc9\xc2\x31\xbb\x36\x50\xae\x34\xcc\xca\x0c\x5b".*,
+ "\x27\xd9\x34\x37\xef\xb7\x21\xaa\x40\x18\x21\xdc\xec\x5a\xdf\x89".*,
+ "\x89\x23\x7d\x9d\xed\x9c\x5e\x78\xd8\xb1\xc9\xb1\x66\xcc\x73\x42".*,
+ "\x4a\x6d\x80\x91\xbf\x5e\x7d\x65\x11\x89\xfa\x94\xa2\x50\xb1\x4c".*,
+ "\x0e\x33\xf9\x60\x55\xe7\xae\x89\x3f\xfc\x0e\x3d\xcf\x49\x29\x02".*,
+ "\xe6\x1c\x43\x2b\x72\x0b\x19\xd1\x8e\xc8\xd8\x4b\xdc\x63\x15\x1b".*,
+ "\xf7\xe5\xae\xf5\x49\xf7\x82\xcf\x37\x90\x55\xa6\x08\x26\x9b\x16".*,
+ "\x43\x8d\x03\x0f\xd0\xb7\xa5\x4f\xa8\x37\xf2\xad\x20\x1a\x64\x03".*,
+ "\xa5\x90\xd3\xee\x4f\xbf\x04\xe3\x24\x7e\x0d\x27\xf2\x86\x42\x3f".*,
+ "\x5f\xe2\xc1\xa1\x72\xfe\x93\xc4\xb1\x5c\xd3\x7c\xae\xf9\xf5\x38".*,
+ "\x2c\x97\x32\x5c\xbd\x06\xb3\x6e\xb2\x13\x3d\xd0\x8b\x3a\x01\x7c".*,
+ "\x92\xc8\x14\x22\x7a\x6b\xca\x94\x9f\xf0\x65\x9f\x00\x2a\xd3\x9e".*,
+ "\xdc\xe8\x50\x11\x0b\xd8\x32\x8c\xfb\xd5\x08\x41\xd6\x91\x1d\x87".*,
+ "\x67\xf1\x49\x84\xc7\xda\x79\x12\x48\xe3\x2b\xb5\x92\x25\x83\xda".*,
+ "\x19\x38\xf2\xcf\x72\xd5\x4e\xe9\x7e\x94\x16\x6f\xa9\x1d\x2a\x36".*,
+ "\x74\x48\x1e\x96\x46\xed\x49\xfe\x0f\x62\x24\x30\x16\x04\x69\x8e".*,
+ "\x57\xfc\xa5\xde\x98\xa9\xd6\xd8\x00\x64\x38\xd0\x58\x3d\x8a\x1d".*,
+ "\x9f\xec\xde\x1c\xef\xdc\x1c\xbe\xd4\x76\x36\x74\xd9\x57\x53\x59".*,
+ "\xe3\x04\x0c\x00\xeb\x28\xf1\x53\x66\xca\x73\xcb\xd8\x72\xe7\x40".*,
+ "\x76\x97\x00\x9a\x6a\x83\x1d\xfe\xcc\xa9\x1c\x59\x93\x67\x0f\x7a".*,
+ "\x58\x53\x54\x23\x21\xf5\x67\xa0\x05\xd5\x47\xa4\xf0\x47\x59\xbd".*,
+ "\x51\x50\xd1\x77\x2f\x50\x83\x4a\x50\x3e\x06\x9a\x97\x3f\xbd\x7c".*,
};
const siphash = SipHash128(2, 4);
diff --git a/lib/std/io/test.zig b/lib/std/io/test.zig
index 28b8371d9d..d2374f0a3f 100644
--- a/lib/std/io/test.zig
+++ b/lib/std/io/test.zig
@@ -595,8 +595,8 @@ test "Deserializer bad data" {
test "c out stream" {
if (!builtin.link_libc) return error.SkipZigTest;
- const filename = c"tmp_io_test_file.txt";
- const out_file = std.c.fopen(filename, c"w") orelse return error.UnableToOpenTestFile;
+ const filename = "tmp_io_test_file.txt";
+ const out_file = std.c.fopen(filename, "w") orelse return error.UnableToOpenTestFile;
defer {
_ = std.c.fclose(out_file);
fs.deleteFileC(filename) catch {};
diff --git a/lib/std/mem.zig b/lib/std/mem.zig
index 19e9634d5a..160b8e6e5e 100644
--- a/lib/std/mem.zig
+++ b/lib/std/mem.zig
@@ -1408,7 +1408,9 @@ test "toBytes" {
fn BytesAsValueReturnType(comptime T: type, comptime B: type) type {
const size = @as(usize, @sizeOf(T));
- if (comptime !trait.is(builtin.TypeId.Pointer)(B) or meta.Child(B) != [size]u8) {
+ if (comptime !trait.is(builtin.TypeId.Pointer)(B) or
+ (meta.Child(B) != [size]u8 and meta.Child(B) != [size]null u8))
+ {
@compileError("expected *[N]u8 " ++ ", passed " ++ @typeName(B));
}
@@ -1430,12 +1432,12 @@ test "bytesAsValue" {
builtin.Endian.Little => "\xEF\xBE\xAD\xDE",
};
- testing.expect(deadbeef == bytesAsValue(u32, &deadbeef_bytes).*);
+ testing.expect(deadbeef == bytesAsValue(u32, deadbeef_bytes).*);
- var codeface_bytes = switch (builtin.endian) {
+ var codeface_bytes: [4]u8 = switch (builtin.endian) {
builtin.Endian.Big => "\xC0\xDE\xFA\xCE",
builtin.Endian.Little => "\xCE\xFA\xDE\xC0",
- };
+ }.*;
var codeface = bytesAsValue(u32, &codeface_bytes);
testing.expect(codeface.* == 0xC0DEFACE);
codeface.* = 0;
@@ -1456,14 +1458,14 @@ test "bytesAsValue" {
.d = 0xA1,
};
const inst_bytes = "\xBE\xEF\xDE\xA1";
- const inst2 = bytesAsValue(S, &inst_bytes);
+ const inst2 = bytesAsValue(S, inst_bytes);
testing.expect(meta.eql(inst, inst2.*));
}
///Given a pointer to an array of bytes, returns a value of the specified type backed by a
/// copy of those bytes.
pub fn bytesToValue(comptime T: type, bytes: var) T {
- return bytesAsValue(T, &bytes).*;
+ return bytesAsValue(T, bytes).*;
}
test "bytesToValue" {
const deadbeef_bytes = switch (builtin.endian) {
@@ -1491,11 +1493,11 @@ pub fn subArrayPtr(ptr: var, comptime start: usize, comptime length: usize) SubA
}
test "subArrayPtr" {
- const a1 = "abcdef";
+ const a1: [6]u8 = "abcdef".*;
const sub1 = subArrayPtr(&a1, 2, 3);
testing.expect(eql(u8, sub1.*, "cde"));
- var a2 = "abcdef";
+ var a2: [6]u8 = "abcdef".*;
var sub2 = subArrayPtr(&a2, 2, 3);
testing.expect(eql(u8, sub2, "cde"));
diff --git a/lib/std/meta.zig b/lib/std/meta.zig
index 01d240f31f..b770b97a47 100644
--- a/lib/std/meta.zig
+++ b/lib/std/meta.zig
@@ -469,19 +469,19 @@ test "std.meta.eql" {
const s_1 = S{
.a = 134,
.b = 123.3,
- .c = "12345",
+ .c = "12345".*,
};
const s_2 = S{
.a = 1,
.b = 123.3,
- .c = "54321",
+ .c = "54321".*,
};
const s_3 = S{
.a = 134,
.b = 123.3,
- .c = "12345",
+ .c = "12345".*,
};
const u_1 = U{ .f = 24 };
@@ -494,9 +494,9 @@ test "std.meta.eql" {
testing.expect(eql(u_1, u_3));
testing.expect(!eql(u_1, u_2));
- var a1 = "abcdef";
- var a2 = "abcdef";
- var a3 = "ghijkl";
+ var a1 = "abcdef".*;
+ var a2 = "abcdef".*;
+ var a3 = "ghijkl".*;
testing.expect(eql(a1, a2));
testing.expect(!eql(a1, a3));
@@ -558,4 +558,3 @@ pub fn refAllDecls(comptime T: type) void {
if (!builtin.is_test) return;
_ = declarations(T);
}
-
diff --git a/lib/std/meta/trait.zig b/lib/std/meta/trait.zig
index 8857b4aa9e..2388acbeb6 100644
--- a/lib/std/meta/trait.zig
+++ b/lib/std/meta/trait.zig
@@ -319,7 +319,6 @@ test "std.meta.trait.isNumber" {
testing.expect(!isNumber(NotANumber));
}
-///
pub fn isConstPtr(comptime T: type) bool {
if (!comptime is(builtin.TypeId.Pointer)(T)) return false;
const info = @typeInfo(T);
@@ -335,7 +334,6 @@ test "std.meta.trait.isConstPtr" {
testing.expect(!isConstPtr(@typeOf(6)));
}
-///
pub fn isContainer(comptime T: type) bool {
const info = @typeInfo(T);
return switch (info) {
diff --git a/lib/std/net.zig b/lib/std/net.zig
index f4cd09482b..5e194d73ca 100644
--- a/lib/std/net.zig
+++ b/lib/std/net.zig
@@ -666,35 +666,35 @@ const Policy = struct {
const defined_policies = [_]Policy{
Policy{
- .addr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
+ .addr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01".*,
.len = 15,
.mask = 0xff,
.prec = 50,
.label = 0,
},
Policy{
- .addr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00",
+ .addr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00".*,
.len = 11,
.mask = 0xff,
.prec = 35,
.label = 4,
},
Policy{
- .addr = "\x20\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ .addr = "\x20\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".*,
.len = 1,
.mask = 0xff,
.prec = 30,
.label = 2,
},
Policy{
- .addr = "\x20\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ .addr = "\x20\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".*,
.len = 3,
.mask = 0xff,
.prec = 5,
.label = 5,
},
Policy{
- .addr = "\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ .addr = "\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".*,
.len = 0,
.mask = 0xfe,
.prec = 3,
@@ -708,7 +708,7 @@ const defined_policies = [_]Policy{
// { "\x3f\xfe", 1, 0xff, 1, 12 },
// Last rule must match all addresses to stop loop.
Policy{
- .addr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ .addr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".*,
.len = 0,
.mask = 0,
.prec = 40,
@@ -812,7 +812,7 @@ fn linuxLookupNameFromHosts(
family: os.sa_family_t,
port: u16,
) !void {
- const file = fs.File.openReadC(c"/etc/hosts") catch |err| switch (err) {
+ const file = fs.File.openReadC("/etc/hosts") catch |err| switch (err) {
error.FileNotFound,
error.NotDir,
error.AccessDenied,
@@ -1006,7 +1006,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void {
};
errdefer rc.deinit();
- const file = fs.File.openReadC(c"/etc/resolv.conf") catch |err| switch (err) {
+ const file = fs.File.openReadC("/etc/resolv.conf") catch |err| switch (err) {
error.FileNotFound,
error.NotDir,
error.AccessDenied,
diff --git a/lib/std/os.zig b/lib/std/os.zig
index 68a3a6e9f6..28a88beb04 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -157,7 +157,7 @@ pub fn getrandom(buffer: []u8) GetRandomError!void {
}
fn getRandomBytesDevURandom(buf: []u8) !void {
- const fd = try openC(c"/dev/urandom", O_RDONLY | O_CLOEXEC, 0);
+ const fd = try openC("/dev/urandom", O_RDONLY | O_CLOEXEC, 0);
defer close(fd);
const st = try fstat(fd);
@@ -2674,7 +2674,7 @@ pub fn dl_iterate_phdr(
if (it.end()) {
var info = dl_phdr_info{
.dlpi_addr = elf_base,
- .dlpi_name = c"/proc/self/exe",
+ .dlpi_name = "/proc/self/exe",
.dlpi_phdr = phdrs.ptr,
.dlpi_phnum = ehdr.e_phnum,
};
diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig
index 7e2f14021f..1de66b8d2e 100644
--- a/lib/std/os/linux.zig
+++ b/lib/std/os/linux.zig
@@ -1053,7 +1053,7 @@ pub fn dl_iterate_phdr(comptime T: type, callback: extern fn (info: *dl_phdr_inf
if (it.end()) {
var info = dl_phdr_info{
.dlpi_addr = elf_base,
- .dlpi_name = c"/proc/self/exe",
+ .dlpi_name = "/proc/self/exe",
.dlpi_phdr = @intToPtr([*]elf.Phdr, elf_base + __ehdr_start.e_phoff),
.dlpi_phnum = __ehdr_start.e_phnum,
};
diff --git a/lib/std/os/linux/test.zig b/lib/std/os/linux/test.zig
index bccb7beb1e..8281851d6b 100644
--- a/lib/std/os/linux/test.zig
+++ b/lib/std/os/linux/test.zig
@@ -56,7 +56,7 @@ test "statx" {
}
var statx_buf: linux.Statx = undefined;
- switch (linux.getErrno(linux.statx(file.handle, c"", linux.AT_EMPTY_PATH, linux.STATX_BASIC_STATS, &statx_buf))) {
+ switch (linux.getErrno(linux.statx(file.handle, "", linux.AT_EMPTY_PATH, linux.STATX_BASIC_STATS, &statx_buf))) {
0 => {},
// The statx syscall was only introduced in linux 4.11
linux.ENOSYS => return error.SkipZigTest,
@@ -64,7 +64,7 @@ test "statx" {
}
var stat_buf: linux.Stat = undefined;
- switch (linux.getErrno(linux.fstatat(file.handle, c"", &stat_buf, linux.AT_EMPTY_PATH))) {
+ switch (linux.getErrno(linux.fstatat(file.handle, "", &stat_buf, linux.AT_EMPTY_PATH))) {
0 => {},
else => unreachable,
}
diff --git a/lib/std/process.zig b/lib/std/process.zig
index fca10a240d..3f065de8fc 100644
--- a/lib/std/process.zig
+++ b/lib/std/process.zig
@@ -473,14 +473,14 @@ pub fn argsFree(allocator: *mem.Allocator, args_alloc: []const []u8) void {
}
test "windows arg parsing" {
- testWindowsCmdLine(c"a b\tc d", [_][]const u8{ "a", "b", "c", "d" });
- testWindowsCmdLine(c"\"abc\" d e", [_][]const u8{ "abc", "d", "e" });
- testWindowsCmdLine(c"a\\\\\\b d\"e f\"g h", [_][]const u8{ "a\\\\\\b", "de fg", "h" });
- testWindowsCmdLine(c"a\\\\\\\"b c d", [_][]const u8{ "a\\\"b", "c", "d" });
- testWindowsCmdLine(c"a\\\\\\\\\"b c\" d e", [_][]const u8{ "a\\\\b c", "d", "e" });
- testWindowsCmdLine(c"a b\tc \"d f", [_][]const u8{ "a", "b", "c", "\"d", "f" });
-
- testWindowsCmdLine(c"\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", [_][]const u8{
+ testWindowsCmdLine("a b\tc d", [_][]const u8{ "a", "b", "c", "d" });
+ testWindowsCmdLine("\"abc\" d e", [_][]const u8{ "abc", "d", "e" });
+ testWindowsCmdLine("a\\\\\\b d\"e f\"g h", [_][]const u8{ "a\\\\\\b", "de fg", "h" });
+ testWindowsCmdLine("a\\\\\\\"b c d", [_][]const u8{ "a\\\"b", "c", "d" });
+ testWindowsCmdLine("a\\\\\\\\\"b c\" d e", [_][]const u8{ "a\\\\b c", "d", "e" });
+ testWindowsCmdLine("a b\tc \"d f", [_][]const u8{ "a", "b", "c", "\"d", "f" });
+
+ testWindowsCmdLine("\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", [_][]const u8{
".\\..\\zig-cache\\build",
"bin\\zig.exe",
".\\..",
diff --git a/lib/std/special/c.zig b/lib/std/special/c.zig
index 145c8897d5..8ac00c4e04 100644
--- a/lib/std/special/c.zig
+++ b/lib/std/special/c.zig
@@ -66,14 +66,14 @@ extern fn strncmp(_l: [*]const u8, _r: [*]const u8, _n: usize) c_int {
}
extern fn strerror(errnum: c_int) [*]const u8 {
- return c"TODO strerror implementation";
+ return "TODO strerror implementation";
}
test "strncmp" {
- std.testing.expect(strncmp(c"a", c"b", 1) == -1);
- std.testing.expect(strncmp(c"a", c"c", 1) == -2);
- std.testing.expect(strncmp(c"b", c"a", 1) == 1);
- std.testing.expect(strncmp(c"\xff", c"\x02", 1) == 253);
+ std.testing.expect(strncmp("a", "b", 1) == -1);
+ std.testing.expect(strncmp("a", "c", 1) == -2);
+ std.testing.expect(strncmp("b", "a", 1) == 1);
+ std.testing.expect(strncmp("\xff", "\x02", 1) == 253);
}
// Avoid dragging in the runtime safety mechanisms into this .o file,
diff --git a/lib/std/thread.zig b/lib/std/thread.zig
index 4e15354055..fe976a6839 100644
--- a/lib/std/thread.zig
+++ b/lib/std/thread.zig
@@ -353,7 +353,7 @@ pub const Thread = struct {
}
var count: c_int = undefined;
var count_len: usize = @sizeOf(c_int);
- const name = if (comptime std.Target.current.isDarwin()) c"hw.logicalcpu" else c"hw.ncpu";
+ const name = if (comptime std.Target.current.isDarwin()) "hw.logicalcpu" else "hw.ncpu";
os.sysctlbynameC(name, &count, &count_len, null, 0) catch |err| switch (err) {
error.NameTooLong => unreachable,
else => |e| return e,
diff --git a/lib/std/valgrind/memcheck.zig b/lib/std/valgrind/memcheck.zig
index a15a6cca0e..e0aefa7d5f 100644
--- a/lib/std/valgrind/memcheck.zig
+++ b/lib/std/valgrind/memcheck.zig
@@ -3,7 +3,7 @@ const testing = std.testing;
const valgrind = std.valgrind;
pub const MemCheckClientRequest = extern enum {
- MakeMemNoAccess = valgrind.ToolBase("MC"),
+ MakeMemNoAccess = valgrind.ToolBase("MC".*),
MakeMemUndefined,
MakeMemDefined,
Discard,
diff --git a/src-self-hosted/codegen.zig b/src-self-hosted/codegen.zig
index 90f5309faf..212a54b1aa 100644
--- a/src-self-hosted/codegen.zig
+++ b/src-self-hosted/codegen.zig
@@ -52,7 +52,7 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)
u32(c.ZIG_VERSION_MINOR),
u32(c.ZIG_VERSION_PATCH),
);
- const flags = c"";
+ const flags = "";
const runtime_version = 0;
const compile_unit_file = llvm.CreateFile(
dibuilder,
@@ -68,7 +68,7 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)
is_optimized,
flags,
runtime_version,
- c"",
+ "",
0,
!comp.strip,
) orelse return error.OutOfMemory;
@@ -402,7 +402,7 @@ pub fn getHandleValue(ofile: *ObjectFile, ptr: *llvm.Value, ptr_type: *Type.Poin
if (child_type.handleIsPtr()) {
return ptr;
}
- return try renderLoad(ofile, ptr, ptr_type, c"");
+ return try renderLoad(ofile, ptr, ptr_type, "");
}
pub fn renderStoreUntyped(
diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig
index 1e71a5e561..24c57f98ba 100644
--- a/src-self-hosted/compilation.zig
+++ b/src-self-hosted/compilation.zig
@@ -511,8 +511,8 @@ pub const Compilation = struct {
comp.target_machine = llvm.CreateTargetMachine(
comp.llvm_target,
comp.llvm_triple.ptr(),
- target_specific_cpu_args orelse c"",
- target_specific_cpu_features orelse c"",
+ target_specific_cpu_args orelse "",
+ target_specific_cpu_features orelse "",
opt_level,
reloc_mode,
llvm.CodeModelDefault,
diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig
index df4d436b50..a650a3999d 100644
--- a/src-self-hosted/ir.zig
+++ b/src-self-hosted/ir.zig
@@ -331,7 +331,7 @@ pub const Inst = struct {
@intCast(c_uint, args.len),
llvm_cc,
fn_inline,
- c"",
+ "",
) orelse error.OutOfMemory;
}
};
@@ -1410,7 +1410,7 @@ pub const Builder = struct {
if (block.label) |label| {
block_scope.incoming_values = std.ArrayList(*Inst).init(irb.arena());
block_scope.incoming_blocks = std.ArrayList(*BasicBlock).init(irb.arena());
- block_scope.end_block = try irb.createBasicBlock(parent_scope, c"BlockEnd");
+ block_scope.end_block = try irb.createBasicBlock(parent_scope, "BlockEnd");
block_scope.is_comptime = try irb.buildConstBool(
parent_scope,
Span.token(block.lbrace),
@@ -1542,8 +1542,8 @@ pub const Builder = struct {
const defer_counts = irb.countDefers(scope, outer_scope);
const have_err_defers = defer_counts.error_exit != 0;
if (have_err_defers or irb.comp.have_err_ret_tracing) {
- const err_block = try irb.createBasicBlock(scope, c"ErrRetErr");
- const ok_block = try irb.createBasicBlock(scope, c"ErrRetOk");
+ const err_block = try irb.createBasicBlock(scope, "ErrRetErr");
+ const ok_block = try irb.createBasicBlock(scope, "ErrRetOk");
if (!have_err_defers) {
_ = try await (async irb.genDefersForBlock(scope, outer_scope, Scope.Defer.Kind.ScopeExit) catch unreachable);
}
@@ -1564,7 +1564,7 @@ pub const Builder = struct {
.is_comptime = err_is_comptime,
});
- const ret_stmt_block = try irb.createBasicBlock(scope, c"RetStmt");
+ const ret_stmt_block = try irb.createBasicBlock(scope, "RetStmt");
try irb.setCursorAtEndAndAppendBlock(err_block);
if (have_err_defers) {
@@ -2530,7 +2530,7 @@ pub async fn gen(
var irb = try Builder.init(comp, tree_scope, scope);
errdefer irb.abort();
- const entry_block = try irb.createBasicBlock(scope, c"Entry");
+ const entry_block = try irb.createBasicBlock(scope, "Entry");
entry_block.ref(&irb); // Entry block gets a reference because we enter it to begin.
try irb.setCursorAtEndAndAppendBlock(entry_block);
diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig
index 1f5f07eff0..3af1842b9d 100644
--- a/src-self-hosted/link.zig
+++ b/src-self-hosted/link.zig
@@ -55,7 +55,7 @@ pub async fn link(comp: *Compilation) !void {
// even though we're calling LLD as a library it thinks the first
// argument is its own exe name
- try ctx.args.append(c"lld");
+ try ctx.args.append("lld");
if (comp.haveLibC()) {
ctx.libc = ctx.comp.override_libc orelse blk: {
@@ -145,7 +145,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
// lj->args.append("-T");
// lj->args.append(g->linker_script);
//}
- try ctx.args.append(c"--gc-sections");
+ try ctx.args.append("--gc-sections");
//lj->args.append("-m");
//lj->args.append(getLDMOption(&g->zig_target));
@@ -155,9 +155,9 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
//Buf *soname = nullptr;
if (ctx.comp.is_static) {
if (ctx.comp.target.isArmOrThumb()) {
- try ctx.args.append(c"-Bstatic");
+ try ctx.args.append("-Bstatic");
} else {
- try ctx.args.append(c"-static");
+ try ctx.args.append("-static");
}
}
//} else if (shared) {
@@ -170,7 +170,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
// soname = buf_sprintf("lib%s.so.%" ZIG_PRI_usize "", buf_ptr(g->root_out_name), g->version_major);
//}
- try ctx.args.append(c"-o");
+ try ctx.args.append("-o");
try ctx.args.append(ctx.out_file_path.ptr());
if (ctx.link_in_crt) {
@@ -213,10 +213,10 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
//}
if (ctx.comp.haveLibC()) {
- try ctx.args.append(c"-L");
+ try ctx.args.append("-L");
try ctx.args.append((try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.lib_dir.?)).ptr);
- try ctx.args.append(c"-L");
+ try ctx.args.append("-L");
try ctx.args.append((try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.static_lib_dir.?)).ptr);
if (!ctx.comp.is_static) {
@@ -225,7 +225,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
if (ctx.comp.target.getDynamicLinkerPath()) |dl| break :blk dl;
return error.LibCMissingDynamicLinker;
};
- try ctx.args.append(c"-dynamic-linker");
+ try ctx.args.append("-dynamic-linker");
try ctx.args.append((try std.cstr.addNullByte(&ctx.arena.allocator, dl)).ptr);
}
}
@@ -272,23 +272,23 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
// libc dep
if (ctx.comp.haveLibC()) {
if (ctx.comp.is_static) {
- try ctx.args.append(c"--start-group");
- try ctx.args.append(c"-lgcc");
- try ctx.args.append(c"-lgcc_eh");
- try ctx.args.append(c"-lc");
- try ctx.args.append(c"-lm");
- try ctx.args.append(c"--end-group");
+ try ctx.args.append("--start-group");
+ try ctx.args.append("-lgcc");
+ try ctx.args.append("-lgcc_eh");
+ try ctx.args.append("-lc");
+ try ctx.args.append("-lm");
+ try ctx.args.append("--end-group");
} else {
- try ctx.args.append(c"-lgcc");
- try ctx.args.append(c"--as-needed");
- try ctx.args.append(c"-lgcc_s");
- try ctx.args.append(c"--no-as-needed");
- try ctx.args.append(c"-lc");
- try ctx.args.append(c"-lm");
- try ctx.args.append(c"-lgcc");
- try ctx.args.append(c"--as-needed");
- try ctx.args.append(c"-lgcc_s");
- try ctx.args.append(c"--no-as-needed");
+ try ctx.args.append("-lgcc");
+ try ctx.args.append("--as-needed");
+ try ctx.args.append("-lgcc_s");
+ try ctx.args.append("--no-as-needed");
+ try ctx.args.append("-lc");
+ try ctx.args.append("-lm");
+ try ctx.args.append("-lgcc");
+ try ctx.args.append("--as-needed");
+ try ctx.args.append("-lgcc_s");
+ try ctx.args.append("--no-as-needed");
}
}
@@ -299,14 +299,14 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
}
if (ctx.comp.target != Target.Native) {
- try ctx.args.append(c"--allow-shlib-undefined");
+ try ctx.args.append("--allow-shlib-undefined");
}
if (ctx.comp.target.getOs() == .zen) {
- try ctx.args.append(c"-e");
- try ctx.args.append(c"_start");
+ try ctx.args.append("-e");
+ try ctx.args.append("_start");
- try ctx.args.append(c"--image-base=0x10000000");
+ try ctx.args.append("--image-base=0x10000000");
}
}
@@ -317,23 +317,23 @@ fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void {
}
fn constructLinkerArgsCoff(ctx: *Context) !void {
- try ctx.args.append(c"-NOLOGO");
+ try ctx.args.append("-NOLOGO");
if (!ctx.comp.strip) {
- try ctx.args.append(c"-DEBUG");
+ try ctx.args.append("-DEBUG");
}
switch (ctx.comp.target.getArch()) {
- builtin.Arch.i386 => try ctx.args.append(c"-MACHINE:X86"),
- builtin.Arch.x86_64 => try ctx.args.append(c"-MACHINE:X64"),
- builtin.Arch.aarch64 => try ctx.args.append(c"-MACHINE:ARM"),
+ builtin.Arch.i386 => try ctx.args.append("-MACHINE:X86"),
+ builtin.Arch.x86_64 => try ctx.args.append("-MACHINE:X64"),
+ builtin.Arch.aarch64 => try ctx.args.append("-MACHINE:ARM"),
else => return error.UnsupportedLinkArchitecture,
}
if (ctx.comp.windows_subsystem_windows) {
- try ctx.args.append(c"/SUBSYSTEM:windows");
+ try ctx.args.append("/SUBSYSTEM:windows");
} else if (ctx.comp.windows_subsystem_console) {
- try ctx.args.append(c"/SUBSYSTEM:console");
+ try ctx.args.append("/SUBSYSTEM:console");
}
const is_library = ctx.comp.kind == Compilation.Kind.Lib;
@@ -367,14 +367,14 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {
// Visual C++ 2015 Conformance Changes
// https://msdn.microsoft.com/en-us/library/bb531344.aspx
- try ctx.args.append(c"legacy_stdio_definitions.lib");
+ try ctx.args.append("legacy_stdio_definitions.lib");
// msvcrt depends on kernel32
- try ctx.args.append(c"kernel32.lib");
+ try ctx.args.append("kernel32.lib");
} else {
- try ctx.args.append(c"-NODEFAULTLIB");
+ try ctx.args.append("-NODEFAULTLIB");
if (!is_library) {
- try ctx.args.append(c"-ENTRY:WinMainCRTStartup");
+ try ctx.args.append("-ENTRY:WinMainCRTStartup");
// TODO
//if (g->have_winmain) {
// lj->args.append("-ENTRY:WinMain");
@@ -385,7 +385,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {
}
if (is_library and !ctx.comp.is_static) {
- try ctx.args.append(c"-DLL");
+ try ctx.args.append("-DLL");
}
//for (size_t i = 0; i < g->lib_dirs.length; i += 1) {
@@ -463,18 +463,18 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {
}
fn constructLinkerArgsMachO(ctx: *Context) !void {
- try ctx.args.append(c"-demangle");
+ try ctx.args.append("-demangle");
if (ctx.comp.linker_rdynamic) {
- try ctx.args.append(c"-export_dynamic");
+ try ctx.args.append("-export_dynamic");
}
const is_lib = ctx.comp.kind == Compilation.Kind.Lib;
const shared = !ctx.comp.is_static and is_lib;
if (ctx.comp.is_static) {
- try ctx.args.append(c"-static");
+ try ctx.args.append("-static");
} else {
- try ctx.args.append(c"-dynamic");
+ try ctx.args.append("-dynamic");
}
//if (is_lib) {
@@ -503,7 +503,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
// }
//}
- try ctx.args.append(c"-arch");
+ try ctx.args.append("-arch");
const darwin_arch_str = try std.cstr.addNullByte(
&ctx.arena.allocator,
ctx.comp.target.getDarwinArchString(),
@@ -512,22 +512,22 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
const platform = try DarwinPlatform.get(ctx.comp);
switch (platform.kind) {
- DarwinPlatform.Kind.MacOS => try ctx.args.append(c"-macosx_version_min"),
- DarwinPlatform.Kind.IPhoneOS => try ctx.args.append(c"-iphoneos_version_min"),
- DarwinPlatform.Kind.IPhoneOSSimulator => try ctx.args.append(c"-ios_simulator_version_min"),
+ DarwinPlatform.Kind.MacOS => try ctx.args.append("-macosx_version_min"),
+ DarwinPlatform.Kind.IPhoneOS => try ctx.args.append("-iphoneos_version_min"),
+ DarwinPlatform.Kind.IPhoneOSSimulator => try ctx.args.append("-ios_simulator_version_min"),
}
const ver_str = try std.fmt.allocPrint(&ctx.arena.allocator, "{}.{}.{}\x00", platform.major, platform.minor, platform.micro);
try ctx.args.append(ver_str.ptr);
if (ctx.comp.kind == Compilation.Kind.Exe) {
if (ctx.comp.is_static) {
- try ctx.args.append(c"-no_pie");
+ try ctx.args.append("-no_pie");
} else {
- try ctx.args.append(c"-pie");
+ try ctx.args.append("-pie");
}
}
- try ctx.args.append(c"-o");
+ try ctx.args.append("-o");
try ctx.args.append(ctx.out_file_path.ptr());
//for (size_t i = 0; i < g->rpath_list.length; i += 1) {
@@ -537,27 +537,27 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
//add_rpath(lj, &lj->out_file);
if (shared) {
- try ctx.args.append(c"-headerpad_max_install_names");
+ try ctx.args.append("-headerpad_max_install_names");
} else if (ctx.comp.is_static) {
- try ctx.args.append(c"-lcrt0.o");
+ try ctx.args.append("-lcrt0.o");
} else {
switch (platform.kind) {
DarwinPlatform.Kind.MacOS => {
if (platform.versionLessThan(10, 5)) {
- try ctx.args.append(c"-lcrt1.o");
+ try ctx.args.append("-lcrt1.o");
} else if (platform.versionLessThan(10, 6)) {
- try ctx.args.append(c"-lcrt1.10.5.o");
+ try ctx.args.append("-lcrt1.10.5.o");
} else if (platform.versionLessThan(10, 8)) {
- try ctx.args.append(c"-lcrt1.10.6.o");
+ try ctx.args.append("-lcrt1.10.6.o");
}
},
DarwinPlatform.Kind.IPhoneOS => {
if (ctx.comp.target.getArch() == builtin.Arch.aarch64) {
// iOS does not need any crt1 files for arm64
} else if (platform.versionLessThan(3, 1)) {
- try ctx.args.append(c"-lcrt1.o");
+ try ctx.args.append("-lcrt1.o");
} else if (platform.versionLessThan(6, 0)) {
- try ctx.args.append(c"-lcrt1.3.1.o");
+ try ctx.args.append("-lcrt1.3.1.o");
}
},
DarwinPlatform.Kind.IPhoneOSSimulator => {}, // no crt1.o needed
@@ -589,7 +589,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
// to make syscalls because the syscall numbers are not documented
// and change between versions.
// so we always link against libSystem
- try ctx.args.append(c"-lSystem");
+ try ctx.args.append("-lSystem");
} else {
if (mem.indexOfScalar(u8, lib.name, '/') == null) {
const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", lib.name);
@@ -601,15 +601,15 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
}
}
} else {
- try ctx.args.append(c"-undefined");
- try ctx.args.append(c"dynamic_lookup");
+ try ctx.args.append("-undefined");
+ try ctx.args.append("dynamic_lookup");
}
if (platform.kind == DarwinPlatform.Kind.MacOS) {
if (platform.versionLessThan(10, 5)) {
- try ctx.args.append(c"-lgcc_s.10.4");
+ try ctx.args.append("-lgcc_s.10.4");
} else if (platform.versionLessThan(10, 6)) {
- try ctx.args.append(c"-lgcc_s.10.5");
+ try ctx.args.append("-lgcc_s.10.5");
}
} else {
@panic("TODO");
diff --git a/src-self-hosted/stage1.zig b/src-self-hosted/stage1.zig
index 37945bf029..49ad23a19d 100644
--- a/src-self-hosted/stage1.zig
+++ b/src-self-hosted/stage1.zig
@@ -28,7 +28,7 @@ comptime {
// ABI warning
export fn stage2_zen(ptr: *[*]const u8, len: *usize) void {
const info_zen = @import("main.zig").info_zen;
- ptr.* = &info_zen;
+ ptr.* = info_zen;
len.* = info_zen.len;
}
diff --git a/src-self-hosted/value.zig b/src-self-hosted/value.zig
index 6908307c56..63aefbe717 100644
--- a/src-self-hosted/value.zig
+++ b/src-self-hosted/value.zig
@@ -474,7 +474,7 @@ pub const Value = struct {
dont_null_terminate,
) orelse return error.OutOfMemory;
const str_init_type = llvm.TypeOf(llvm_str_init);
- const global = llvm.AddGlobal(ofile.module, str_init_type, c"") orelse return error.OutOfMemory;
+ const global = llvm.AddGlobal(ofile.module, str_init_type, "") orelse return error.OutOfMemory;
llvm.SetInitializer(global, llvm_str_init);
llvm.SetLinkage(global, llvm.PrivateLinkage);
llvm.SetGlobalConstant(global, 1);
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 0fe43eaa3e..4047a7d4a5 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -102,6 +102,10 @@ struct IrExecutable {
bool is_inline;
bool is_generic_instantiation;
bool need_err_code_spill;
+
+ // This is a function for use in the debugger to print
+ // the source location.
+ void src();
};
enum OutType {
@@ -237,9 +241,6 @@ struct ConstPtrValue {
struct {
ConstExprValue *array_val;
size_t elem_index;
- // This helps us preserve the null byte when performing compile-time
- // concatenation on C strings.
- bool is_cstr;
} base_array;
struct {
ConstExprValue *struct_val;
@@ -1001,7 +1002,6 @@ struct AstNodeStructField {
struct AstNodeStringLiteral {
Buf *buf;
- bool c;
};
struct AstNodeCharLiteral {
@@ -1956,6 +1956,7 @@ struct CodeGen {
HashMap external_prototypes;
HashMap string_literals_table;
HashMap type_info_cache;
+ HashMap one_possible_values;
ZigList resolve_queue;
size_t resolve_queue_index;
diff --git a/src/analyze.cpp b/src/analyze.cpp
index f67c4a035e..9c42177d11 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -767,10 +767,18 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, bo
ZigType *entry = new_type_table_entry(ZigTypeIdArray);
+ const char *null_str = is_null_terminated ? "null " : "";
+
buf_resize(&entry->name, 0);
- buf_appendf(&entry->name, "[%" ZIG_PRI_u64 "]%s", array_size, buf_ptr(&child_type->name));
+ buf_appendf(&entry->name, "[%" ZIG_PRI_u64 "]%s%s", array_size, null_str, buf_ptr(&child_type->name));
+
+ size_t full_array_size;
+ if (array_size == 0) {
+ full_array_size = 0;
+ } else {
+ full_array_size = array_size + (is_null_terminated ? 1 : 0);
+ }
- size_t full_array_size = array_size + (is_null_terminated ? 1 : 0);
entry->size_in_bits = child_type->size_in_bits * full_array_size;
entry->abi_align = child_type->abi_align;
entry->abi_size = child_type->abi_size * full_array_size;
@@ -5046,7 +5054,6 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) {
hash_val += (uint32_t)1764906839;
hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val);
hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index);
- hash_val += const_val->data.x_ptr.data.base_array.is_cstr ? 1297263887 : 200363492;
return hash_val;
case ConstPtrSpecialBaseStruct:
hash_val += (uint32_t)3518317043;
@@ -5550,6 +5557,18 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {
zig_unreachable();
}
+ConstExprValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) {
+ auto entry = g->one_possible_values.maybe_get(type_entry);
+ if (entry != nullptr) {
+ return entry->value;
+ }
+ ConstExprValue *result = create_const_vals(1);
+ result->type = type_entry;
+ result->special = ConstValSpecialStatic;
+ g->one_possible_values.put(type_entry, result);
+ return result;
+}
+
ReqCompTime type_requires_comptime(CodeGen *g, ZigType *ty) {
Error err;
switch (ty->id) {
@@ -5617,52 +5636,26 @@ void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
return;
}
- const_val->special = ConstValSpecialStatic;
- const_val->type = get_array_type(g, g->builtin_types.entry_u8, buf_len(str), false);
- const_val->data.x_array.special = ConstArraySpecialBuf;
- const_val->data.x_array.data.s_buf = str;
-
- g->string_literals_table.put(str, const_val);
-}
-
-ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str) {
- ConstExprValue *const_val = create_const_vals(1);
- init_const_str_lit(g, const_val, str);
- return const_val;
-}
-
-void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
// first we build the underlying array
- size_t len_with_null = buf_len(str) + 1;
ConstExprValue *array_val = create_const_vals(1);
array_val->special = ConstValSpecialStatic;
- array_val->type = get_array_type(g, g->builtin_types.entry_u8, len_with_null, false);
- // TODO buf optimization
- array_val->data.x_array.data.s_none.elements = create_const_vals(len_with_null);
- for (size_t i = 0; i < buf_len(str); i += 1) {
- ConstExprValue *this_char = &array_val->data.x_array.data.s_none.elements[i];
- this_char->special = ConstValSpecialStatic;
- this_char->type = g->builtin_types.entry_u8;
- bigint_init_unsigned(&this_char->data.x_bigint, (uint8_t)buf_ptr(str)[i]);
- }
- ConstExprValue *null_char = &array_val->data.x_array.data.s_none.elements[len_with_null - 1];
- null_char->special = ConstValSpecialStatic;
- null_char->type = g->builtin_types.entry_u8;
- bigint_init_unsigned(&null_char->data.x_bigint, 0);
+ array_val->type = get_array_type(g, g->builtin_types.entry_u8, buf_len(str), true);
+ array_val->data.x_array.special = ConstArraySpecialBuf;
+ array_val->data.x_array.data.s_buf = str;
// then make the pointer point to it
const_val->special = ConstValSpecialStatic;
- // TODO make this `[*]null u8` instead of `[*]u8`
- const_val->type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
- PtrLenUnknown, 0, 0, 0, false);
- const_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
- const_val->data.x_ptr.data.base_array.array_val = array_val;
- const_val->data.x_ptr.data.base_array.elem_index = 0;
- const_val->data.x_ptr.data.base_array.is_cstr = true;
+ const_val->type = get_pointer_to_type_extra2(g, array_val->type, true, false,
+ PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE, nullptr);
+ const_val->data.x_ptr.special = ConstPtrSpecialRef;
+ const_val->data.x_ptr.data.ref.pointee = array_val;
+
+ g->string_literals_table.put(str, const_val);
}
-ConstExprValue *create_const_c_str_lit(CodeGen *g, Buf *str) {
+
+ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str) {
ConstExprValue *const_val = create_const_vals(1);
- init_const_c_str_lit(g, const_val, str);
+ init_const_str_lit(g, const_val, str);
return const_val;
}
@@ -5712,6 +5705,18 @@ ConstExprValue *create_const_signed(ZigType *type, int64_t x) {
return const_val;
}
+void init_const_null(ConstExprValue *const_val, ZigType *type) {
+ const_val->special = ConstValSpecialStatic;
+ const_val->type = type;
+ const_val->data.x_optional = nullptr;
+}
+
+ConstExprValue *create_const_null(ZigType *type) {
+ ConstExprValue *const_val = create_const_vals(1);
+ init_const_null(const_val, type);
+ return const_val;
+}
+
void init_const_float(ConstExprValue *const_val, ZigType *type, double value) {
const_val->special = ConstValSpecialStatic;
const_val->type = type;
@@ -6446,8 +6451,6 @@ bool ir_get_var_is_comptime(ZigVar *var) {
bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) {
if (a->data.x_ptr.special != b->data.x_ptr.special)
return false;
- if (a->data.x_ptr.mut != b->data.x_ptr.mut)
- return false;
switch (a->data.x_ptr.special) {
case ConstPtrSpecialInvalid:
zig_unreachable();
@@ -6464,8 +6467,6 @@ bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) {
}
if (a->data.x_ptr.data.base_array.elem_index != b->data.x_ptr.data.base_array.elem_index)
return false;
- if (a->data.x_ptr.data.base_array.is_cstr != b->data.x_ptr.data.base_array.is_cstr)
- return false;
return true;
case ConstPtrSpecialBaseStruct:
if (a->data.x_ptr.data.base_struct.struct_val != b->data.x_ptr.data.base_struct.struct_val &&
@@ -6544,6 +6545,16 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) {
assert(a->type->id == b->type->id);
assert(a->special == ConstValSpecialStatic);
assert(b->special == ConstValSpecialStatic);
+ if (a->type == b->type) {
+ switch (type_has_one_possible_value(g, a->type)) {
+ case OnePossibleValueInvalid:
+ zig_unreachable();
+ case OnePossibleValueNo:
+ break;
+ case OnePossibleValueYes:
+ return true;
+ }
+ }
switch (a->type->id) {
case ZigTypeIdOpaque:
zig_unreachable();
@@ -6709,15 +6720,10 @@ static void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val
render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr));
return;
case ConstPtrSpecialBaseArray:
- if (const_val->data.x_ptr.data.base_array.is_cstr) {
- buf_appendf(buf, "*(c str lit)");
- return;
- } else {
- buf_appendf(buf, "*");
- // TODO we need a source node for const_ptr_pointee because it can generate compile errors
- render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr));
- return;
- }
+ buf_appendf(buf, "*");
+ // TODO we need a source node for const_ptr_pointee because it can generate compile errors
+ render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr));
+ return;
case ConstPtrSpecialHardCodedAddr:
buf_appendf(buf, "(%s)(%" ZIG_PRI_x64 ")", buf_ptr(&type_entry->name),
const_val->data.x_ptr.data.hard_coded_addr.addr);
@@ -8653,14 +8659,16 @@ static void resolve_llvm_types_array(CodeGen *g, ZigType *type) {
ZigType *elem_type = type->data.array.child_type;
+ uint64_t extra_len_from_null = type->data.array.is_null_terminated ? 1 : 0;
+ uint64_t full_len = type->data.array.len + extra_len_from_null;
// TODO https://github.com/ziglang/zig/issues/1424
- type->llvm_type = LLVMArrayType(get_llvm_type(g, elem_type), (unsigned)type->data.array.len);
+ type->llvm_type = LLVMArrayType(get_llvm_type(g, elem_type), (unsigned)full_len);
uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, type->llvm_type);
uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, type->llvm_type);
type->llvm_di_type = ZigLLVMCreateDebugArrayType(g->dbuilder, debug_size_in_bits,
- debug_align_in_bits, get_llvm_di_type(g, elem_type), (int)type->data.array.len);
+ debug_align_in_bits, get_llvm_di_type(g, elem_type), (int)full_len);
}
static void resolve_llvm_types_fn_type(CodeGen *g, ZigType *fn_type) {
@@ -9150,3 +9158,24 @@ Error analyze_import(CodeGen *g, ZigType *source_import, Buf *import_target_str,
*out_import = add_source_file(g, target_package, resolved_path, import_code, source_kind);
return ErrorNone;
}
+
+
+void IrExecutable::src() {
+ IrExecutable *it;
+ for (it = this; it != nullptr && it->source_node != nullptr; it = it->parent_exec) {
+ it->source_node->src();
+ }
+}
+
+ConstExprValue *get_null_value(ZigType *ty) {
+ if (ty->id == ZigTypeIdInt || ty->id == ZigTypeIdComptimeInt) {
+ return create_const_unsigned_negative(ty, 0, false);
+ } else if (ty->id == ZigTypeIdFloat || ty->id == ZigTypeIdComptimeFloat) {
+ return create_const_float(ty, NAN);
+ } else if (ty->id == ZigTypeIdOptional) {
+ return create_const_null(ty);
+ } else {
+ zig_unreachable();
+ }
+}
+
diff --git a/src/analyze.hpp b/src/analyze.hpp
index a1e38a43d7..a3d4621178 100644
--- a/src/analyze.hpp
+++ b/src/analyze.hpp
@@ -126,9 +126,6 @@ ScopeExpr *create_expr_scope(CodeGen *g, AstNode *node, Scope *parent);
void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str);
ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str);
-void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *c_str);
-ConstExprValue *create_const_c_str_lit(CodeGen *g, Buf *c_str);
-
void init_const_bigint(ConstExprValue *const_val, ZigType *type, const BigInt *bigint);
ConstExprValue *create_const_bigint(ZigType *type, const BigInt *bigint);
@@ -176,6 +173,9 @@ ConstExprValue *create_const_slice(CodeGen *g, ConstExprValue *array_val, size_t
void init_const_arg_tuple(CodeGen *g, ConstExprValue *const_val, size_t arg_index_start, size_t arg_index_end);
ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_t arg_index_end);
+void init_const_null(ConstExprValue *const_val, ZigType *type);
+ConstExprValue *create_const_null(ZigType *type);
+
ConstExprValue *create_const_vals(size_t count);
ConstExprValue **alloc_const_vals_ptrs(size_t count);
ConstExprValue **realloc_const_vals_ptrs(ConstExprValue **ptr, size_t old_count, size_t new_count);
@@ -275,5 +275,6 @@ IrInstruction *ir_create_alloca(CodeGen *g, Scope *scope, AstNode *source_node,
ZigType *var_type, const char *name_hint);
Error analyze_import(CodeGen *codegen, ZigType *source_import, Buf *import_target_str,
ZigType **out_import, Buf **out_import_target_path, Buf *out_full_path);
-
+ConstExprValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry);
+ConstExprValue *get_null_value(ZigType *ty);
#endif
diff --git a/src/ast_render.cpp b/src/ast_render.cpp
index 34cbed245a..53388fa033 100644
--- a/src/ast_render.cpp
+++ b/src/ast_render.cpp
@@ -619,9 +619,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
break;
case NodeTypeStringLiteral:
{
- if (node->data.string_literal.c) {
- fprintf(ar->f, "c");
- }
Buf tmp_buf = BUF_INIT;
string_literal_escape(node->data.string_literal.buf, &tmp_buf);
fprintf(ar->f, "\"%s\"", buf_ptr(&tmp_buf));
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 5def04575e..4fc3b968c1 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -949,7 +949,7 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {
if (!val->global_refs->llvm_global) {
Buf *buf_msg = panic_msg_buf(msg_id);
- ConstExprValue *array_val = create_const_str_lit(g, buf_msg);
+ ConstExprValue *array_val = create_const_str_lit(g, buf_msg)->data.x_ptr.data.ref.pointee;
init_const_slice(g, val, array_val, 0, buf_len(buf_msg), true);
render_const_val(g, val, "");
@@ -2784,14 +2784,6 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
IrInstruction *op1 = bin_op_instruction->op1;
IrInstruction *op2 = bin_op_instruction->op2;
- assert(op1->value.type == op2->value.type || op_id == IrBinOpBitShiftLeftLossy ||
- op_id == IrBinOpBitShiftLeftExact || op_id == IrBinOpBitShiftRightLossy ||
- op_id == IrBinOpBitShiftRightExact ||
- (op1->value.type->id == ZigTypeIdErrorSet && op2->value.type->id == ZigTypeIdErrorSet) ||
- (op1->value.type->id == ZigTypeIdPointer &&
- (op_id == IrBinOpAdd || op_id == IrBinOpSub) &&
- op1->value.type->data.pointer.ptr_len != PtrLenSingle)
- );
ZigType *operand_type = op1->value.type;
ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type;
@@ -2848,7 +2840,6 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
AddSubMulMul;
if (scalar_type->id == ZigTypeIdPointer) {
- assert(scalar_type->data.pointer.ptr_len != PtrLenSingle);
LLVMValueRef subscript_value;
if (operand_type->id == ZigTypeIdVector)
zig_panic("TODO: Implement vector operations on pointers.");
@@ -3077,7 +3068,14 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
case CastOpNumLitToConcrete:
zig_unreachable();
case CastOpNoop:
- return expr_val;
+ if (actual_type->id == ZigTypeIdPointer && wanted_type->id == ZigTypeIdPointer &&
+ actual_type->data.pointer.child_type->id == ZigTypeIdArray &&
+ wanted_type->data.pointer.child_type->id == ZigTypeIdArray)
+ {
+ return LLVMBuildBitCast(g->builder, expr_val, get_llvm_type(g, wanted_type), "");
+ } else {
+ return expr_val;
+ }
case CastOpIntToFloat:
assert(actual_type->id == ZigTypeIdInt);
if (actual_type->data.integral.is_signed) {
@@ -3709,8 +3707,9 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
array_type = array_type->data.pointer.child_type;
}
if (safety_check_on) {
- LLVMValueRef end = LLVMConstInt(g->builtin_types.entry_usize->llvm_type,
- array_type->data.array.len, false);
+ uint64_t extra_len_from_null = array_type->data.array.is_null_terminated ? 1 : 0;
+ uint64_t full_len = array_type->data.array.len + extra_len_from_null;
+ LLVMValueRef end = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, full_len, false);
add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, end);
}
if (array_ptr_type->data.pointer.host_int_bytes != 0) {
@@ -6637,11 +6636,20 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con
ConstExprValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val;
assert(array_const_val->type->id == ZigTypeIdArray);
if (!type_has_bits(array_const_val->type)) {
- // make this a null pointer
- ZigType *usize = g->builtin_types.entry_usize;
- const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type),
- get_llvm_type(g, const_val->type));
- return const_val->global_refs->llvm_value;
+ if (array_const_val->type->data.array.is_null_terminated) {
+ ConstExprValue *pointee = get_null_value(array_const_val->type->data.array.child_type);
+ render_const_val(g, pointee, "");
+ render_const_val_global(g, pointee, "");
+ const_val->global_refs->llvm_value = LLVMConstBitCast(pointee->global_refs->llvm_global,
+ get_llvm_type(g, const_val->type));
+ return const_val->global_refs->llvm_value;
+ } else {
+ // make this a null pointer
+ ZigType *usize = g->builtin_types.entry_usize;
+ const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type),
+ get_llvm_type(g, const_val->type));
+ return const_val->global_refs->llvm_value;
+ }
}
size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index;
LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val, elem_index);
@@ -6955,7 +6963,9 @@ check: switch (const_val->special) {
case ConstArraySpecialUndef:
return LLVMGetUndef(get_llvm_type(g, type_entry));
case ConstArraySpecialNone: {
- LLVMValueRef *values = allocate(len);
+ uint64_t extra_len_from_null = type_entry->data.array.is_null_terminated ? 1 : 0;
+ uint64_t full_len = len + extra_len_from_null;
+ LLVMValueRef *values = allocate(full_len);
LLVMTypeRef element_type_ref = get_llvm_type(g, type_entry->data.array.child_type);
bool make_unnamed_struct = false;
for (uint64_t i = 0; i < len; i += 1) {
@@ -6964,15 +6974,19 @@ check: switch (const_val->special) {
values[i] = val;
make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(g, elem_value->type, val);
}
+ if (type_entry->data.array.is_null_terminated) {
+ values[len] = LLVMConstNull(element_type_ref);
+ }
if (make_unnamed_struct) {
- return LLVMConstStruct(values, len, true);
+ return LLVMConstStruct(values, full_len, true);
} else {
- return LLVMConstArray(element_type_ref, values, (unsigned)len);
+ return LLVMConstArray(element_type_ref, values, (unsigned)full_len);
}
}
case ConstArraySpecialBuf: {
Buf *buf = const_val->data.x_array.data.s_buf;
- return LLVMConstString(buf_ptr(buf), (unsigned)buf_len(buf), true);
+ return LLVMConstString(buf_ptr(buf), (unsigned)buf_len(buf),
+ !type_entry->data.array.is_null_terminated);
}
}
zig_unreachable();
@@ -9092,7 +9106,7 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
this_val->data.x_struct.fields = alloc_const_vals_ptrs(2);
ConstExprValue *name_field = this_val->data.x_struct.fields[0];
- ConstExprValue *name_array_val = create_const_str_lit(g, &test_fn_entry->symbol_name);
+ ConstExprValue *name_array_val = create_const_str_lit(g, &test_fn_entry->symbol_name)->data.x_ptr.data.ref.pointee;
init_const_slice(g, name_field, name_array_val, 0, buf_len(&test_fn_entry->symbol_name), true);
ConstExprValue *fn_field = this_val->data.x_struct.fields[1];
@@ -10415,6 +10429,7 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget
g->external_prototypes.init(8);
g->string_literals_table.init(16);
g->type_info_cache.init(32);
+ g->one_possible_values.init(32);
g->is_test_build = is_test_build;
g->is_single_threaded = false;
buf_resize(&g->global_asm, 0);
diff --git a/src/ir.cpp b/src/ir.cpp
index c910d4800d..4a3d89c0c1 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -66,6 +66,8 @@ enum ConstCastResultId {
ConstCastResultIdUnresolvedInferredErrSet,
ConstCastResultIdAsyncAllocatorType,
ConstCastResultIdBadAllowsZero,
+ ConstCastResultIdArrayChild,
+ ConstCastResultIdBadNullTermArrays,
};
struct ConstCastOnly;
@@ -87,7 +89,9 @@ struct ConstCastErrUnionErrSetMismatch;
struct ConstCastErrUnionPayloadMismatch;
struct ConstCastErrSetMismatch;
struct ConstCastTypeMismatch;
+struct ConstCastArrayMismatch;
struct ConstCastBadAllowsZero;
+struct ConstCastBadNullTermArrays;
struct ConstCastOnly {
ConstCastResultId id;
@@ -99,11 +103,13 @@ struct ConstCastOnly {
ConstCastErrUnionPayloadMismatch *error_union_payload;
ConstCastErrUnionErrSetMismatch *error_union_error_set;
ConstCastTypeMismatch *type_mismatch;
+ ConstCastArrayMismatch *array_mismatch;
ConstCastOnly *return_type;
ConstCastOnly *null_wrap_ptr_child;
ConstCastArg fn_arg;
ConstCastArgNoAlias arg_no_alias;
ConstCastBadAllowsZero *bad_allows_zero;
+ ConstCastBadNullTermArrays *bad_null_term_arrays;
} data;
};
@@ -130,6 +136,12 @@ struct ConstCastSliceMismatch {
ZigType *actual_child;
};
+struct ConstCastArrayMismatch {
+ ConstCastOnly child;
+ ZigType *wanted_child;
+ ZigType *actual_child;
+};
+
struct ConstCastErrUnionErrSetMismatch {
ConstCastOnly child;
ZigType *wanted_err_set;
@@ -151,6 +163,12 @@ struct ConstCastBadAllowsZero {
ZigType *actual_type;
};
+struct ConstCastBadNullTermArrays {
+ ConstCastOnly child;
+ ZigType *wanted_type;
+ ZigType *actual_type;
+};
+
static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope);
static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval,
@@ -217,10 +235,7 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c
case OnePossibleValueInvalid:
zig_unreachable();
case OnePossibleValueYes:
- result = create_const_vals(1);
- result->type = const_val->type->data.pointer.child_type;
- result->special = ConstValSpecialStatic;
- return result;
+ return get_the_one_possible_value(g, const_val->type->data.pointer.child_type);
case OnePossibleValueNo:
break;
}
@@ -233,8 +248,13 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c
break;
case ConstPtrSpecialBaseArray: {
ConstExprValue *array_val = const_val->data.x_ptr.data.base_array.array_val;
- expand_undef_array(g, array_val);
- result = &array_val->data.x_array.data.s_none.elements[const_val->data.x_ptr.data.base_array.elem_index];
+ if (const_val->data.x_ptr.data.base_array.elem_index == array_val->type->data.array.len) {
+ assert(array_val->type->data.array.is_null_terminated);
+ result = get_null_value(array_val->type->data.array.child_type);
+ } else {
+ expand_undef_array(g, array_val);
+ result = &array_val->data.x_array.data.s_none.elements[const_val->data.x_ptr.data.base_array.elem_index];
+ }
break;
}
case ConstPtrSpecialBaseStruct: {
@@ -282,20 +302,20 @@ static bool slice_is_const(ZigType *type) {
// This function returns true when you can change the type of a ConstExprValue and the
// value remains meaningful.
-static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {
- if (a == b)
+static bool types_have_same_zig_comptime_repr(ZigType *expected, ZigType *actual) {
+ if (expected == actual)
return true;
- if (get_codegen_ptr_type(a) != nullptr && get_codegen_ptr_type(b) != nullptr)
+ if (get_codegen_ptr_type(expected) != nullptr && get_codegen_ptr_type(actual) != nullptr)
return true;
- if (is_opt_err_set(a) && is_opt_err_set(b))
+ if (is_opt_err_set(expected) && is_opt_err_set(actual))
return true;
- if (a->id != b->id)
+ if (expected->id != actual->id)
return false;
- switch (a->id) {
+ switch (expected->id) {
case ZigTypeIdInvalid:
case ZigTypeIdUnreachable:
zig_unreachable();
@@ -314,12 +334,11 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {
case ZigTypeIdAnyFrame:
return true;
case ZigTypeIdFloat:
- return a->data.floating.bit_count == b->data.floating.bit_count;
+ return expected->data.floating.bit_count == actual->data.floating.bit_count;
case ZigTypeIdInt:
- return a->data.integral.is_signed == b->data.integral.is_signed;
+ return expected->data.integral.is_signed == actual->data.integral.is_signed;
case ZigTypeIdStruct:
- return is_slice(a) && is_slice(b);
- case ZigTypeIdArray:
+ return is_slice(expected) && is_slice(actual);
case ZigTypeIdOptional:
case ZigTypeIdErrorUnion:
case ZigTypeIdEnum:
@@ -329,6 +348,10 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {
case ZigTypeIdVector:
case ZigTypeIdFnFrame:
return false;
+ case ZigTypeIdArray:
+ return expected->data.array.len == actual->data.array.len &&
+ expected->data.array.child_type == actual->data.array.child_type &&
+ (!expected->data.array.is_null_terminated || actual->data.array.is_null_terminated);
}
zig_unreachable();
}
@@ -1299,12 +1322,6 @@ static IrInstruction *ir_build_const_str_lit(IrBuilder *irb, Scope *scope, AstNo
return instruction;
}
-static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, Scope *scope, AstNode *source_node, Buf *str) {
- IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, source_node);
- init_const_c_str_lit(irb->codegen, &const_instruction->base.value, str);
- return &const_instruction->base;
-}
-
static IrInstruction *ir_build_bin_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrBinOp op_id,
IrInstruction *op1, IrInstruction *op2, bool safety_check_on)
{
@@ -6932,11 +6949,7 @@ static IrInstruction *ir_gen_enum_literal(IrBuilder *irb, Scope *scope, AstNode
static IrInstruction *ir_gen_string_literal(IrBuilder *irb, Scope *scope, AstNode *node) {
assert(node->type == NodeTypeStringLiteral);
- if (node->data.string_literal.c) {
- return ir_build_const_c_str_lit(irb, scope, node, node->data.string_literal.buf);
- } else {
- return ir_build_const_str_lit(irb, scope, node, node->data.string_literal.buf);
- }
+ return ir_build_const_str_lit(irb, scope, node, node->data.string_literal.buf);
}
static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *node) {
@@ -8662,7 +8675,15 @@ ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprVal
assert(val != nullptr);
assert(const_val->type->id == ZigTypeIdPointer);
ZigType *expected_type = const_val->type->data.pointer.child_type;
- if (!types_have_same_zig_comptime_repr(val->type, expected_type)) {
+ switch (type_has_one_possible_value(codegen, expected_type)) {
+ case OnePossibleValueInvalid:
+ return nullptr;
+ case OnePossibleValueNo:
+ break;
+ case OnePossibleValueYes:
+ return get_the_one_possible_value(codegen, expected_type);
+ }
+ if (!types_have_same_zig_comptime_repr(expected_type, val->type)) {
if ((err = eval_comptime_ptr_reinterpret(ira, codegen, source_node, const_val)))
return nullptr;
return const_ptr_pointee_unchecked(codegen, const_val);
@@ -9876,6 +9897,35 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
}
}
+ // arrays
+ if (wanted_type->id == ZigTypeIdArray && actual_type->id == ZigTypeIdArray &&
+ wanted_type->data.array.len == actual_type->data.array.len)
+ {
+ ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.array.child_type,
+ actual_type->data.array.child_type, source_node, wanted_is_mutable);
+ if (child.id == ConstCastResultIdInvalid)
+ return child;
+ if (child.id != ConstCastResultIdOk) {
+ result.id = ConstCastResultIdArrayChild;
+ result.data.array_mismatch = allocate_nonzero(1);
+ result.data.array_mismatch->child = child;
+ result.data.array_mismatch->wanted_child = wanted_type->data.array.child_type;
+ result.data.array_mismatch->actual_child = actual_type->data.array.child_type;
+ return result;
+ }
+ bool ok_null_terminated = !wanted_type->data.array.is_null_terminated ||
+ actual_type->data.array.is_null_terminated;
+ if (!ok_null_terminated) {
+ result.id = ConstCastResultIdBadNullTermArrays;
+ result.data.bad_null_term_arrays = allocate_nonzero(1);
+ result.data.bad_null_term_arrays->child = child;
+ result.data.bad_null_term_arrays->wanted_type = wanted_type;
+ result.data.bad_null_term_arrays->actual_type = actual_type;
+ return result;
+ }
+ return result;
+ }
+
// slice const
if (is_slice(wanted_type) && is_slice(actual_type)) {
ZigType *actual_ptr_type = actual_type->data.structure.fields[slice_ptr_index]->type_entry;
@@ -10692,6 +10742,42 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
continue;
}
+
+ // *[N]T and *[M]T
+ if (cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenSingle &&
+ cur_type->data.pointer.child_type->id == ZigTypeIdArray &&
+ prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenSingle &&
+ prev_type->data.pointer.child_type->id == ZigTypeIdArray &&
+ (cur_type->data.pointer.is_const || !prev_type->data.pointer.is_const ||
+ prev_type->data.pointer.child_type->data.array.len == 0) &&
+ (cur_type->data.pointer.child_type->data.array.is_null_terminated ||
+ !prev_type->data.pointer.child_type->data.array.is_null_terminated) &&
+ types_match_const_cast_only(ira,
+ cur_type->data.pointer.child_type->data.array.child_type,
+ prev_type->data.pointer.child_type->data.array.child_type,
+ source_node, !cur_type->data.pointer.is_const).id == ConstCastResultIdOk)
+ {
+ prev_inst = cur_inst;
+ convert_to_const_slice = true;
+ continue;
+ }
+ if (prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenSingle &&
+ prev_type->data.pointer.child_type->id == ZigTypeIdArray &&
+ cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenSingle &&
+ cur_type->data.pointer.child_type->id == ZigTypeIdArray &&
+ (prev_type->data.pointer.is_const || !cur_type->data.pointer.is_const ||
+ cur_type->data.pointer.child_type->data.array.len == 0) &&
+ (prev_type->data.pointer.child_type->data.array.is_null_terminated ||
+ !cur_type->data.pointer.child_type->data.array.is_null_terminated) &&
+ types_match_const_cast_only(ira,
+ prev_type->data.pointer.child_type->data.array.child_type,
+ cur_type->data.pointer.child_type->data.array.child_type,
+ source_node, !prev_type->data.pointer.is_const).id == ConstCastResultIdOk)
+ {
+ convert_to_const_slice = true;
+ continue;
+ }
+
// [N]T to []T
if (prev_type->id == ZigTypeIdArray && is_slice(cur_type) &&
(cur_type->data.structure.fields[slice_ptr_index]->type_entry->data.pointer.is_const ||
@@ -10740,16 +10826,33 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
free(errors);
if (convert_to_const_slice) {
- assert(prev_inst->value.type->id == ZigTypeIdArray);
- ZigType *ptr_type = get_pointer_to_type_extra(
- ira->codegen, prev_inst->value.type->data.array.child_type,
- true, false, PtrLenUnknown,
- 0, 0, 0, false);
- ZigType *slice_type = get_slice_type(ira->codegen, ptr_type);
- if (err_set_type != nullptr) {
- return get_error_union_type(ira->codegen, err_set_type, slice_type);
+ if (prev_inst->value.type->id == ZigTypeIdArray) {
+ ZigType *ptr_type = get_pointer_to_type_extra(
+ ira->codegen, prev_inst->value.type->data.array.child_type,
+ true, false, PtrLenUnknown,
+ 0, 0, 0, false);
+ ZigType *slice_type = get_slice_type(ira->codegen, ptr_type);
+ if (err_set_type != nullptr) {
+ return get_error_union_type(ira->codegen, err_set_type, slice_type);
+ } else {
+ return slice_type;
+ }
+ } else if (prev_inst->value.type->id == ZigTypeIdPointer) {
+ ZigType *array_type = prev_inst->value.type->data.pointer.child_type;
+ src_assert(array_type->id == ZigTypeIdArray, source_node);
+ ZigType *ptr_type = get_pointer_to_type_extra(
+ ira->codegen, array_type->data.array.child_type,
+ prev_inst->value.type->data.pointer.is_const, false,
+ array_type->data.array.is_null_terminated ? PtrLenNull : PtrLenUnknown,
+ 0, 0, 0, false);
+ ZigType *slice_type = get_slice_type(ira->codegen, ptr_type);
+ if (err_set_type != nullptr) {
+ return get_error_union_type(ira->codegen, err_set_type, slice_type);
+ } else {
+ return slice_type;
+ }
} else {
- return slice_type;
+ zig_unreachable();
}
} else if (err_set_type != nullptr) {
if (prev_inst->value.type->id == ZigTypeIdErrorSet) {
@@ -10970,7 +11073,6 @@ static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira,
result->value.data.x_ptr.mut = value->value.data.x_ptr.mut;
result->value.data.x_ptr.data.base_array.array_val = pointee;
result->value.data.x_ptr.data.base_array.elem_index = 0;
- result->value.data.x_ptr.data.base_array.is_cstr = false;
return result;
}
}
@@ -10982,31 +11084,31 @@ static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira,
}
static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruction *source_instr,
- IrInstruction *value, ZigType *wanted_type, ResultLoc *result_loc)
+ IrInstruction *array_ptr, ZigType *wanted_type, ResultLoc *result_loc)
{
Error err;
- if ((err = type_resolve(ira->codegen, value->value.type->data.pointer.child_type,
+ if ((err = type_resolve(ira->codegen, array_ptr->value.type->data.pointer.child_type,
ResolveStatusAlignmentKnown)))
{
return ira->codegen->invalid_instruction;
}
- wanted_type = adjust_slice_align(ira->codegen, wanted_type, get_ptr_align(ira->codegen, value->value.type));
+ wanted_type = adjust_slice_align(ira->codegen, wanted_type, get_ptr_align(ira->codegen, array_ptr->value.type));
- if (instr_is_comptime(value)) {
- ConstExprValue *pointee = const_ptr_pointee(ira, ira->codegen, &value->value, source_instr->source_node);
+ if (instr_is_comptime(array_ptr)) {
+ ConstExprValue *pointee = const_ptr_pointee(ira, ira->codegen, &array_ptr->value, source_instr->source_node);
if (pointee == nullptr)
return ira->codegen->invalid_instruction;
if (pointee->special != ConstValSpecialRuntime) {
- assert(value->value.type->id == ZigTypeIdPointer);
- ZigType *array_type = value->value.type->data.pointer.child_type;
+ assert(array_ptr->value.type->id == ZigTypeIdPointer);
+ ZigType *array_type = array_ptr->value.type->data.pointer.child_type;
assert(is_slice(wanted_type));
bool is_const = wanted_type->data.structure.fields[slice_ptr_index]->type_entry->data.pointer.is_const;
IrInstruction *result = ir_const(ira, source_instr, wanted_type);
init_const_slice(ira->codegen, &result->value, pointee, 0, array_type->data.array.len, is_const);
- result->value.data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = value->value.data.x_ptr.mut;
+ result->value.data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr->value.data.x_ptr.mut;
result->value.type = wanted_type;
return result;
}
@@ -11018,7 +11120,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruc
if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) {
return result_loc_inst;
}
- return ir_build_ptr_of_array_to_slice(ira, source_instr, wanted_type, value, result_loc_inst);
+ return ir_build_ptr_of_array_to_slice(ira, source_instr, wanted_type, array_ptr, result_loc_inst);
}
static IrBasicBlock *ir_get_new_bb(IrAnalyze *ira, IrBasicBlock *old_bb, IrInstruction *ref_old_instruction) {
@@ -12483,6 +12585,8 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa
case ConstCastResultIdFnArgNoAlias: // TODO
case ConstCastResultIdUnresolvedInferredErrSet: // TODO
case ConstCastResultIdAsyncAllocatorType: // TODO
+ case ConstCastResultIdArrayChild: // TODO
+ case ConstCastResultIdBadNullTermArrays: // TODO
break;
}
}
@@ -12795,7 +12899,6 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
}
-
// cast from [N]T to []const T
// TODO: once https://github.com/ziglang/zig/issues/265 lands, remove this
if (is_slice(wanted_type) && actual_type->id == ZigTypeIdArray) {
@@ -12834,23 +12937,46 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
}
}
- // *[N]T to [*]T and [*c]T
- if (wanted_type->id == ZigTypeIdPointer &&
- (wanted_type->data.pointer.ptr_len == PtrLenUnknown || wanted_type->data.pointer.ptr_len == PtrLenC) &&
+ // *[N]T to ?[]const T
+ if (wanted_type->id == ZigTypeIdOptional &&
+ is_slice(wanted_type->data.maybe.child_type) &&
actual_type->id == ZigTypeIdPointer &&
actual_type->data.pointer.ptr_len == PtrLenSingle &&
actual_type->data.pointer.child_type->id == ZigTypeIdArray)
{
- if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
+ IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.maybe.child_type, value, nullptr);
+ if (type_is_invalid(cast1->value.type))
return ira->codegen->invalid_instruction;
- if ((err = type_resolve(ira->codegen, wanted_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
+
+ IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1, result_loc);
+ if (type_is_invalid(cast2->value.type))
return ira->codegen->invalid_instruction;
- if (get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, wanted_type) &&
- types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
- actual_type->data.pointer.child_type->data.array.child_type, source_node,
- !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
+
+ return cast2;
+ }
+
+ // *[N]T to [*]T and [*c]T
+ if (wanted_type->id == ZigTypeIdPointer &&
+ (wanted_type->data.pointer.ptr_len == PtrLenUnknown || wanted_type->data.pointer.ptr_len == PtrLenC ||
+ wanted_type->data.pointer.ptr_len == PtrLenNull) &&
+ actual_type->id == ZigTypeIdPointer &&
+ actual_type->data.pointer.ptr_len == PtrLenSingle &&
+ actual_type->data.pointer.child_type->id == ZigTypeIdArray)
+ {
+ if (wanted_type->data.pointer.ptr_len != PtrLenNull ||
+ actual_type->data.pointer.child_type->data.array.is_null_terminated)
{
- return ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, wanted_type);
+ if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
+ return ira->codegen->invalid_instruction;
+ if ((err = type_resolve(ira->codegen, wanted_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
+ return ira->codegen->invalid_instruction;
+ if (get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, wanted_type) &&
+ types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
+ actual_type->data.pointer.child_type->data.array.child_type, source_node,
+ !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
+ {
+ return ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, wanted_type);
+ }
}
}
@@ -14544,8 +14670,6 @@ static bool ok_float_op(IrBinOp op) {
}
static bool is_pointer_arithmetic_allowed(ZigType *lhs_type, IrBinOp op) {
- if (lhs_type->id != ZigTypeIdPointer)
- return false;
switch (op) {
case IrBinOpAdd:
case IrBinOpSub:
@@ -14553,15 +14677,17 @@ static bool is_pointer_arithmetic_allowed(ZigType *lhs_type, IrBinOp op) {
default:
return false;
}
+ if (lhs_type->id != ZigTypeIdPointer)
+ return false;
switch (lhs_type->data.pointer.ptr_len) {
case PtrLenSingle:
- return false;
+ return lhs_type->data.pointer.child_type->id == ZigTypeIdArray;
case PtrLenUnknown:
case PtrLenNull:
case PtrLenC:
- break;
+ return true;
}
- return true;
+ zig_unreachable();
}
static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *instruction) {
@@ -14823,6 +14949,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
if (!op2_val)
return ira->codegen->invalid_instruction;
+ bool is_null_terminated = false;
ConstExprValue *op1_array_val;
size_t op1_array_index;
size_t op1_array_end;
@@ -14834,13 +14961,14 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
op1_array_end = op1_type->data.array.len;
} else if (op1_type->id == ZigTypeIdPointer &&
op1_type->data.pointer.child_type == ira->codegen->builtin_types.entry_u8 &&
- op1_val->data.x_ptr.special == ConstPtrSpecialBaseArray &&
- op1_val->data.x_ptr.data.base_array.is_cstr)
+ op1_type->data.pointer.ptr_len == PtrLenNull &&
+ op1_val->data.x_ptr.special == ConstPtrSpecialBaseArray)
{
child_type = op1_type->data.pointer.child_type;
op1_array_val = op1_val->data.x_ptr.data.base_array.array_val;
op1_array_index = op1_val->data.x_ptr.data.base_array.elem_index;
- op1_array_end = op1_array_val->type->data.array.len - 1;
+ op1_array_end = op1_array_val->type->data.array.len;
+ is_null_terminated = true;
} else if (is_slice(op1_type)) {
ZigType *ptr_type = op1_type->data.structure.fields[slice_ptr_index]->type_entry;
child_type = ptr_type->data.pointer.child_type;
@@ -14850,9 +14978,20 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
op1_array_index = ptr_val->data.x_ptr.data.base_array.elem_index;
ConstExprValue *len_val = op1_val->data.x_struct.fields[slice_len_index];
op1_array_end = op1_array_index + bigint_as_usize(&len_val->data.x_bigint);
+ } else if (op1_type->id == ZigTypeIdPointer && op1_type->data.pointer.ptr_len == PtrLenSingle &&
+ op1_type->data.pointer.child_type->id == ZigTypeIdArray)
+ {
+ ZigType *array_type = op1_type->data.pointer.child_type;
+ child_type = array_type->data.array.child_type;
+ op1_array_val = const_ptr_pointee(ira, ira->codegen, op1_val, op1->source_node);
+ if (op1_array_val == nullptr)
+ return ira->codegen->invalid_instruction;
+ op1_array_index = 0;
+ op1_array_end = array_type->data.array.len;
+ is_null_terminated = is_null_terminated || array_type->data.array.is_null_terminated;
} else {
ir_add_error(ira, op1,
- buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op1->value.type->name)));
+ buf_sprintf("expected array, found '%s'", buf_ptr(&op1->value.type->name)));
return ira->codegen->invalid_instruction;
}
@@ -14866,14 +15005,14 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
op2_array_index = 0;
op2_array_end = op2_array_val->type->data.array.len;
} else if (op2_type->id == ZigTypeIdPointer &&
- op2_type->data.pointer.child_type == ira->codegen->builtin_types.entry_u8 &&
- op2_val->data.x_ptr.special == ConstPtrSpecialBaseArray &&
- op2_val->data.x_ptr.data.base_array.is_cstr)
+ op2_type->data.pointer.ptr_len == PtrLenNull &&
+ op2_val->data.x_ptr.special == ConstPtrSpecialBaseArray)
{
- op2_type_valid = child_type == ira->codegen->builtin_types.entry_u8;
+ op2_type_valid = op2_type->data.pointer.child_type == child_type;
op2_array_val = op2_val->data.x_ptr.data.base_array.array_val;
op2_array_index = op2_val->data.x_ptr.data.base_array.elem_index;
- op2_array_end = op2_array_val->type->data.array.len - 1;
+ op2_array_end = op2_array_val->type->data.array.len;
+ is_null_terminated = true;
} else if (is_slice(op2_type)) {
ZigType *ptr_type = op2_type->data.structure.fields[slice_ptr_index]->type_entry;
op2_type_valid = ptr_type->data.pointer.child_type == child_type;
@@ -14883,6 +15022,17 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
op2_array_index = ptr_val->data.x_ptr.data.base_array.elem_index;
ConstExprValue *len_val = op2_val->data.x_struct.fields[slice_len_index];
op2_array_end = op2_array_index + bigint_as_usize(&len_val->data.x_bigint);
+ } else if (op2_type->id == ZigTypeIdPointer && op2_type->data.pointer.ptr_len == PtrLenSingle &&
+ op2_type->data.pointer.child_type->id == ZigTypeIdArray)
+ {
+ ZigType *array_type = op2_type->data.pointer.child_type;
+ op2_type_valid = array_type->data.array.child_type == child_type;
+ op2_array_val = const_ptr_pointee(ira, ira->codegen, op2_val, op2->source_node);
+ if (op2_array_val == nullptr)
+ return ira->codegen->invalid_instruction;
+ op2_array_index = 0;
+ op2_array_end = array_type->data.array.len;
+ is_null_terminated = is_null_terminated || array_type->data.array.is_null_terminated;
} else {
ir_add_error(ira, op2,
buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op2->value.type->name)));
@@ -14905,6 +15055,14 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
result->value.type = get_array_type(ira->codegen, child_type, new_len, false);
out_array_val = out_val;
+ } else if (op1_type->id == ZigTypeIdPointer || op2_type->id == ZigTypeIdPointer) {
+ out_array_val = create_const_vals(1);
+ out_array_val->special = ConstValSpecialStatic;
+ out_array_val->type = get_array_type(ira->codegen, child_type, new_len, is_null_terminated);
+
+ out_val->data.x_ptr.special = ConstPtrSpecialRef;
+ out_val->data.x_ptr.data.ref.pointee = out_array_val;
+ out_val->type = get_pointer_to_type(ira->codegen, out_array_val->type, true);
} else if (is_slice(op1_type) || is_slice(op2_type)) {
ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, child_type,
true, false, PtrLenUnknown, 0, 0, 0, false);
@@ -14925,22 +15083,20 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
out_val->data.x_struct.fields[slice_len_index]->special = ConstValSpecialStatic;
bigint_init_unsigned(&out_val->data.x_struct.fields[slice_len_index]->data.x_bigint, new_len);
} else {
- new_len += 1; // null byte
-
- // TODO make this `[*]null T` instead of `[*]T`
- result->value.type = get_pointer_to_type_extra(ira->codegen, child_type, true, false, PtrLenUnknown, 0, 0, 0, false);
+ result->value.type = get_pointer_to_type_extra(ira->codegen, child_type, true, false, PtrLenNull,
+ 0, 0, 0, false);
out_array_val = create_const_vals(1);
out_array_val->special = ConstValSpecialStatic;
out_array_val->type = get_array_type(ira->codegen, child_type, new_len, false);
out_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
- out_val->data.x_ptr.data.base_array.is_cstr = true;
out_val->data.x_ptr.data.base_array.array_val = out_array_val;
out_val->data.x_ptr.data.base_array.elem_index = 0;
}
if (op1_array_val->data.x_array.special == ConstArraySpecialUndef &&
- op2_array_val->data.x_array.special == ConstArraySpecialUndef) {
+ op2_array_val->data.x_array.special == ConstArraySpecialUndef)
+ {
out_array_val->data.x_array.special = ConstArraySpecialUndef;
return result;
}
@@ -14978,20 +15134,34 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp *
if (type_is_invalid(op2->value.type))
return ira->codegen->invalid_instruction;
- ConstExprValue *array_val = ir_resolve_const(ira, op1, UndefBad);
- if (!array_val)
+ bool want_ptr_to_array = false;
+ ZigType *array_type;
+ ConstExprValue *array_val;
+ if (op1->value.type->id == ZigTypeIdArray) {
+ array_type = op1->value.type;
+ array_val = ir_resolve_const(ira, op1, UndefOk);
+ if (array_val == nullptr)
+ return ira->codegen->invalid_instruction;
+ } else if (op1->value.type->id == ZigTypeIdPointer && op1->value.type->data.pointer.ptr_len == PtrLenSingle &&
+ op1->value.type->data.pointer.child_type->id == ZigTypeIdArray)
+ {
+ array_type = op1->value.type->data.pointer.child_type;
+ IrInstruction *array_inst = ir_get_deref(ira, op1, op1, nullptr);
+ if (type_is_invalid(array_inst->value.type))
+ return ira->codegen->invalid_instruction;
+ array_val = ir_resolve_const(ira, array_inst, UndefOk);
+ if (array_val == nullptr)
+ return ira->codegen->invalid_instruction;
+ want_ptr_to_array = true;
+ } else {
+ ir_add_error(ira, op1, buf_sprintf("expected array type, found '%s'", buf_ptr(&op1->value.type->name)));
return ira->codegen->invalid_instruction;
+ }
uint64_t mult_amt;
if (!ir_resolve_usize(ira, op2, &mult_amt))
return ira->codegen->invalid_instruction;
- ZigType *array_type = op1->value.type;
- if (array_type->id != ZigTypeIdArray) {
- ir_add_error(ira, op1, buf_sprintf("expected array type, found '%s'", buf_ptr(&op1->value.type->name)));
- return ira->codegen->invalid_instruction;
- }
-
uint64_t old_array_len = array_type->data.array.len;
uint64_t new_array_len;
@@ -15001,42 +15171,59 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp *
}
ZigType *child_type = array_type->data.array.child_type;
+ ZigType *result_array_type = get_array_type(ira->codegen, child_type, new_array_len,
+ array_type->data.array.is_null_terminated);
- IrInstruction *result = ir_const(ira, &instruction->base,
- get_array_type(ira->codegen, child_type, new_array_len, false));
- ConstExprValue *out_val = &result->value;
- if (array_val->data.x_array.special == ConstArraySpecialUndef) {
- out_val->data.x_array.special = ConstArraySpecialUndef;
- return result;
- }
+ IrInstruction *array_result;
+ if (array_val->special == ConstValSpecialUndef || array_val->data.x_array.special == ConstArraySpecialUndef) {
+ array_result = ir_const_undef(ira, &instruction->base, result_array_type);
+ } else {
+ array_result = ir_const(ira, &instruction->base, result_array_type);
+ ConstExprValue *out_val = &array_result->value;
- switch (type_has_one_possible_value(ira->codegen, result->value.type)) {
- case OnePossibleValueInvalid:
- return ira->codegen->invalid_instruction;
- case OnePossibleValueYes:
- return result;
- case OnePossibleValueNo:
- break;
- }
+ switch (type_has_one_possible_value(ira->codegen, result_array_type)) {
+ case OnePossibleValueInvalid:
+ return ira->codegen->invalid_instruction;
+ case OnePossibleValueYes:
+ goto skip_computation;
+ case OnePossibleValueNo:
+ break;
+ }
- // TODO optimize the buf case
- expand_undef_array(ira->codegen, array_val);
- out_val->data.x_array.data.s_none.elements = create_const_vals(new_array_len);
+ // TODO optimize the buf case
+ expand_undef_array(ira->codegen, array_val);
+ size_t extra_null_term = array_type->data.array.is_null_terminated ? 1 : 0;
+ out_val->data.x_array.data.s_none.elements = create_const_vals(new_array_len + extra_null_term);
- uint64_t i = 0;
- for (uint64_t x = 0; x < mult_amt; x += 1) {
- for (uint64_t y = 0; y < old_array_len; y += 1) {
+ uint64_t i = 0;
+ for (uint64_t x = 0; x < mult_amt; x += 1) {
+ for (uint64_t y = 0; y < old_array_len; y += 1) {
+ ConstExprValue *elem_dest_val = &out_val->data.x_array.data.s_none.elements[i];
+ copy_const_val(elem_dest_val, &array_val->data.x_array.data.s_none.elements[y], false);
+ elem_dest_val->parent.id = ConstParentIdArray;
+ elem_dest_val->parent.data.p_array.array_val = out_val;
+ elem_dest_val->parent.data.p_array.elem_index = i;
+ i += 1;
+ }
+ }
+ assert(i == new_array_len);
+
+ if (array_type->data.array.is_null_terminated) {
+ ConstExprValue *null_value = get_null_value(array_type->data.array.child_type);
ConstExprValue *elem_dest_val = &out_val->data.x_array.data.s_none.elements[i];
- copy_const_val(elem_dest_val, &array_val->data.x_array.data.s_none.elements[y], false);
+ copy_const_val(elem_dest_val, null_value, false);
elem_dest_val->parent.id = ConstParentIdArray;
elem_dest_val->parent.data.p_array.array_val = out_val;
elem_dest_val->parent.data.p_array.elem_index = i;
i += 1;
}
}
- assert(i == new_array_len);
-
- return result;
+skip_computation:
+ if (want_ptr_to_array) {
+ return ir_get_ref(ira, &instruction->base, array_result, true, false);
+ } else {
+ return array_result;
+ }
}
static IrInstruction *ir_analyze_instruction_merge_err_sets(IrAnalyze *ira,
@@ -17309,6 +17496,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
assert(out_val->type != nullptr);
ConstExprValue *pointee = const_ptr_pointee_unchecked(codegen, ptr_val);
+ src_assert(pointee->type != nullptr, source_node);
if ((err = type_resolve(codegen, pointee->type, ResolveStatusSizeKnown)))
return ErrorSemanticAnalyzeFail;
@@ -17319,7 +17507,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
size_t dst_size = type_size(codegen, out_val->type);
if (dst_size <= src_size) {
- if (src_size == dst_size && types_have_same_zig_comptime_repr(pointee->type, out_val->type)) {
+ if (src_size == dst_size && types_have_same_zig_comptime_repr(out_val->type, pointee->type)) {
copy_const_val(out_val, pointee, ptr_val->data.x_ptr.mut != ConstPtrMutComptimeVar);
return ErrorNone;
}
@@ -18070,6 +18258,12 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
uint64_t index = bigint_as_u64(&casted_elem_index->value.data.x_bigint);
if (array_type->id == ZigTypeIdArray) {
uint64_t array_len = array_type->data.array.len;
+ if (index == array_len && array_type->data.array.is_null_terminated) {
+ ZigType *elem_type = array_type->data.array.child_type;
+ IrInstruction *null_element = ir_const(ira, &elem_ptr_instruction->base, elem_type);
+ null_element->value = *get_null_value(elem_type);
+ return ir_get_ref(ira, &elem_ptr_instruction->base, null_element, true, false);
+ }
if (index >= array_len) {
ir_add_error_node(ira, elem_ptr_instruction->base.source_node,
buf_sprintf("index %" ZIG_PRI_u64 " outside array of size %" ZIG_PRI_u64,
@@ -18203,7 +18397,11 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
{
size_t offset = array_ptr_val->data.x_ptr.data.base_array.elem_index;
new_index = offset + index;
- mem_size = array_ptr_val->data.x_ptr.data.base_array.array_val->type->data.array.len;
+ ZigType *array_type = array_ptr_val->data.x_ptr.data.base_array.array_val->type;
+ mem_size = array_type->data.array.len;
+ if (array_type->data.array.is_null_terminated) {
+ mem_size += 1;
+ }
old_size = mem_size - offset;
assert(array_ptr_val->data.x_ptr.data.base_array.array_val);
@@ -18212,8 +18410,6 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
out_val->data.x_ptr.data.base_array.array_val =
array_ptr_val->data.x_ptr.data.base_array.array_val;
out_val->data.x_ptr.data.base_array.elem_index = new_index;
- out_val->data.x_ptr.data.base_array.is_cstr =
- array_ptr_val->data.x_ptr.data.base_array.is_cstr;
break;
}
@@ -18277,8 +18473,6 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
out_val->data.x_ptr.data.base_array.array_val =
ptr_field->data.x_ptr.data.base_array.array_val;
out_val->data.x_ptr.data.base_array.elem_index = new_index;
- out_val->data.x_ptr.data.base_array.is_cstr =
- ptr_field->data.x_ptr.data.base_array.is_cstr;
break;
}
case ConstPtrSpecialBaseStruct:
@@ -19550,7 +19744,7 @@ static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstr
ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type,
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0, false);
- bool same_comptime_repr = types_have_same_zig_comptime_repr(type_entry, child_type);
+ bool same_comptime_repr = types_have_same_zig_comptime_repr(child_type, type_entry);
if (instr_is_comptime(base_ptr)) {
ConstExprValue *ptr_val = ir_resolve_const(ira, base_ptr, UndefBad);
@@ -20685,7 +20879,7 @@ static IrInstruction *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruct
return ira->codegen->invalid_instruction;
ErrorTableEntry *err = casted_value->value.data.x_err_set;
if (!err->cached_error_name_val) {
- ConstExprValue *array_val = create_const_str_lit(ira->codegen, &err->name);
+ ConstExprValue *array_val = create_const_str_lit(ira->codegen, &err->name)->data.x_ptr.data.ref.pointee;
err->cached_error_name_val = create_const_slice(ira->codegen, array_val, 0, buf_len(&err->name), true);
}
IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
@@ -20714,7 +20908,7 @@ static IrInstruction *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIns
if ((err = type_resolve(ira->codegen, target->value.type, ResolveStatusZeroBitsKnown)))
return ira->codegen->invalid_instruction;
TypeEnumField *field = find_enum_field_by_tag(target->value.type, &target->value.data.x_bigint);
- ConstExprValue *array_val = create_const_str_lit(ira->codegen, field->name);
+ ConstExprValue *array_val = create_const_str_lit(ira->codegen, field->name)->data.x_ptr.data.ref.pointee;
IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
init_const_slice(ira->codegen, &result->value, array_val, 0, buf_len(field->name), true);
return result;
@@ -21019,7 +21213,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr
declaration_val->type = type_info_declaration_type;
ConstExprValue **inner_fields = alloc_const_vals_ptrs(3);
- ConstExprValue *name = create_const_str_lit(ira->codegen, curr_entry->key);
+ ConstExprValue *name = create_const_str_lit(ira->codegen, curr_entry->key)->data.x_ptr.data.ref.pointee;
init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(curr_entry->key), true);
inner_fields[1]->special = ConstValSpecialStatic;
inner_fields[1]->type = ira->codegen->builtin_types.entry_bool;
@@ -21122,7 +21316,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr
fn_decl_fields[6]->type = get_optional_type(ira->codegen, get_slice_type(ira->codegen, u8_ptr));
if (fn_node->is_extern && fn_node->lib_name != nullptr && buf_len(fn_node->lib_name) > 0) {
fn_decl_fields[6]->data.x_optional = create_const_vals(1);
- ConstExprValue *lib_name = create_const_str_lit(ira->codegen, fn_node->lib_name);
+ ConstExprValue *lib_name = create_const_str_lit(ira->codegen, fn_node->lib_name)->data.x_ptr.data.ref.pointee;
init_const_slice(ira->codegen, fn_decl_fields[6]->data.x_optional, lib_name, 0,
buf_len(fn_node->lib_name), true);
} else {
@@ -21149,7 +21343,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr
ZigVar *arg_var = fn_entry->variable_list.at(fn_arg_index);
ConstExprValue *fn_arg_name_val = &fn_arg_name_array->data.x_array.data.s_none.elements[fn_arg_index];
ConstExprValue *arg_name = create_const_str_lit(ira->codegen,
- buf_create_from_str(arg_var->name));
+ buf_create_from_str(arg_var->name))->data.x_ptr.data.ref.pointee;
init_const_slice(ira->codegen, fn_arg_name_val, arg_name, 0, strlen(arg_var->name), true);
fn_arg_name_val->parent.id = ConstParentIdArray;
fn_arg_name_val->parent.data.p_array.array_val = fn_arg_name_array;
@@ -21294,7 +21488,7 @@ static void make_enum_field_val(IrAnalyze *ira, ConstExprValue *enum_field_val,
inner_fields[1]->special = ConstValSpecialStatic;
inner_fields[1]->type = ira->codegen->builtin_types.entry_num_lit_int;
- ConstExprValue *name = create_const_str_lit(ira->codegen, enum_field->name);
+ ConstExprValue *name = create_const_str_lit(ira->codegen, enum_field->name)->data.x_ptr.data.ref.pointee;
init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(enum_field->name), true);
bigint_init_bigint(&inner_fields[1]->data.x_bigint, &enum_field->value);
@@ -21560,7 +21754,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
if (error->cached_error_name_val != nullptr)
name = error->cached_error_name_val;
if (name == nullptr)
- name = create_const_str_lit(ira->codegen, &error->name);
+ name = create_const_str_lit(ira->codegen, &error->name)->data.x_ptr.data.ref.pointee;
init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(&error->name), true);
bigint_init_unsigned(&inner_fields[1]->data.x_bigint, error->value);
@@ -21666,7 +21860,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
inner_fields[2]->type = ira->codegen->builtin_types.entry_type;
inner_fields[2]->data.x_type = union_field->type_entry;
- ConstExprValue *name = create_const_str_lit(ira->codegen, union_field->name);
+ ConstExprValue *name = create_const_str_lit(ira->codegen, union_field->name)->data.x_ptr.data.ref.pointee;
init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(union_field->name), true);
union_field_val->data.x_struct.fields = inner_fields;
@@ -21752,7 +21946,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
inner_fields[2]->type = ira->codegen->builtin_types.entry_type;
inner_fields[2]->data.x_type = struct_field->type_entry;
- ConstExprValue *name = create_const_str_lit(ira->codegen, struct_field->name);
+ ConstExprValue *name = create_const_str_lit(ira->codegen, struct_field->name)->data.x_ptr.data.ref.pointee;
init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(struct_field->name), true);
struct_field_val->data.x_struct.fields = inner_fields;
diff --git a/src/parser.cpp b/src/parser.cpp
index 3da0d8a643..c3f719425b 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -1718,7 +1718,6 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) {
if (string_lit != nullptr) {
AstNode *res = ast_create_node(pc, NodeTypeStringLiteral, string_lit);
res->data.string_literal.buf = token_buf(string_lit);
- res->data.string_literal.c = string_lit->data.str_lit.is_c_str;
return res;
}
diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp
index 7ece5ff3fe..5088fbdbf8 100644
--- a/src/tokenizer.cpp
+++ b/src/tokenizer.cpp
@@ -33,10 +33,10 @@
'0': \
case DIGIT_NON_ZERO
-#define ALPHA_EXCEPT_C \
+#define ALPHA \
'a': \
case 'b': \
- /*case 'c':*/ \
+ case 'c': \
case 'd': \
case 'e': \
case 'f': \
@@ -87,10 +87,6 @@
case 'Y': \
case 'Z'
-#define ALPHA \
- ALPHA_EXCEPT_C: \
- case 'c'
-
#define SYMBOL_CHAR \
ALPHA: \
case DIGIT: \
@@ -180,7 +176,6 @@ static bool is_symbol_char(uint8_t c) {
enum TokenizeState {
TokenizeStateStart,
TokenizeStateSymbol,
- TokenizeStateSymbolFirstC,
TokenizeStateZero, // "0", which might lead to "0x"
TokenizeStateNumber, // "123", "0x123"
TokenizeStateNumberDot,
@@ -279,7 +274,6 @@ static void set_token_id(Tokenize *t, Token *token, TokenId id) {
} else if (id == TokenIdStringLiteral || id == TokenIdSymbol) {
memset(&token->data.str_lit.str, 0, sizeof(Buf));
buf_resize(&token->data.str_lit.str, 0);
- token->data.str_lit.is_c_str = false;
}
}
@@ -429,12 +423,7 @@ void tokenize(Buf *buf, Tokenization *out) {
switch (c) {
case WHITESPACE:
break;
- case 'c':
- t.state = TokenizeStateSymbolFirstC;
- begin_token(&t, TokenIdSymbol);
- buf_append_char(&t.cur_tok->data.str_lit.str, c);
- break;
- case ALPHA_EXCEPT_C:
+ case ALPHA:
case '_':
t.state = TokenizeStateSymbol;
begin_token(&t, TokenIdSymbol);
@@ -1007,19 +996,7 @@ void tokenize(Buf *buf, Tokenization *out) {
switch (c) {
case WHITESPACE:
break;
- case 'c':
- if (!t.cur_tok->data.str_lit.is_c_str) {
- t.pos -= 1;
- end_token(&t);
- t.state = TokenizeStateStart;
- break;
- }
- t.state = TokenizeStateLineStringContinueC;
- break;
case '\\':
- if (t.cur_tok->data.str_lit.is_c_str) {
- invalid_char_error(&t, c);
- }
t.state = TokenizeStateLineStringContinue;
break;
default:
@@ -1084,29 +1061,6 @@ void tokenize(Buf *buf, Tokenization *out) {
break;
}
break;
- case TokenizeStateSymbolFirstC:
- switch (c) {
- case '"':
- set_token_id(&t, t.cur_tok, TokenIdStringLiteral);
- t.cur_tok->data.str_lit.is_c_str = true;
- t.state = TokenizeStateString;
- break;
- case '\\':
- set_token_id(&t, t.cur_tok, TokenIdStringLiteral);
- t.cur_tok->data.str_lit.is_c_str = true;
- t.state = TokenizeStateSawBackslash;
- break;
- case SYMBOL_CHAR:
- t.state = TokenizeStateSymbol;
- buf_append_char(&t.cur_tok->data.str_lit.str, c);
- break;
- default:
- t.pos -= 1;
- end_token(&t);
- t.state = TokenizeStateStart;
- continue;
- }
- break;
case TokenizeStateSawAtSign:
switch (c) {
case '"':
@@ -1544,7 +1498,6 @@ void tokenize(Buf *buf, Tokenization *out) {
tokenize_error(&t, "unterminated character literal");
break;
case TokenizeStateSymbol:
- case TokenizeStateSymbolFirstC:
case TokenizeStateZero:
case TokenizeStateNumber:
case TokenizeStateFloatFraction:
diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp
index 149e58b6a7..b152eb079c 100644
--- a/src/tokenizer.hpp
+++ b/src/tokenizer.hpp
@@ -149,7 +149,6 @@ struct TokenIntLit {
struct TokenStrLit {
Buf str;
- bool is_c_str;
};
struct TokenCharLit {
diff --git a/src/translate_c.cpp b/src/translate_c.cpp
index 6df61ab13c..5dd6064984 100644
--- a/src/translate_c.cpp
+++ b/src/translate_c.cpp
@@ -323,17 +323,9 @@ static AstNode *trans_create_node_bool(Context *c, bool value) {
return bool_node;
}
-static AstNode *trans_create_node_str_lit_c(Context *c, Buf *buf) {
+static AstNode *trans_create_node_str_lit(Context *c, Buf *buf) {
AstNode *node = trans_create_node(c, NodeTypeStringLiteral);
node->data.string_literal.buf = buf;
- node->data.string_literal.c = true;
- return node;
-}
-
-static AstNode *trans_create_node_str_lit_non_c(Context *c, Buf *buf) {
- AstNode *node = trans_create_node(c, NodeTypeStringLiteral);
- node->data.string_literal.buf = buf;
- node->data.string_literal.c = false;
return node;
}
@@ -632,7 +624,7 @@ static AstNode *qual_type_to_log2_int_ref(Context *c, const ZigClangQualType qt,
// zig_type_node
AstNode *import_fn_call = trans_create_node_builtin_fn_call_str(c, "import");
- import_fn_call->data.fn_call_expr.params.append(trans_create_node_str_lit_non_c(c, buf_create_from_str("std")));
+ import_fn_call->data.fn_call_expr.params.append(trans_create_node_str_lit(c, buf_create_from_str("std")));
AstNode *inner_field_access = trans_create_node_field_access_str(c, import_fn_call, "math");
AstNode *outer_field_access = trans_create_node_field_access_str(c, inner_field_access, "Log2Int");
AstNode *log2int_fn_call = trans_create_node_fn_call_1(c, outer_field_access, zig_type_node);
@@ -3391,7 +3383,7 @@ static AstNode *trans_string_literal(Context *c, ResultUsed result_used, TransSc
case ZigClangStringLiteral_StringKind_UTF8: {
size_t str_len;
const char *str_ptr = ZigClangStringLiteral_getString_bytes_begin_size(stmt, &str_len);
- AstNode *node = trans_create_node_str_lit_c(c, buf_create_from_mem(str_ptr, str_len));
+ AstNode *node = trans_create_node_str_lit(c, buf_create_from_mem(str_ptr, str_len));
return maybe_suppress_result(c, result_used, node);
}
case ZigClangStringLiteral_StringKind_UTF16:
@@ -4890,7 +4882,7 @@ static AstNode *parse_ctok_primary_expr(Context *c, CTokenize *ctok, size_t *tok
return trans_create_node_unsigned(c, tok->data.char_lit);
case CTokIdStrLit:
*tok_i += 1;
- return trans_create_node_str_lit_c(c, buf_create_from_buf(&tok->data.str_lit));
+ return trans_create_node_str_lit(c, buf_create_from_buf(&tok->data.str_lit));
case CTokIdMinus:
*tok_i += 1;
return parse_ctok_num_lit(c, ctok, tok_i, true);
@@ -4937,7 +4929,7 @@ static AstNode *parse_ctok_primary_expr(Context *c, CTokenize *ctok, size_t *tok
// (dest)(x)
AstNode *import_builtin = trans_create_node_builtin_fn_call_str(c, "import");
- import_builtin->data.fn_call_expr.params.append(trans_create_node_str_lit_non_c(c, buf_create_from_str("builtin")));
+ import_builtin->data.fn_call_expr.params.append(trans_create_node_str_lit(c, buf_create_from_str("builtin")));
AstNode *typeid_type = trans_create_node_field_access_str(c, import_builtin, "TypeId");
AstNode *typeid_pointer = trans_create_node_field_access_str(c, typeid_type, "Pointer");
AstNode *typeid_integer = trans_create_node_field_access_str(c, typeid_type, "Int");
diff --git a/test/compare_output.zig b/test/compare_output.zig
index 0842fc4629..1535d0ae52 100644
--- a/test/compare_output.zig
+++ b/test/compare_output.zig
@@ -7,7 +7,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
cases.addC("hello world with libc",
\\const c = @cImport(@cInclude("stdio.h"));
\\export fn main(argc: c_int, argv: [*][*]u8) c_int {
- \\ _ = c.puts(c"Hello, world!");
+ \\ _ = c.puts("Hello, world!");
\\ return 0;
\\}
, "Hello, world!" ++ std.cstr.line_sep);
@@ -144,75 +144,75 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\ // we want actual \n, not \r\n
\\ _ = c._setmode(1, c._O_BINARY);
\\ }
- \\ _ = c.printf(c"0: %llu\n",
+ \\ _ = c.printf("0: %llu\n",
\\ @as(u64, 0));
- \\ _ = c.printf(c"320402575052271: %llu\n",
+ \\ _ = c.printf("320402575052271: %llu\n",
\\ @as(u64, 320402575052271));
- \\ _ = c.printf(c"0x01236789abcdef: %llu\n",
+ \\ _ = c.printf("0x01236789abcdef: %llu\n",
\\ @as(u64, 0x01236789abcdef));
- \\ _ = c.printf(c"0xffffffffffffffff: %llu\n",
+ \\ _ = c.printf("0xffffffffffffffff: %llu\n",
\\ @as(u64, 0xffffffffffffffff));
- \\ _ = c.printf(c"0x000000ffffffffffffffff: %llu\n",
+ \\ _ = c.printf("0x000000ffffffffffffffff: %llu\n",
\\ @as(u64, 0x000000ffffffffffffffff));
- \\ _ = c.printf(c"0o1777777777777777777777: %llu\n",
+ \\ _ = c.printf("0o1777777777777777777777: %llu\n",
\\ @as(u64, 0o1777777777777777777777));
- \\ _ = c.printf(c"0o0000001777777777777777777777: %llu\n",
+ \\ _ = c.printf("0o0000001777777777777777777777: %llu\n",
\\ @as(u64, 0o0000001777777777777777777777));
- \\ _ = c.printf(c"0b1111111111111111111111111111111111111111111111111111111111111111: %llu\n",
+ \\ _ = c.printf("0b1111111111111111111111111111111111111111111111111111111111111111: %llu\n",
\\ @as(u64, 0b1111111111111111111111111111111111111111111111111111111111111111));
- \\ _ = c.printf(c"0b0000001111111111111111111111111111111111111111111111111111111111111111: %llu\n",
+ \\ _ = c.printf("0b0000001111111111111111111111111111111111111111111111111111111111111111: %llu\n",
\\ @as(u64, 0b0000001111111111111111111111111111111111111111111111111111111111111111));
\\
- \\ _ = c.printf(c"\n");
+ \\ _ = c.printf("\n");
\\
- \\ _ = c.printf(c"0.0: %.013a\n",
+ \\ _ = c.printf("0.0: %.013a\n",
\\ @as(f64, 0.0));
- \\ _ = c.printf(c"0e0: %.013a\n",
+ \\ _ = c.printf("0e0: %.013a\n",
\\ @as(f64, 0e0));
- \\ _ = c.printf(c"0.0e0: %.013a\n",
+ \\ _ = c.printf("0.0e0: %.013a\n",
\\ @as(f64, 0.0e0));
- \\ _ = c.printf(c"000000000000000000000000000000000000000000000000000000000.0e0: %.013a\n",
+ \\ _ = c.printf("000000000000000000000000000000000000000000000000000000000.0e0: %.013a\n",
\\ @as(f64, 000000000000000000000000000000000000000000000000000000000.0e0));
- \\ _ = c.printf(c"0.000000000000000000000000000000000000000000000000000000000e0: %.013a\n",
+ \\ _ = c.printf("0.000000000000000000000000000000000000000000000000000000000e0: %.013a\n",
\\ @as(f64, 0.000000000000000000000000000000000000000000000000000000000e0));
- \\ _ = c.printf(c"0.0e000000000000000000000000000000000000000000000000000000000: %.013a\n",
+ \\ _ = c.printf("0.0e000000000000000000000000000000000000000000000000000000000: %.013a\n",
\\ @as(f64, 0.0e000000000000000000000000000000000000000000000000000000000));
- \\ _ = c.printf(c"1.0: %.013a\n",
+ \\ _ = c.printf("1.0: %.013a\n",
\\ @as(f64, 1.0));
- \\ _ = c.printf(c"10.0: %.013a\n",
+ \\ _ = c.printf("10.0: %.013a\n",
\\ @as(f64, 10.0));
- \\ _ = c.printf(c"10.5: %.013a\n",
+ \\ _ = c.printf("10.5: %.013a\n",
\\ @as(f64, 10.5));
- \\ _ = c.printf(c"10.5e5: %.013a\n",
+ \\ _ = c.printf("10.5e5: %.013a\n",
\\ @as(f64, 10.5e5));
- \\ _ = c.printf(c"10.5e+5: %.013a\n",
+ \\ _ = c.printf("10.5e+5: %.013a\n",
\\ @as(f64, 10.5e+5));
- \\ _ = c.printf(c"50.0e-2: %.013a\n",
+ \\ _ = c.printf("50.0e-2: %.013a\n",
\\ @as(f64, 50.0e-2));
- \\ _ = c.printf(c"50e-2: %.013a\n",
+ \\ _ = c.printf("50e-2: %.013a\n",
\\ @as(f64, 50e-2));
\\
- \\ _ = c.printf(c"\n");
+ \\ _ = c.printf("\n");
\\
- \\ _ = c.printf(c"0x1.0: %.013a\n",
+ \\ _ = c.printf("0x1.0: %.013a\n",
\\ @as(f64, 0x1.0));
- \\ _ = c.printf(c"0x10.0: %.013a\n",
+ \\ _ = c.printf("0x10.0: %.013a\n",
\\ @as(f64, 0x10.0));
- \\ _ = c.printf(c"0x100.0: %.013a\n",
+ \\ _ = c.printf("0x100.0: %.013a\n",
\\ @as(f64, 0x100.0));
- \\ _ = c.printf(c"0x103.0: %.013a\n",
+ \\ _ = c.printf("0x103.0: %.013a\n",
\\ @as(f64, 0x103.0));
- \\ _ = c.printf(c"0x103.7: %.013a\n",
+ \\ _ = c.printf("0x103.7: %.013a\n",
\\ @as(f64, 0x103.7));
- \\ _ = c.printf(c"0x103.70: %.013a\n",
+ \\ _ = c.printf("0x103.70: %.013a\n",
\\ @as(f64, 0x103.70));
- \\ _ = c.printf(c"0x103.70p4: %.013a\n",
+ \\ _ = c.printf("0x103.70p4: %.013a\n",
\\ @as(f64, 0x103.70p4));
- \\ _ = c.printf(c"0x103.70p5: %.013a\n",
+ \\ _ = c.printf("0x103.70p5: %.013a\n",
\\ @as(f64, 0x103.70p5));
- \\ _ = c.printf(c"0x103.70p+5: %.013a\n",
+ \\ _ = c.printf("0x103.70p+5: %.013a\n",
\\ @as(f64, 0x103.70p+5));
- \\ _ = c.printf(c"0x103.70p-5: %.013a\n",
+ \\ _ = c.printf("0x103.70p-5: %.013a\n",
\\ @as(f64, 0x103.70p-5));
\\
\\ return 0;
@@ -323,7 +323,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\ const x: f64 = small;
\\ const y = @floatToInt(i32, x);
\\ const z = @intToFloat(f64, y);
- \\ _ = c.printf(c"%.2f\n%d\n%.2f\n%.2f\n", x, y, z, @as(f64, -0.4));
+ \\ _ = c.printf("%.2f\n%d\n%.2f\n%.2f\n", x, y, z, @as(f64, -0.4));
\\ return 0;
\\}
, "3.25\n3\n3.00\n-0.40\n");
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 039afe52df..3343580991 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -164,7 +164,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
cases.add(
"using an unknown len ptr type instead of array",
\\const resolutions = [*][*]const u8{
- \\ c"[320 240 ]",
+ \\ "[320 240 ]",
\\ null,
\\};
\\comptime {
@@ -781,7 +781,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"peer cast then implicit cast const pointer to mutable C pointer",
\\export fn func() void {
\\ var strValue: [*c]u8 = undefined;
- \\ strValue = strValue orelse c"";
+ \\ strValue = strValue orelse "";
\\}
,
"tmp.zig:3:32: error: cast discards const qualifier",
@@ -1115,7 +1115,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"libc headers note",
\\const c = @cImport(@cInclude("stdio.h"));
\\export fn entry() void {
- \\ _ = c.printf(c"hello, world!\n");
+ \\ _ = c.printf("hello, world!\n");
\\}
,
"tmp.zig:1:11: error: C import failed",
@@ -3352,7 +3352,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
cases.add(
"variable has wrong type",
\\export fn f() i32 {
- \\ const a = c"a";
+ \\ const a = "a";
\\ return a;
\\}
,
@@ -4786,7 +4786,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
cases.add(
"assign through constant pointer",
\\export fn f() void {
- \\ var cstr = c"Hat";
+ \\ var cstr = "Hat";
\\ cstr[0] = 'W';
\\}
,
diff --git a/test/stage1/behavior/array.zig b/test/stage1/behavior/array.zig
index 3a9c9a7655..b9000125b3 100644
--- a/test/stage1/behavior/array.zig
+++ b/test/stage1/behavior/array.zig
@@ -132,9 +132,16 @@ test "single-item pointer to array indexing and slicing" {
}
fn testSingleItemPtrArrayIndexSlice() void {
- var array = "aaaa";
- doSomeMangling(&array);
- expect(mem.eql(u8, "azya", array));
+ {
+ var array: [4]u8 = "aaaa".*;
+ doSomeMangling(&array);
+ expect(mem.eql(u8, "azya", &array));
+ }
+ {
+ var array = "aaaa".*;
+ doSomeMangling(&array);
+ expect(mem.eql(u8, "azya", &array));
+ }
}
fn doSomeMangling(array: *[4]u8) void {
@@ -294,9 +301,16 @@ test "read/write through global variable array of struct fields initialized via
}
test "implicit cast zero sized array ptr to slice" {
- var b = "";
- const c: []const u8 = &b;
- expect(c.len == 0);
+ {
+ var b = "".*;
+ const c: []const u8 = &b;
+ expect(c.len == 0);
+ }
+ {
+ var b: [0]u8 = "".*;
+ const c: []const u8 = &b;
+ expect(c.len == 0);
+ }
}
test "anonymous list literal syntax" {
@@ -333,3 +347,16 @@ test "anonymous literal in array" {
S.doTheTest();
comptime S.doTheTest();
}
+
+test "access the null element of a null terminated array" {
+ const S = struct {
+ fn doTheTest() void {
+ var array: [4]null u8 = .{'a', 'o', 'e', 'u'};
+ comptime expect(array[4] == 0);
+ var len: usize = 4;
+ expect(array[len] == 0);
+ }
+ };
+ S.doTheTest();
+ comptime S.doTheTest();
+}
diff --git a/test/stage1/behavior/bugs/1076.zig b/test/stage1/behavior/bugs/1076.zig
index 550ee9703a..fa3caf0df8 100644
--- a/test/stage1/behavior/bugs/1076.zig
+++ b/test/stage1/behavior/bugs/1076.zig
@@ -8,8 +8,16 @@ test "comptime code should not modify constant data" {
}
fn testCastPtrOfArrayToSliceAndPtr() void {
- var array = "aoeu";
- const x: [*]u8 = &array;
- x[0] += 1;
- expect(mem.eql(u8, array[0..], "boeu"));
+ {
+ var array = "aoeu".*;
+ const x: [*]u8 = &array;
+ x[0] += 1;
+ expect(mem.eql(u8, array[0..], "boeu"));
+ }
+ {
+ var array: [4]u8 = "aoeu".*;
+ const x: [*]u8 = &array;
+ x[0] += 1;
+ expect(mem.eql(u8, array[0..], "boeu"));
+ }
}
diff --git a/test/stage1/behavior/cast.zig b/test/stage1/behavior/cast.zig
index 98d987a73f..affd7afe5e 100644
--- a/test/stage1/behavior/cast.zig
+++ b/test/stage1/behavior/cast.zig
@@ -179,18 +179,24 @@ fn gimmeErrOrSlice() anyerror![]u8 {
}
test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" {
- {
- var data = "hi";
- const slice = data[0..];
- expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0);
- expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
- }
- comptime {
- var data = "hi";
- const slice = data[0..];
- expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0);
- expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
- }
+ const S = struct {
+ fn doTheTest() anyerror!void {
+ {
+ var data = "hi".*;
+ const slice = data[0..];
+ expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0);
+ expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
+ }
+ {
+ var data: [2]u8 = "hi".*;
+ const slice = data[0..];
+ expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0);
+ expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
+ }
+ }
+ };
+ try S.doTheTest();
+ try comptime S.doTheTest();
}
fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 {
if (a) {
@@ -217,11 +223,20 @@ test "implicit cast from &const [N]T to []const T" {
}
fn testCastConstArrayRefToConstSlice() void {
- const blah = "aoeu";
- const const_array_ref = &blah;
- expect(@typeOf(const_array_ref) == *const [4]u8);
- const slice: []const u8 = const_array_ref;
- expect(mem.eql(u8, slice, "aoeu"));
+ {
+ const blah = "aoeu".*;
+ const const_array_ref = &blah;
+ expect(@typeOf(const_array_ref) == *const [4]null u8);
+ const slice: []const u8 = const_array_ref;
+ expect(mem.eql(u8, slice, "aoeu"));
+ }
+ {
+ const blah: [4]u8 = "aoeu".*;
+ const const_array_ref = &blah;
+ expect(@typeOf(const_array_ref) == *const [4]u8);
+ const slice: []const u8 = const_array_ref;
+ expect(mem.eql(u8, slice, "aoeu"));
+ }
}
test "peer type resolution: error and [N]T" {
@@ -310,17 +325,28 @@ test "single-item pointer of array to slice and to unknown length pointer" {
}
fn testCastPtrOfArrayToSliceAndPtr() void {
- var array = "aoeu";
- const x: [*]u8 = &array;
- x[0] += 1;
- expect(mem.eql(u8, array[0..], "boeu"));
- const y: []u8 = &array;
- y[0] += 1;
- expect(mem.eql(u8, array[0..], "coeu"));
+ {
+ var array = "aoeu".*;
+ const x: [*]u8 = &array;
+ x[0] += 1;
+ expect(mem.eql(u8, array[0..], "boeu"));
+ const y: []u8 = &array;
+ y[0] += 1;
+ expect(mem.eql(u8, array[0..], "coeu"));
+ }
+ {
+ var array: [4]u8 = "aoeu".*;
+ const x: [*]u8 = &array;
+ x[0] += 1;
+ expect(mem.eql(u8, array[0..], "boeu"));
+ const y: []u8 = &array;
+ y[0] += 1;
+ expect(mem.eql(u8, array[0..], "coeu"));
+ }
}
test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
- const window_name = [1][*]const u8{c"window name"};
+ const window_name = [1][*]const u8{"window name"};
const x: [*]const ?[*]const u8 = &window_name;
expect(mem.eql(u8, std.mem.toSliceConst(u8, x[0].?), "window name"));
}
@@ -545,7 +571,7 @@ test "implicit cast *[0]T to E![]const u8" {
}
test "peer cast *[0]T to E![]const T" {
- var buffer: [5]u8 = "abcde";
+ var buffer: [5]u8 = "abcde".*;
var buf: anyerror![]const u8 = buffer[0..];
var b = false;
var y = if (b) &[0]u8{} else buf;
@@ -553,7 +579,7 @@ test "peer cast *[0]T to E![]const T" {
}
test "peer cast *[0]T to []const T" {
- var buffer: [5]u8 = "abcde";
+ var buffer: [5]u8 = "abcde".*;
var buf: []const u8 = buffer[0..];
var b = false;
var y = if (b) &[0]u8{} else buf;
@@ -565,3 +591,33 @@ test "cast from array reference to fn" {
const f = @ptrCast(extern fn () void, &global_array);
expect(@ptrToInt(f) == @ptrToInt(&global_array));
}
+
+test "*const [N]null u8 to ?[]const u8" {
+ const S = struct {
+ fn doTheTest() void {
+ var a = "Hello";
+ var b: ?[]const u8 = a;
+ expect(mem.eql(u8, b.?, "Hello"));
+ }
+ };
+ S.doTheTest();
+ comptime S.doTheTest();
+}
+
+test "peer resolution of string literals" {
+ const S = struct {
+ const E = extern enum { a, b, c, d};
+
+ fn doTheTest(e: E) void {
+ const cmd = switch (e) {
+ .a => "one",
+ .b => "two",
+ .c => "three",
+ .d => "four",
+ };
+ expect(mem.eql(u8, cmd, "two"));
+ }
+ };
+ S.doTheTest(.b);
+ comptime S.doTheTest(.b);
+}
diff --git a/test/stage1/behavior/const_slice_child.zig b/test/stage1/behavior/const_slice_child.zig
index 13713e1ee7..6720667187 100644
--- a/test/stage1/behavior/const_slice_child.zig
+++ b/test/stage1/behavior/const_slice_child.zig
@@ -6,12 +6,11 @@ var argv: [*]const [*]const u8 = undefined;
test "const slice child" {
const strs = [_][*]const u8{
- c"one",
- c"two",
- c"three",
+ "one",
+ "two",
+ "three",
};
- // TODO this should implicitly cast
- argv = @ptrCast([*]const [*]const u8, &strs);
+ argv = &strs;
bar(strs.len);
}
diff --git a/test/stage1/behavior/eval.zig b/test/stage1/behavior/eval.zig
index fa899d0cb2..b7bce26568 100644
--- a/test/stage1/behavior/eval.zig
+++ b/test/stage1/behavior/eval.zig
@@ -736,7 +736,7 @@ test "comptime pointer cast array and then slice" {
test "slice bounds in comptime concatenation" {
const bs = comptime blk: {
- const b = c"........1........";
+ const b = "........1........";
break :blk b[8..9];
};
const str = "" ++ bs;
diff --git a/test/stage1/behavior/misc.zig b/test/stage1/behavior/misc.zig
index 1a227a5b93..a0188dcedd 100644
--- a/test/stage1/behavior/misc.zig
+++ b/test/stage1/behavior/misc.zig
@@ -204,11 +204,11 @@ test "multiline string" {
test "multiline C string" {
const s1 =
- c\\one
- c\\two)
- c\\three
+ \\one
+ \\two)
+ \\three
;
- const s2 = c"one\ntwo)\nthree";
+ const s2 = "one\ntwo)\nthree";
expect(std.cstr.cmp(s1, s2) == 0);
}
@@ -358,9 +358,12 @@ fn ptrEql(a: *const []const u8, b: *const []const u8) bool {
return a == b;
}
-test "C string concatenation" {
- const a = c"OK" ++ c" IT " ++ c"WORKED";
- const b = c"OK IT WORKED";
+test "string concatenation" {
+ const a = "OK" ++ " IT " ++ "WORKED";
+ const b = "OK IT WORKED";
+
+ comptime expect(@typeOf(a) == *const [12]null u8);
+ comptime expect(@typeOf(b) == *const [12]null u8);
const len = mem.len(u8, b);
const len_with_null = len + 1;
diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig
index fd11e68473..7d8bdea569 100644
--- a/test/stage1/behavior/pointers.zig
+++ b/test/stage1/behavior/pointers.zig
@@ -15,7 +15,7 @@ fn testDerefPtr() void {
}
test "pointer arithmetic" {
- var ptr = c"abcd";
+ var ptr: [*]const u8 = "abcd";
expect(ptr[0] == 'a');
ptr += 1;
diff --git a/test/stage1/behavior/ptrcast.zig b/test/stage1/behavior/ptrcast.zig
index bf92888214..ddb5a63eee 100644
--- a/test/stage1/behavior/ptrcast.zig
+++ b/test/stage1/behavior/ptrcast.zig
@@ -60,7 +60,7 @@ test "comptime ptrcast keeps larger alignment" {
}
test "implicit optional pointer to optional c_void pointer" {
- var buf: [4]u8 = "aoeu";
+ var buf: [4]u8 = "aoeu".*;
var x: ?[*]u8 = &buf;
var y: ?*c_void = x;
var z = @ptrCast(*[4]u8, y);
diff --git a/test/stage1/behavior/slice.zig b/test/stage1/behavior/slice.zig
index d4a8353ca7..ea0a6fe9f4 100644
--- a/test/stage1/behavior/slice.zig
+++ b/test/stage1/behavior/slice.zig
@@ -36,7 +36,7 @@ fn assertLenIsZero(msg: []const u8) void {
}
test "C pointer" {
- var buf: [*c]const u8 = c"kjdhfkjdhfdkjhfkfjhdfkjdhfkdjhfdkjhf";
+ var buf: [*c]const u8 = "kjdhfkjdhfdkjhfkfjhdfkjdhfkdjhfdkjhf";
var len: u32 = 10;
var slice = buf[0..len];
expectEqualSlices(u8, "kjdhfkjdhf", slice);
diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig
index 722f44d352..e42bd4e9d7 100644
--- a/test/stage1/behavior/struct.zig
+++ b/test/stage1/behavior/struct.zig
@@ -493,7 +493,7 @@ test "non-byte-aligned array inside packed struct" {
fn doTheTest() void {
var foo = Foo{
.a = true,
- .b = "abcdefghijklmnopqurstu",
+ .b = "abcdefghijklmnopqurstu".*,
};
bar(foo.b);
}
diff --git a/test/stage2/compare_output.zig b/test/stage2/compare_output.zig
index fdc3d49145..a86811b27b 100644
--- a/test/stage2/compare_output.zig
+++ b/test/stage2/compare_output.zig
@@ -6,7 +6,7 @@ pub fn addCases(ctx: *TestContext) !void {
try ctx.testCompareOutputLibC(
\\extern fn puts([*]const u8) void;
\\export fn main() c_int {
- \\ puts(c"Hello, world!");
+ \\ puts("Hello, world!");
\\ return 0;
\\}
, "Hello, world!" ++ std.cstr.line_sep);
@@ -15,7 +15,7 @@ pub fn addCases(ctx: *TestContext) !void {
try ctx.testCompareOutputLibC(
\\extern fn puts(s: [*]const u8) void;
\\export fn main() c_int {
- \\ return foo(c"OK");
+ \\ return foo("OK");
\\}
\\fn foo(s: [*]const u8) c_int {
\\ puts(s);
diff --git a/test/standalone/hello_world/hello_libc.zig b/test/standalone/hello_world/hello_libc.zig
index 05356bf529..c6f290f70e 100644
--- a/test/standalone/hello_world/hello_libc.zig
+++ b/test/standalone/hello_world/hello_libc.zig
@@ -5,7 +5,7 @@ const c = @cImport({
@cInclude("string.h");
});
-const msg = c"Hello, world!\n";
+const msg = "Hello, world!\n";
export fn main(argc: c_int, argv: **u8) c_int {
if (c.printf(msg) != @intCast(c_int, c.strlen(msg))) return -1;
diff --git a/test/translate_c.zig b/test/translate_c.zig
index f78e2181eb..f543fbc74e 100644
--- a/test/translate_c.zig
+++ b/test/translate_c.zig
@@ -47,7 +47,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub fn foo() void {
\\ var a: c_int = undefined;
\\ _ = 1;
- \\ _ = c"hey";
+ \\ _ = "hey";
\\ _ = (1 + 1);
\\ _ = (1 - 1);
\\ a = 1;
@@ -213,9 +213,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
,
\\pub fn foo() void {
- \\ _ = c"foo";
- \\ _ = c"foo";
- \\ _ = c"void foo(void)";
+ \\ _ = "foo";
+ \\ _ = "foo";
+ \\ _ = "void foo(void)";
\\}
);
@@ -232,7 +232,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub fn foo() void {
\\ var a: c_int = undefined;
\\ _ = 1;
- \\ _ = c"hey";
+ \\ _ = "hey";
\\ _ = (1 + 1);
\\ _ = (1 - 1);
\\ a = 1;
@@ -543,7 +543,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
cases.add("#define string",
\\#define foo "a string"
,
- \\pub const foo = c"a string";
+ \\pub const foo = "a string";
);
cases.add("__cdecl doesn't mess up function pointers",
@@ -617,9 +617,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\#define FOO2 "aoeu\x0007a derp"
\\#define FOO_CHAR '\xfF'
,
- \\pub const FOO = c"aoeu\xab derp";
+ \\pub const FOO = "aoeu\xab derp";
,
- \\pub const FOO2 = c"aoeuz derp";
+ \\pub const FOO2 = "aoeuz derp";
,
\\pub const FOO_CHAR = 255;
);
@@ -629,9 +629,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\#define FOO2 "aoeu\0234 derp"
\\#define FOO_CHAR '\077'
,
- \\pub const FOO = c"aoeu\x13 derp";
+ \\pub const FOO = "aoeu\x13 derp";
,
- \\pub const FOO2 = c"aoeu\x134 derp";
+ \\pub const FOO2 = "aoeu\x134 derp";
,
\\pub const FOO_CHAR = 63;
);
@@ -1351,7 +1351,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
,
\\pub fn foo() [*c]const u8 {
- \\ return c"bar";
+ \\ return "bar";
\\}
);
@@ -1523,7 +1523,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
cases.add("const ptr initializer",
\\static const char *v0 = "0.0.0";
,
- \\pub var v0: [*c]const u8 = c"0.0.0";
+ \\pub var v0: [*c]const u8 = "0.0.0";
);
cases.add("static incomplete array inside function",
@@ -1532,7 +1532,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
,
\\pub fn foo() void {
- \\ const v2: [*c]const u8 = c"2.2.2";
+ \\ const v2: [*c]const u8 = "2.2.2";
\\}
);
@@ -1809,7 +1809,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ var i: u8 = @as(u8, '\x0b');
\\ var j: u8 = @as(u8, '\x00');
\\ var k: u8 = @as(u8, '\"');
- \\ return c"\'\\\x07\x08\x0c\n\r\t\x0b\x00\"";
+ \\ return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\"";
\\}
\\
);
--
cgit v1.2.3
From 7597735badd1f6aa6750f354a7e9c85fec705c55 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sat, 23 Nov 2019 04:45:35 -0500
Subject: update the stage1 implementation to the new proposal
See #3731
---
lib/std/builtin.zig | 14 +-
lib/std/c.zig | 2 +-
lib/std/mem.zig | 2 +-
lib/std/zig/parser_test.zig | 6 +-
src/all_types.hpp | 27 ++-
src/analyze.cpp | 221 +++++++++---------
src/analyze.hpp | 6 +-
src/ast_render.cpp | 4 +-
src/codegen.cpp | 27 ++-
src/dump_analysis.cpp | 4 -
src/ir.cpp | 454 +++++++++++++++++++++++++------------
src/parser.cpp | 184 +++++++++------
src/tokenizer.cpp | 69 +-----
src/tokenizer.hpp | 3 -
src/translate_c.cpp | 6 +-
test/stage1/behavior/array.zig | 2 +-
test/stage1/behavior/cast.zig | 2 +-
test/stage1/behavior/misc.zig | 4 +-
test/stage1/behavior/pointers.zig | 2 +-
test/stage1/behavior/type.zig | 8 +-
test/stage1/behavior/type_info.zig | 10 +-
21 files changed, 614 insertions(+), 443 deletions(-)
(limited to 'src/analyze.cpp')
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig
index 56c3426d8b..64fc68e4cc 100644
--- a/lib/std/builtin.zig
+++ b/lib/std/builtin.zig
@@ -144,7 +144,12 @@ pub const TypeInfo = union(enum) {
alignment: comptime_int,
child: type,
is_allowzero: bool,
- is_null_terminated: bool,
+ /// The type of the sentinel is the element type of the pointer, which is
+ /// the value of the `child` field in this struct. However there is no way
+ /// to refer to that type here, so this is a pointer to an opaque value.
+ /// It will be known at compile-time to be the correct type. Dereferencing
+ /// this pointer will work at compile-time.
+ sentinel: ?*const c_void,
/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
@@ -161,7 +166,12 @@ pub const TypeInfo = union(enum) {
pub const Array = struct {
len: comptime_int,
child: type,
- is_null_terminated: bool,
+ /// The type of the sentinel is the element type of the array, which is
+ /// the value of the `child` field in this struct. However there is no way
+ /// to refer to that type here, so this is a pointer to an opaque value.
+ /// It will be known at compile-time to be the correct type. Dereferencing
+ /// this pointer will work at compile-time.
+ sentinel: ?*const c_void,
};
/// This data structure is used by the Zig language code generation and
diff --git a/lib/std/c.zig b/lib/std/c.zig
index 1faf45a489..fac13efc69 100644
--- a/lib/std/c.zig
+++ b/lib/std/c.zig
@@ -63,7 +63,7 @@ pub extern "c" fn fclose(stream: *FILE) c_int;
pub extern "c" fn fwrite(ptr: [*]const u8, size_of_type: usize, item_count: usize, stream: *FILE) usize;
pub extern "c" fn fread(ptr: [*]u8, size_of_type: usize, item_count: usize, stream: *FILE) usize;
-pub extern "c" fn printf(format: [*]null const u8, ...) c_int;
+pub extern "c" fn printf(format: [*:0]const u8, ...) c_int;
pub extern "c" fn abort() noreturn;
pub extern "c" fn exit(code: c_int) noreturn;
pub extern "c" fn isatty(fd: fd_t) c_int;
diff --git a/lib/std/mem.zig b/lib/std/mem.zig
index 160b8e6e5e..f790dd683b 100644
--- a/lib/std/mem.zig
+++ b/lib/std/mem.zig
@@ -1409,7 +1409,7 @@ fn BytesAsValueReturnType(comptime T: type, comptime B: type) type {
const size = @as(usize, @sizeOf(T));
if (comptime !trait.is(builtin.TypeId.Pointer)(B) or
- (meta.Child(B) != [size]u8 and meta.Child(B) != [size]null u8))
+ (meta.Child(B) != [size]u8 and meta.Child(B) != [size:0]u8))
{
@compileError("expected *[N]u8 " ++ ", passed " ++ @typeName(B));
}
diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig
index ebe396e145..ce19588722 100644
--- a/lib/std/zig/parser_test.zig
+++ b/lib/std/zig/parser_test.zig
@@ -1552,7 +1552,7 @@ test "zig fmt: pointer attributes" {
\\extern fn f2(s: **align(1) *const *volatile u8) c_int;
\\extern fn f3(s: *align(1) const *align(1) volatile *const volatile u8) c_int;
\\extern fn f4(s: *align(1) const volatile u8) c_int;
- \\extern fn f5(s: [*]null align(1) const volatile u8) c_int;
+ \\extern fn f5(s: [*:0]align(1) const volatile u8) c_int;
\\
);
}
@@ -1563,7 +1563,7 @@ test "zig fmt: slice attributes" {
\\extern fn f2(s: **align(1) *const *volatile u8) c_int;
\\extern fn f3(s: *align(1) const *align(1) volatile *const volatile u8) c_int;
\\extern fn f4(s: *align(1) const volatile u8) c_int;
- \\extern fn f5(s: [*]null align(1) const volatile u8) c_int;
+ \\extern fn f5(s: [*:0]align(1) const volatile u8) c_int;
\\
);
}
@@ -1885,7 +1885,7 @@ test "zig fmt: arrays" {
\\ 2,
\\ };
\\ const a: [0]u8 = []u8{};
- \\ const x: [4]null u8 = undefined;
+ \\ const x: [4:0]u8 = undefined;
\\}
\\
);
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 4047a7d4a5..1f785a63f3 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -55,7 +55,6 @@ enum PtrLen {
PtrLenUnknown,
PtrLenSingle,
PtrLenC,
- PtrLenNull,
};
// This one corresponds to the builtin.zig enum.
@@ -353,19 +352,20 @@ struct LazyValueSliceType {
LazyValue base;
IrAnalyze *ira;
+ IrInstruction *sentinel; // can be null
IrInstruction *elem_type;
IrInstruction *align_inst; // can be null
bool is_const;
bool is_volatile;
bool is_allowzero;
- bool is_null_terminated;
};
struct LazyValuePtrType {
LazyValue base;
IrAnalyze *ira;
+ IrInstruction *sentinel; // can be null
IrInstruction *elem_type;
IrInstruction *align_inst; // can be null
@@ -821,6 +821,7 @@ struct AstNodePrefixOpExpr {
struct AstNodePointerType {
Token *star_token;
+ AstNode *sentinel;
AstNode *align_expr;
BigInt *bit_offset_start;
BigInt *host_int_bytes;
@@ -828,21 +829,21 @@ struct AstNodePointerType {
Token *allow_zero_token;
bool is_const;
bool is_volatile;
- bool is_null_terminated;
};
struct AstNodeInferredArrayType {
+ AstNode *sentinel; // can be null
AstNode *child_type;
};
struct AstNodeArrayType {
AstNode *size;
+ AstNode *sentinel;
AstNode *child_type;
AstNode *align_expr;
Token *allow_zero_token;
bool is_const;
bool is_volatile;
- bool is_null_terminated;
};
struct AstNodeUsingNamespace {
@@ -1208,6 +1209,11 @@ struct ZigTypePointer {
// struct.
InferredStructField *inferred_struct_field;
+ // This can be null. If it is non-null, it means the pointer is terminated by this
+ // sentinel value. This is most commonly used for C-style strings, with a 0 byte
+ // to specify the length of the memory pointed to.
+ ConstExprValue *sentinel;
+
PtrLen ptr_len;
uint32_t explicit_alignment; // 0 means use ABI alignment
@@ -1235,7 +1241,7 @@ struct ZigTypeFloat {
struct ZigTypeArray {
ZigType *child_type;
uint64_t len;
- bool is_null_terminated;
+ ConstExprValue *sentinel;
};
struct TypeStructField {
@@ -1761,8 +1767,10 @@ struct TypeId {
union {
struct {
+ CodeGen *codegen;
ZigType *child_type;
InferredStructField *inferred_struct_field;
+ ConstExprValue *sentinel;
PtrLen ptr_len;
uint32_t alignment;
@@ -1775,9 +1783,10 @@ struct TypeId {
bool allow_zero;
} pointer;
struct {
+ CodeGen *codegen;
ZigType *child_type;
uint64_t size;
- bool is_null_terminated;
+ ConstExprValue *sentinel;
} array;
struct {
bool is_signed;
@@ -2033,6 +2042,7 @@ struct CodeGen {
IrInstruction *invalid_instruction;
IrInstruction *unreach_instruction;
+ ConstExprValue const_zero_byte;
ConstExprValue const_void_val;
ConstExprValue panic_msg_vals[PanicMsgIdCount];
@@ -2989,13 +2999,14 @@ struct IrInstructionArrayType {
IrInstruction base;
IrInstruction *size;
+ IrInstruction *sentinel;
IrInstruction *child_type;
- bool is_null_terminated;
};
struct IrInstructionPtrType {
IrInstruction base;
+ IrInstruction *sentinel;
IrInstruction *align_value;
IrInstruction *child_type;
uint32_t bit_offset_start;
@@ -3015,12 +3026,12 @@ struct IrInstructionAnyFrameType {
struct IrInstructionSliceType {
IrInstruction base;
+ IrInstruction *sentinel;
IrInstruction *align_value;
IrInstruction *child_type;
bool is_const;
bool is_volatile;
bool is_allow_zero;
- bool is_null_terminated;
};
struct IrInstructionGlobalAsm {
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 9c42177d11..aa58d64aa4 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -452,20 +452,6 @@ ZigType *get_any_frame_type(CodeGen *g, ZigType *result_type) {
return entry;
}
-static const char *ptr_len_to_star_str(PtrLen ptr_len) {
- switch (ptr_len) {
- case PtrLenSingle:
- return "*";
- case PtrLenUnknown:
- return "[*]";
- case PtrLenC:
- return "[*c]";
- case PtrLenNull:
- return "[*]null ";
- }
- zig_unreachable();
-}
-
ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn) {
if (fn->frame_type != nullptr) {
return fn->frame_type;
@@ -485,10 +471,47 @@ ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn) {
return entry;
}
+static void append_ptr_type_attrs(Buf *type_name, ZigType *ptr_type) {
+ const char *const_str = ptr_type->data.pointer.is_const ? "const " : "";
+ const char *volatile_str = ptr_type->data.pointer.is_volatile ? "volatile " : "";
+ const char *allow_zero_str;
+ if (ptr_type->data.pointer.ptr_len == PtrLenC) {
+ assert(ptr_type->data.pointer.allow_zero);
+ allow_zero_str = "";
+ } else {
+ allow_zero_str = ptr_type->data.pointer.allow_zero ? "allowzero " : "";
+ }
+ if (ptr_type->data.pointer.explicit_alignment != 0 || ptr_type->data.pointer.host_int_bytes != 0 ||
+ ptr_type->data.pointer.vector_index != VECTOR_INDEX_NONE)
+ {
+ buf_appendf(type_name, "align(");
+ if (ptr_type->data.pointer.explicit_alignment != 0) {
+ buf_appendf(type_name, "%" PRIu32, ptr_type->data.pointer.explicit_alignment);
+ }
+ if (ptr_type->data.pointer.host_int_bytes != 0) {
+ buf_appendf(type_name, ":%" PRIu32 ":%" PRIu32, ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes);
+ }
+ if (ptr_type->data.pointer.vector_index == VECTOR_INDEX_RUNTIME) {
+ buf_appendf(type_name, ":?");
+ } else if (ptr_type->data.pointer.vector_index != VECTOR_INDEX_NONE) {
+ buf_appendf(type_name, ":%" PRIu32, ptr_type->data.pointer.vector_index);
+ }
+ buf_appendf(type_name, ")");
+ }
+ buf_appendf(type_name, "%s%s%s", const_str, volatile_str, allow_zero_str);
+ if (ptr_type->data.pointer.inferred_struct_field != nullptr) {
+ buf_appendf(type_name, " field '%s' of %s)",
+ buf_ptr(ptr_type->data.pointer.inferred_struct_field->field_name),
+ buf_ptr(&ptr_type->data.pointer.inferred_struct_field->inferred_struct_type->name));
+ } else {
+ buf_appendf(type_name, "%s", buf_ptr(&ptr_type->data.pointer.child_type->name));
+ }
+}
+
ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_const,
bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment,
uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero,
- uint32_t vector_index, InferredStructField *inferred_struct_field)
+ uint32_t vector_index, InferredStructField *inferred_struct_field, ConstExprValue *sentinel)
{
assert(ptr_len != PtrLenC || allow_zero);
assert(!type_is_invalid(child_type));
@@ -511,9 +534,11 @@ ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_con
TypeId type_id = {};
ZigType **parent_pointer = nullptr;
if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle ||
- allow_zero || vector_index != VECTOR_INDEX_NONE || inferred_struct_field != nullptr)
+ allow_zero || vector_index != VECTOR_INDEX_NONE || inferred_struct_field != nullptr ||
+ sentinel != nullptr)
{
type_id.id = ZigTypeIdPointer;
+ type_id.data.pointer.codegen = g;
type_id.data.pointer.child_type = child_type;
type_id.data.pointer.is_const = is_const;
type_id.data.pointer.is_volatile = is_volatile;
@@ -524,6 +549,7 @@ ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_con
type_id.data.pointer.allow_zero = allow_zero;
type_id.data.pointer.vector_index = vector_index;
type_id.data.pointer.inferred_struct_field = inferred_struct_field;
+ type_id.data.pointer.sentinel = sentinel;
auto existing_entry = g->type_table.maybe_get(type_id);
if (existing_entry)
@@ -539,57 +565,36 @@ ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_con
ZigType *entry = new_type_table_entry(ZigTypeIdPointer);
- const char *star_str = ptr_len_to_star_str(ptr_len);
- const char *const_str = is_const ? "const " : "";
- const char *volatile_str = is_volatile ? "volatile " : "";
- const char *allow_zero_str;
- if (ptr_len == PtrLenC) {
- assert(allow_zero);
- allow_zero_str = "";
- } else {
- allow_zero_str = allow_zero ? "allowzero " : "";
- }
buf_resize(&entry->name, 0);
- if (host_int_bytes == 0 && byte_alignment == 0 && vector_index == VECTOR_INDEX_NONE) {
- if (inferred_struct_field == nullptr) {
- buf_appendf(&entry->name, "%s%s%s%s%s",
- star_str, const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name));
- } else {
- buf_appendf(&entry->name, "(%s%s%s%s field '%s' of %s)",
- star_str, const_str, volatile_str, allow_zero_str,
- buf_ptr(inferred_struct_field->field_name),
- buf_ptr(&inferred_struct_field->inferred_struct_type->name));
- }
- } else if (host_int_bytes == 0 && vector_index == VECTOR_INDEX_NONE) {
- buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s%s", star_str, byte_alignment,
- const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name));
- } else if (byte_alignment == 0) {
- assert(vector_index == VECTOR_INDEX_NONE);
- buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s%s",
- star_str,
- bit_offset_in_host, host_int_bytes,
- const_str, volatile_str, allow_zero_str,
- buf_ptr(&child_type->name));
- } else if (vector_index == VECTOR_INDEX_NONE) {
- buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s%s",
- star_str, byte_alignment,
- bit_offset_in_host, host_int_bytes,
- const_str, volatile_str, allow_zero_str,
- buf_ptr(&child_type->name));
- } else if (vector_index == VECTOR_INDEX_RUNTIME) {
- buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ":?) %s%s%s%s",
- star_str, byte_alignment,
- bit_offset_in_host, host_int_bytes,
- const_str, volatile_str, allow_zero_str,
- buf_ptr(&child_type->name));
- } else {
- buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s%s",
- star_str, byte_alignment,
- bit_offset_in_host, host_int_bytes, vector_index,
- const_str, volatile_str, allow_zero_str,
- buf_ptr(&child_type->name));
+ if (inferred_struct_field != nullptr) {
+ buf_appendf(&entry->name, "(");
+ }
+ switch (ptr_len) {
+ case PtrLenSingle:
+ buf_appendf(&entry->name, "*");
+ break;
+ case PtrLenUnknown:
+ buf_appendf(&entry->name, "[*");
+ break;
+ case PtrLenC:
+ assert(sentinel == nullptr);
+ buf_appendf(&entry->name, "[*c]");
+ break;
+ }
+ if (sentinel != nullptr) {
+ buf_appendf(&entry->name, ":");
+ render_const_value(g, &entry->name, sentinel);
+ }
+ switch (ptr_len) {
+ case PtrLenSingle:
+ case PtrLenC:
+ break;
+ case PtrLenUnknown:
+ buf_appendf(&entry->name, "]");
+ break;
}
+
if (type_is_resolved(child_type, ResolveStatusZeroBitsKnown)) {
if (type_has_bits(child_type)) {
entry->abi_size = g->builtin_types.entry_usize->abi_size;
@@ -617,6 +622,9 @@ ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_con
entry->data.pointer.allow_zero = allow_zero;
entry->data.pointer.vector_index = vector_index;
entry->data.pointer.inferred_struct_field = inferred_struct_field;
+ entry->data.pointer.sentinel = sentinel;
+
+ append_ptr_type_attrs(&entry->name, entry);
if (parent_pointer) {
*parent_pointer = entry;
@@ -631,12 +639,12 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero)
{
return get_pointer_to_type_extra2(g, child_type, is_const, is_volatile, ptr_len,
- byte_alignment, bit_offset_in_host, host_int_bytes, allow_zero, VECTOR_INDEX_NONE, nullptr);
+ byte_alignment, bit_offset_in_host, host_int_bytes, allow_zero, VECTOR_INDEX_NONE, nullptr, nullptr);
}
ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const) {
return get_pointer_to_type_extra2(g, child_type, is_const, false, PtrLenSingle, 0, 0, 0, false,
- VECTOR_INDEX_NONE, nullptr);
+ VECTOR_INDEX_NONE, nullptr, nullptr);
}
ZigType *get_optional_type(CodeGen *g, ZigType *child_type) {
@@ -752,12 +760,13 @@ ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payloa
return entry;
}
-ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, bool is_null_terminated) {
+ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, ConstExprValue *sentinel) {
TypeId type_id = {};
type_id.id = ZigTypeIdArray;
+ type_id.data.array.codegen = g;
type_id.data.array.child_type = child_type;
type_id.data.array.size = array_size;
- type_id.data.array.is_null_terminated = is_null_terminated;
+ type_id.data.array.sentinel = sentinel;
auto existing_entry = g->type_table.maybe_get(type_id);
if (existing_entry) {
return existing_entry->value;
@@ -767,16 +776,19 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, bo
ZigType *entry = new_type_table_entry(ZigTypeIdArray);
- const char *null_str = is_null_terminated ? "null " : "";
-
buf_resize(&entry->name, 0);
- buf_appendf(&entry->name, "[%" ZIG_PRI_u64 "]%s%s", array_size, null_str, buf_ptr(&child_type->name));
+ buf_appendf(&entry->name, "[%" ZIG_PRI_u64, array_size);
+ if (sentinel != nullptr) {
+ buf_appendf(&entry->name, ":");
+ render_const_value(g, &entry->name, sentinel);
+ }
+ buf_appendf(&entry->name, "]%s", buf_ptr(&child_type->name));
size_t full_array_size;
if (array_size == 0) {
full_array_size = 0;
} else {
- full_array_size = array_size + (is_null_terminated ? 1 : 0);
+ full_array_size = array_size + ((sentinel != nullptr) ? 1 : 0);
}
entry->size_in_bits = child_type->size_in_bits * full_array_size;
@@ -785,7 +797,7 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, bo
entry->data.array.child_type = child_type;
entry->data.array.len = array_size;
- entry->data.array.is_null_terminated = is_null_terminated;
+ entry->data.array.sentinel = sentinel;
g->type_table.put(type_id, entry);
return entry;
@@ -793,7 +805,7 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, bo
ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
assert(ptr_type->id == ZigTypeIdPointer);
- assert(ptr_type->data.pointer.ptr_len == PtrLenUnknown || ptr_type->data.pointer.ptr_len == PtrLenNull);
+ assert(ptr_type->data.pointer.ptr_len == PtrLenUnknown);
ZigType **parent_pointer = &ptr_type->data.pointer.slice_parent;
if (*parent_pointer) {
@@ -802,10 +814,14 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
ZigType *entry = new_type_table_entry(ZigTypeIdStruct);
- // replace the & with [] to go from a ptr type name to a slice type name
buf_resize(&entry->name, 0);
- size_t name_offset = (ptr_type->data.pointer.ptr_len == PtrLenSingle) ? 1 : 3;
- buf_appendf(&entry->name, "[]%s", buf_ptr(&ptr_type->name) + name_offset);
+ buf_appendf(&entry->name, "[");
+ if (ptr_type->data.pointer.sentinel != nullptr) {
+ buf_appendf(&entry->name, ":");
+ render_const_value(g, &entry->name, ptr_type->data.pointer.sentinel);
+ }
+ buf_appendf(&entry->name, "]");
+ append_ptr_type_attrs(&entry->name, ptr_type);
unsigned element_count = 2;
Buf *ptr_field_name = buf_create_from_str("ptr");
@@ -5639,14 +5655,14 @@ void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
// first we build the underlying array
ConstExprValue *array_val = create_const_vals(1);
array_val->special = ConstValSpecialStatic;
- array_val->type = get_array_type(g, g->builtin_types.entry_u8, buf_len(str), true);
+ array_val->type = get_array_type(g, g->builtin_types.entry_u8, buf_len(str), &g->const_zero_byte);
array_val->data.x_array.special = ConstArraySpecialBuf;
array_val->data.x_array.data.s_buf = str;
// then make the pointer point to it
const_val->special = ConstValSpecialStatic;
const_val->type = get_pointer_to_type_extra2(g, array_val->type, true, false,
- PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE, nullptr);
+ PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE, nullptr, nullptr);
const_val->data.x_ptr.special = ConstPtrSpecialRef;
const_val->data.x_ptr.data.ref.pointee = array_val;
@@ -6079,7 +6095,7 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
fields.append({"@stack_trace", get_stack_trace_type(g), 0});
fields.append({"@instruction_addresses",
- get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count, false), 0});
+ get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count, nullptr), 0});
}
frame_type->data.frame.locals_struct = get_struct_type(g, buf_ptr(&frame_type->name),
@@ -6287,7 +6303,7 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
if (codegen_fn_has_err_ret_tracing_stack(g, fn, true)) {
fields.append({"@stack_trace", get_stack_trace_type(g), 0});
fields.append({"@instruction_addresses",
- get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count, false), 0});
+ get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count, nullptr), 0});
}
for (size_t alloca_i = 0; alloca_i < fn->alloca_gen_list.length; alloca_i += 1) {
@@ -7050,11 +7066,12 @@ uint32_t type_id_hash(TypeId x) {
(((uint32_t)x.data.pointer.alignment) ^ (uint32_t)0x777fbe0e) +
(((uint32_t)x.data.pointer.bit_offset_in_host) ^ (uint32_t)2639019452) +
(((uint32_t)x.data.pointer.vector_index) ^ (uint32_t)0x19199716) +
- (((uint32_t)x.data.pointer.host_int_bytes) ^ (uint32_t)529908881);
+ (((uint32_t)x.data.pointer.host_int_bytes) ^ (uint32_t)529908881) *
+ (x.data.pointer.sentinel ? hash_const_val(x.data.pointer.sentinel) : (uint32_t)2955491856);
case ZigTypeIdArray:
return hash_ptr(x.data.array.child_type) *
((uint32_t)x.data.array.size ^ (uint32_t)2122979968) *
- ((uint32_t)x.data.array.is_null_terminated ^ (uint32_t)2048352596);
+ (x.data.array.sentinel ? hash_const_val(x.data.array.sentinel) : (uint32_t)1927201585);
case ZigTypeIdInt:
return (x.data.integer.is_signed ? (uint32_t)2652528194 : (uint32_t)163929201) +
(((uint32_t)x.data.integer.bit_count) ^ (uint32_t)2998081557);
@@ -7105,6 +7122,11 @@ bool type_id_eql(TypeId a, TypeId b) {
a.data.pointer.bit_offset_in_host == b.data.pointer.bit_offset_in_host &&
a.data.pointer.vector_index == b.data.pointer.vector_index &&
a.data.pointer.host_int_bytes == b.data.pointer.host_int_bytes &&
+ (
+ a.data.pointer.sentinel == b.data.pointer.sentinel ||
+ (a.data.pointer.sentinel != nullptr && b.data.pointer.sentinel != nullptr &&
+ const_values_equal(a.data.pointer.codegen, a.data.pointer.sentinel, b.data.pointer.sentinel))
+ ) &&
(
a.data.pointer.inferred_struct_field == b.data.pointer.inferred_struct_field ||
(a.data.pointer.inferred_struct_field != nullptr &&
@@ -7117,7 +7139,11 @@ bool type_id_eql(TypeId a, TypeId b) {
case ZigTypeIdArray:
return a.data.array.child_type == b.data.array.child_type &&
a.data.array.size == b.data.array.size &&
- a.data.array.is_null_terminated == b.data.array.is_null_terminated;
+ (
+ a.data.array.sentinel == b.data.array.sentinel ||
+ (a.data.array.sentinel != nullptr && b.data.array.sentinel != nullptr &&
+ const_values_equal(a.data.array.codegen, a.data.array.sentinel, b.data.array.sentinel))
+ );
case ZigTypeIdInt:
return a.data.integer.is_signed == b.data.integer.is_signed &&
a.data.integer.bit_count == b.data.integer.bit_count;
@@ -8303,7 +8329,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta
size_t padding_bytes = union_type->data.unionation.union_abi_size - most_aligned_union_member->type_entry->abi_size;
if (padding_bytes > 0) {
ZigType *u8_type = get_int_type(g, false, 8);
- ZigType *padding_array = get_array_type(g, u8_type, padding_bytes, false);
+ ZigType *padding_array = get_array_type(g, u8_type, padding_bytes, nullptr);
LLVMTypeRef union_element_types[] = {
most_aligned_union_member->type_entry->llvm_type,
get_llvm_type(g, padding_array),
@@ -8337,7 +8363,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta
union_type_ref = get_llvm_type(g, most_aligned_union_member->type_entry);
} else {
ZigType *u8_type = get_int_type(g, false, 8);
- ZigType *padding_array = get_array_type(g, u8_type, padding_bytes, false);
+ ZigType *padding_array = get_array_type(g, u8_type, padding_bytes, nullptr);
LLVMTypeRef union_element_types[] = {
get_llvm_type(g, most_aligned_union_member->type_entry),
get_llvm_type(g, padding_array),
@@ -8418,19 +8444,19 @@ static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type, ResolveStatus
if (type->data.pointer.is_const || type->data.pointer.is_volatile ||
type->data.pointer.explicit_alignment != 0 || type->data.pointer.ptr_len != PtrLenSingle ||
type->data.pointer.bit_offset_in_host != 0 || type->data.pointer.allow_zero ||
- type->data.pointer.vector_index != VECTOR_INDEX_NONE)
+ type->data.pointer.vector_index != VECTOR_INDEX_NONE || type->data.pointer.sentinel != nullptr)
{
assertNoError(type_resolve(g, elem_type, ResolveStatusLLVMFwdDecl));
ZigType *peer_type;
if (type->data.pointer.vector_index == VECTOR_INDEX_NONE) {
peer_type = get_pointer_to_type_extra2(g, elem_type, false, false,
PtrLenSingle, 0, 0, type->data.pointer.host_int_bytes, false,
- VECTOR_INDEX_NONE, nullptr);
+ VECTOR_INDEX_NONE, nullptr, nullptr);
} else {
uint32_t host_vec_len = type->data.pointer.host_int_bytes;
ZigType *host_vec_type = get_vector_type(g, host_vec_len, elem_type);
peer_type = get_pointer_to_type_extra2(g, host_vec_type, false, false,
- PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE, nullptr);
+ PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE, nullptr, nullptr);
}
type->llvm_type = get_llvm_type(g, peer_type);
type->llvm_di_type = get_llvm_di_type(g, peer_type);
@@ -8659,8 +8685,8 @@ static void resolve_llvm_types_array(CodeGen *g, ZigType *type) {
ZigType *elem_type = type->data.array.child_type;
- uint64_t extra_len_from_null = type->data.array.is_null_terminated ? 1 : 0;
- uint64_t full_len = type->data.array.len + extra_len_from_null;
+ uint64_t extra_len_from_sentinel = (type->data.array.sentinel != nullptr) ? 1 : 0;
+ uint64_t full_len = type->data.array.len + extra_len_from_sentinel;
// TODO https://github.com/ziglang/zig/issues/1424
type->llvm_type = LLVMArrayType(get_llvm_type(g, elem_type), (unsigned)full_len);
@@ -9166,16 +9192,3 @@ void IrExecutable::src() {
it->source_node->src();
}
}
-
-ConstExprValue *get_null_value(ZigType *ty) {
- if (ty->id == ZigTypeIdInt || ty->id == ZigTypeIdComptimeInt) {
- return create_const_unsigned_negative(ty, 0, false);
- } else if (ty->id == ZigTypeIdFloat || ty->id == ZigTypeIdComptimeFloat) {
- return create_const_float(ty, NAN);
- } else if (ty->id == ZigTypeIdOptional) {
- return create_const_null(ty);
- } else {
- zig_unreachable();
- }
-}
-
diff --git a/src/analyze.hpp b/src/analyze.hpp
index a3d4621178..fcf993eac4 100644
--- a/src/analyze.hpp
+++ b/src/analyze.hpp
@@ -24,7 +24,8 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type,
ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type,
bool is_const, bool is_volatile, PtrLen ptr_len,
uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count,
- bool allow_zero, uint32_t vector_index, InferredStructField *inferred_struct_field);
+ bool allow_zero, uint32_t vector_index, InferredStructField *inferred_struct_field,
+ ConstExprValue *sentinel);
uint64_t type_size(CodeGen *g, ZigType *type_entry);
uint64_t type_size_bits(CodeGen *g, ZigType *type_entry);
ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits);
@@ -33,7 +34,7 @@ ZigType **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type);
ZigType *get_c_int_type(CodeGen *g, CIntType c_int_type);
ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id);
ZigType *get_optional_type(CodeGen *g, ZigType *child_type);
-ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, bool is_null_terminated);
+ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, ConstExprValue *sentinel);
ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type);
ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind,
AstNode *decl_node, const char *full_name, Buf *bare_name, ContainerLayout layout);
@@ -276,5 +277,4 @@ IrInstruction *ir_create_alloca(CodeGen *g, Scope *scope, AstNode *source_node,
Error analyze_import(CodeGen *codegen, ZigType *source_import, Buf *import_target_str,
ZigType **out_import, Buf **out_import_target_path, Buf *out_full_path);
ConstExprValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry);
-ConstExprValue *get_null_value(ZigType *ty);
#endif
diff --git a/src/ast_render.cpp b/src/ast_render.cpp
index 53388fa033..f4f97c3730 100644
--- a/src/ast_render.cpp
+++ b/src/ast_render.cpp
@@ -147,9 +147,9 @@ static const char *token_to_ptr_len_str(Token *tok) {
case TokenIdStar:
case TokenIdStarStar:
return "*";
- case TokenIdBracketStarBracket:
+ case TokenIdLBracket:
return "[*]";
- case TokenIdBracketStarCBracket:
+ case TokenIdSymbol:
return "[*c]";
default:
zig_unreachable();
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 4fc3b968c1..9a269ec41f 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -3707,8 +3707,8 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
array_type = array_type->data.pointer.child_type;
}
if (safety_check_on) {
- uint64_t extra_len_from_null = array_type->data.array.is_null_terminated ? 1 : 0;
- uint64_t full_len = array_type->data.array.len + extra_len_from_null;
+ uint64_t extra_len_from_sentinel = (array_type->data.array.sentinel != nullptr) ? 1 : 0;
+ uint64_t full_len = array_type->data.array.len + extra_len_from_sentinel;
LLVMValueRef end = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, full_len, false);
add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, end);
}
@@ -6636,8 +6636,8 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con
ConstExprValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val;
assert(array_const_val->type->id == ZigTypeIdArray);
if (!type_has_bits(array_const_val->type)) {
- if (array_const_val->type->data.array.is_null_terminated) {
- ConstExprValue *pointee = get_null_value(array_const_val->type->data.array.child_type);
+ if (array_const_val->type->data.array.sentinel != nullptr) {
+ ConstExprValue *pointee = array_const_val->type->data.array.sentinel;
render_const_val(g, pointee, "");
render_const_val_global(g, pointee, "");
const_val->global_refs->llvm_value = LLVMConstBitCast(pointee->global_refs->llvm_global,
@@ -6963,8 +6963,8 @@ check: switch (const_val->special) {
case ConstArraySpecialUndef:
return LLVMGetUndef(get_llvm_type(g, type_entry));
case ConstArraySpecialNone: {
- uint64_t extra_len_from_null = type_entry->data.array.is_null_terminated ? 1 : 0;
- uint64_t full_len = len + extra_len_from_null;
+ uint64_t extra_len_from_sentinel = (type_entry->data.array.sentinel != nullptr) ? 1 : 0;
+ uint64_t full_len = len + extra_len_from_sentinel;
LLVMValueRef *values = allocate(full_len);
LLVMTypeRef element_type_ref = get_llvm_type(g, type_entry->data.array.child_type);
bool make_unnamed_struct = false;
@@ -6974,8 +6974,8 @@ check: switch (const_val->special) {
values[i] = val;
make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(g, elem_value->type, val);
}
- if (type_entry->data.array.is_null_terminated) {
- values[len] = LLVMConstNull(element_type_ref);
+ if (type_entry->data.array.sentinel != nullptr) {
+ values[len] = gen_const_val(g, type_entry->data.array.sentinel, "");
}
if (make_unnamed_struct) {
return LLVMConstStruct(values, full_len, true);
@@ -6986,7 +6986,7 @@ check: switch (const_val->special) {
case ConstArraySpecialBuf: {
Buf *buf = const_val->data.x_array.data.s_buf;
return LLVMConstString(buf_ptr(buf), (unsigned)buf_len(buf),
- !type_entry->data.array.is_null_terminated);
+ type_entry->data.array.sentinel == nullptr);
}
}
zig_unreachable();
@@ -7479,7 +7479,7 @@ static void do_code_gen(CodeGen *g) {
!is_async && !have_err_ret_trace_arg;
LLVMValueRef err_ret_array_val = nullptr;
if (have_err_ret_trace_stack) {
- ZigType *array_type = get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count, false);
+ ZigType *array_type = get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count, nullptr);
err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", get_abi_alignment(g, array_type));
(void)get_llvm_type(g, get_stack_trace_type(g));
@@ -8642,6 +8642,11 @@ static void init(CodeGen *g) {
g->const_void_val.type = g->builtin_types.entry_void;
g->const_void_val.global_refs = allocate(1);
+ g->const_zero_byte.special = ConstValSpecialStatic;
+ g->const_zero_byte.type = g->builtin_types.entry_u8;
+ g->const_zero_byte.global_refs = allocate(1);
+ bigint_init_unsigned(&g->const_zero_byte.data.x_bigint, 0);
+
{
ConstGlobalRefs *global_refs = allocate(PanicMsgIdCount);
for (size_t i = 0; i < PanicMsgIdCount; i += 1) {
@@ -9081,7 +9086,7 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
zig_unreachable();
ConstExprValue *test_fn_array = create_const_vals(1);
- test_fn_array->type = get_array_type(g, struct_type, g->test_fns.length, false);
+ test_fn_array->type = get_array_type(g, struct_type, g->test_fns.length, nullptr);
test_fn_array->special = ConstValSpecialStatic;
test_fn_array->data.x_array.data.s_none.elements = create_const_vals(g->test_fns.length);
diff --git a/src/dump_analysis.cpp b/src/dump_analysis.cpp
index 825ae4baa5..98bbcc6a42 100644
--- a/src/dump_analysis.cpp
+++ b/src/dump_analysis.cpp
@@ -992,10 +992,6 @@ static void anal_dump_type(AnalDumpCtx *ctx, ZigType *ty) {
jw_object_field(jw, "len");
jw_int(jw, 3);
break;
- case PtrLenNull:
- jw_object_field(jw, "len");
- jw_int(jw, 4);
- break;
}
anal_dump_pointer_attrs(ctx, ty);
break;
diff --git a/src/ir.cpp b/src/ir.cpp
index 03ec3c0436..a7a3fc51e4 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -67,9 +67,10 @@ enum ConstCastResultId {
ConstCastResultIdAsyncAllocatorType,
ConstCastResultIdBadAllowsZero,
ConstCastResultIdArrayChild,
- ConstCastResultIdBadNullTermArrays,
+ ConstCastResultIdSentinelArrays,
ConstCastResultIdPtrLens,
ConstCastResultIdCV,
+ ConstCastResultIdPtrSentinel,
};
struct ConstCastOnly;
@@ -94,8 +95,8 @@ struct ConstCastTypeMismatch;
struct ConstCastArrayMismatch;
struct ConstCastBadAllowsZero;
struct ConstCastBadNullTermArrays;
-struct ConstCastBadPtrLens;
struct ConstCastBadCV;
+struct ConstCastPtrSentinel;
struct ConstCastOnly {
ConstCastResultId id;
@@ -113,9 +114,9 @@ struct ConstCastOnly {
ConstCastArg fn_arg;
ConstCastArgNoAlias arg_no_alias;
ConstCastBadAllowsZero *bad_allows_zero;
- ConstCastBadNullTermArrays *bad_null_term_arrays;
- ConstCastBadPtrLens *bad_ptr_lens;
+ ConstCastBadNullTermArrays *sentinel_arrays;
ConstCastBadCV *bad_cv;
+ ConstCastPtrSentinel *bad_ptr_sentinel;
} data;
};
@@ -175,14 +176,13 @@ struct ConstCastBadNullTermArrays {
ZigType *actual_type;
};
-struct ConstCastBadPtrLens {
+struct ConstCastBadCV {
ZigType *wanted_type;
ZigType *actual_type;
};
-struct ConstCastBadCV {
+struct ConstCastPtrSentinel {
ZigType *wanted_type;
- ZigType *actual_type;
};
static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope);
@@ -264,8 +264,7 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c
case ConstPtrSpecialBaseArray: {
ConstExprValue *array_val = const_val->data.x_ptr.data.base_array.array_val;
if (const_val->data.x_ptr.data.base_array.elem_index == array_val->type->data.array.len) {
- assert(array_val->type->data.array.is_null_terminated);
- result = get_null_value(array_val->type->data.array.child_type);
+ result = array_val->type->data.array.sentinel;
} else {
expand_undef_array(g, array_val);
result = &array_val->data.x_array.data.s_none.elements[const_val->data.x_ptr.data.base_array.elem_index];
@@ -317,7 +316,7 @@ static bool slice_is_const(ZigType *type) {
// This function returns true when you can change the type of a ConstExprValue and the
// value remains meaningful.
-static bool types_have_same_zig_comptime_repr(ZigType *expected, ZigType *actual) {
+static bool types_have_same_zig_comptime_repr(CodeGen *codegen, ZigType *expected, ZigType *actual) {
if (expected == actual)
return true;
@@ -366,7 +365,8 @@ static bool types_have_same_zig_comptime_repr(ZigType *expected, ZigType *actual
case ZigTypeIdArray:
return expected->data.array.len == actual->data.array.len &&
expected->data.array.child_type == actual->data.array.child_type &&
- (!expected->data.array.is_null_terminated || actual->data.array.is_null_terminated);
+ (expected->data.array.sentinel == nullptr || (actual->data.array.sentinel != nullptr &&
+ const_values_equal(codegen, expected->data.array.sentinel, actual->data.array.sentinel)));
}
zig_unreachable();
}
@@ -1576,9 +1576,11 @@ static IrInstruction *ir_build_br(IrBuilder *irb, Scope *scope, AstNode *source_
static IrInstruction *ir_build_ptr_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *child_type, bool is_const, bool is_volatile, PtrLen ptr_len,
- IrInstruction *align_value, uint32_t bit_offset_start, uint32_t host_int_bytes, bool is_allow_zero)
+ IrInstruction *sentinel, IrInstruction *align_value,
+ uint32_t bit_offset_start, uint32_t host_int_bytes, bool is_allow_zero)
{
IrInstructionPtrType *ptr_type_of_instruction = ir_build_instruction(irb, scope, source_node);
+ ptr_type_of_instruction->sentinel = sentinel;
ptr_type_of_instruction->align_value = align_value;
ptr_type_of_instruction->child_type = child_type;
ptr_type_of_instruction->is_const = is_const;
@@ -1588,6 +1590,7 @@ static IrInstruction *ir_build_ptr_type(IrBuilder *irb, Scope *scope, AstNode *s
ptr_type_of_instruction->host_int_bytes = host_int_bytes;
ptr_type_of_instruction->is_allow_zero = is_allow_zero;
+ if (sentinel) ir_ref_instruction(sentinel, irb->current_basic_block);
if (align_value) ir_ref_instruction(align_value, irb->current_basic_block);
ir_ref_instruction(child_type, irb->current_basic_block);
@@ -1804,14 +1807,15 @@ static IrInstruction *ir_build_set_float_mode(IrBuilder *irb, Scope *scope, AstN
}
static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *size,
- IrInstruction *child_type, bool is_null_terminated)
+ IrInstruction *sentinel, IrInstruction *child_type)
{
IrInstructionArrayType *instruction = ir_build_instruction(irb, scope, source_node);
instruction->size = size;
+ instruction->sentinel = sentinel;
instruction->child_type = child_type;
- instruction->is_null_terminated = is_null_terminated;
ir_ref_instruction(size, irb->current_basic_block);
+ if (sentinel != nullptr) ir_ref_instruction(sentinel, irb->current_basic_block);
ir_ref_instruction(child_type, irb->current_basic_block);
return &instruction->base;
@@ -1827,20 +1831,22 @@ static IrInstruction *ir_build_anyframe_type(IrBuilder *irb, Scope *scope, AstNo
return &instruction->base;
}
+
static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value, bool is_allow_zero,
- bool is_null_terminated)
+ IrInstruction *child_type, bool is_const, bool is_volatile,
+ IrInstruction *sentinel, IrInstruction *align_value, bool is_allow_zero)
{
IrInstructionSliceType *instruction = ir_build_instruction(irb, scope, source_node);
instruction->is_const = is_const;
instruction->is_volatile = is_volatile;
instruction->child_type = child_type;
+ instruction->sentinel = sentinel;
instruction->align_value = align_value;
instruction->is_allow_zero = is_allow_zero;
- instruction->is_null_terminated = is_null_terminated;
+ if (sentinel != nullptr) ir_ref_instruction(sentinel, irb->current_basic_block);
+ if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block);
ir_ref_instruction(child_type, irb->current_basic_block);
- if (align_value) ir_ref_instruction(align_value, irb->current_basic_block);
return &instruction->base;
}
@@ -6067,9 +6073,9 @@ static PtrLen star_token_to_ptr_len(TokenId token_id) {
case TokenIdStar:
case TokenIdStarStar:
return PtrLenSingle;
- case TokenIdBracketStarBracket:
+ case TokenIdLBracket:
return PtrLenUnknown;
- case TokenIdBracketStarCBracket:
+ case TokenIdSymbol:
return PtrLenC;
default:
zig_unreachable();
@@ -6080,22 +6086,22 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode
assert(node->type == NodeTypePointerType);
PtrLen ptr_len = star_token_to_ptr_len(node->data.pointer_type.star_token->id);
- if (node->data.pointer_type.is_null_terminated) {
- if (ptr_len == PtrLenUnknown) {
- ptr_len = PtrLenNull;
- } else {
- exec_add_error_node(irb->codegen, irb->exec, node,
- buf_sprintf("null-terminated pointer must be specified with [*] token"));
- return irb->codegen->invalid_instruction;
- }
- }
bool is_const = node->data.pointer_type.is_const;
bool is_volatile = node->data.pointer_type.is_volatile;
bool is_allow_zero = node->data.pointer_type.allow_zero_token != nullptr;
+ AstNode *sentinel_expr = node->data.pointer_type.sentinel;
AstNode *expr_node = node->data.pointer_type.op_expr;
AstNode *align_expr = node->data.pointer_type.align_expr;
+ IrInstruction *sentinel;
+ if (sentinel_expr != nullptr) {
+ sentinel = ir_gen_node(irb, sentinel_expr, scope);
+ if (sentinel == irb->codegen->invalid_instruction)
+ return sentinel;
+ } else {
+ sentinel = nullptr;
+ }
IrInstruction *align_value;
if (align_expr != nullptr) {
@@ -6141,7 +6147,7 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode
}
return ir_build_ptr_type(irb, scope, node, child_type, is_const, is_volatile,
- ptr_len, align_value, bit_offset_start, host_int_bytes, is_allow_zero);
+ ptr_len, sentinel, align_value, bit_offset_start, host_int_bytes, is_allow_zero);
}
static IrInstruction *ir_gen_catch_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node,
@@ -6245,13 +6251,22 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A
buf_sprintf("initializing array with struct syntax"));
return irb->codegen->invalid_instruction;
}
+ IrInstruction *sentinel;
+ if (container_init_expr->type->data.inferred_array_type.sentinel != nullptr) {
+ sentinel = ir_gen_node(irb, container_init_expr->type->data.inferred_array_type.sentinel, scope);
+ if (sentinel == irb->codegen->invalid_instruction)
+ return sentinel;
+ } else {
+ sentinel = nullptr;
+ }
+
IrInstruction *elem_type = ir_gen_node(irb,
container_init_expr->type->data.inferred_array_type.child_type, scope);
if (elem_type == irb->codegen->invalid_instruction)
return elem_type;
size_t item_count = container_init_expr->entries.length;
IrInstruction *item_count_inst = ir_build_const_usize(irb, scope, node, item_count);
- container_type = ir_build_array_type(irb, scope, node, item_count_inst, elem_type, false);
+ container_type = ir_build_array_type(irb, scope, node, item_count_inst, sentinel, elem_type);
} else {
container_type = ir_gen_node(irb, container_init_expr->type, scope);
if (container_type == irb->codegen->invalid_instruction)
@@ -6975,10 +6990,20 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
bool is_const = node->data.array_type.is_const;
bool is_volatile = node->data.array_type.is_volatile;
bool is_allow_zero = node->data.array_type.allow_zero_token != nullptr;
- bool is_null_terminated = node->data.array_type.is_null_terminated;
+ AstNode *sentinel_expr = node->data.array_type.sentinel;
AstNode *align_expr = node->data.array_type.align_expr;
Scope *comptime_scope = create_comptime_scope(irb->codegen, node, scope);
+
+ IrInstruction *sentinel;
+ if (sentinel_expr != nullptr) {
+ sentinel = ir_gen_node(irb, sentinel_expr, comptime_scope);
+ if (sentinel == irb->codegen->invalid_instruction)
+ return sentinel;
+ } else {
+ sentinel = nullptr;
+ }
+
if (size_node) {
if (is_const) {
add_node_error(irb->codegen, node, buf_create_from_str("const qualifier invalid on array type"));
@@ -7005,7 +7030,7 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
if (child_type == irb->codegen->invalid_instruction)
return child_type;
- return ir_build_array_type(irb, scope, node, size_value, child_type, is_null_terminated);
+ return ir_build_array_type(irb, scope, node, size_value, sentinel, child_type);
} else {
IrInstruction *align_value;
if (align_expr != nullptr) {
@@ -7020,8 +7045,8 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
if (child_type == irb->codegen->invalid_instruction)
return child_type;
- return ir_build_slice_type(irb, scope, node, child_type, is_const, is_volatile, align_value, is_allow_zero,
- is_null_terminated);
+ return ir_build_slice_type(irb, scope, node, child_type, is_const, is_volatile, sentinel,
+ align_value, is_allow_zero);
}
}
@@ -8698,7 +8723,7 @@ ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprVal
case OnePossibleValueYes:
return get_the_one_possible_value(codegen, expected_type);
}
- if (!types_have_same_zig_comptime_repr(expected_type, val->type)) {
+ if (!types_have_same_zig_comptime_repr(codegen, expected_type, val->type)) {
if ((err = eval_comptime_ptr_reinterpret(ira, codegen, source_node, const_val)))
return nullptr;
return const_ptr_pointee_unchecked(codegen, const_val);
@@ -9846,7 +9871,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
// alignment can be decreased
// bit offset attributes must match exactly
// PtrLenSingle/PtrLenUnknown must match exactly, but PtrLenC matches either one
- // PtrLenNull can coerce into PtrLenUnknown
+ // sentinel-terminated pointers can coerce into PtrLenUnknown
ZigType *wanted_ptr_type = get_src_ptr_type(wanted_type);
ZigType *actual_ptr_type = get_src_ptr_type(actual_type);
bool wanted_allows_zero = ptr_allows_addr_zero(wanted_type);
@@ -9858,15 +9883,20 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
bool actual_opt_or_ptr = actual_ptr_type != nullptr &&
(actual_type->id == ZigTypeIdPointer || actual_type->id == ZigTypeIdOptional);
if (wanted_opt_or_ptr && actual_opt_or_ptr) {
- bool ptr_lens_equal = actual_ptr_type->data.pointer.ptr_len == wanted_ptr_type->data.pointer.ptr_len;
bool ok_null_term_ptrs =
- actual_ptr_type->data.pointer.ptr_len == PtrLenNull ||
- wanted_ptr_type->data.pointer.ptr_len == PtrLenUnknown;
- if (!(ptr_lens_equal || wanted_is_c_ptr || actual_is_c_ptr || ok_null_term_ptrs)) {
+ wanted_ptr_type->data.pointer.sentinel == nullptr ||
+ (actual_ptr_type->data.pointer.sentinel != nullptr &&
+ const_values_equal(ira->codegen, wanted_ptr_type->data.pointer.sentinel,
+ actual_ptr_type->data.pointer.sentinel));
+ if (!ok_null_term_ptrs) {
+ result.id = ConstCastResultIdPtrSentinel;
+ result.data.bad_ptr_sentinel = allocate_nonzero(1);
+ result.data.bad_ptr_sentinel->wanted_type = wanted_type;
+ return result;
+ }
+ bool ptr_lens_equal = actual_ptr_type->data.pointer.ptr_len == wanted_ptr_type->data.pointer.ptr_len;
+ if (!(ptr_lens_equal || wanted_is_c_ptr || actual_is_c_ptr)) {
result.id = ConstCastResultIdPtrLens;
- result.data.bad_ptr_lens = allocate_nonzero(1);
- result.data.bad_ptr_lens->wanted_type = wanted_type;
- result.data.bad_ptr_lens->actual_type = actual_type;
return result;
}
@@ -9944,14 +9974,15 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
result.data.array_mismatch->actual_child = actual_type->data.array.child_type;
return result;
}
- bool ok_null_terminated = !wanted_type->data.array.is_null_terminated ||
- actual_type->data.array.is_null_terminated;
+ bool ok_null_terminated = (wanted_type->data.array.sentinel == nullptr) ||
+ (actual_type->data.array.sentinel != nullptr &&
+ const_values_equal(ira->codegen, wanted_type->data.array.sentinel, actual_type->data.array.sentinel));
if (!ok_null_terminated) {
- result.id = ConstCastResultIdBadNullTermArrays;
- result.data.bad_null_term_arrays = allocate_nonzero(1);
- result.data.bad_null_term_arrays->child = child;
- result.data.bad_null_term_arrays->wanted_type = wanted_type;
- result.data.bad_null_term_arrays->actual_type = actual_type;
+ result.id = ConstCastResultIdSentinelArrays;
+ result.data.sentinel_arrays = allocate_nonzero(1);
+ result.data.sentinel_arrays->child = child;
+ result.data.sentinel_arrays->wanted_type = wanted_type;
+ result.data.sentinel_arrays->actual_type = actual_type;
return result;
}
return result;
@@ -10781,8 +10812,12 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
prev_type->data.pointer.child_type->id == ZigTypeIdArray &&
(cur_type->data.pointer.is_const || !prev_type->data.pointer.is_const ||
prev_type->data.pointer.child_type->data.array.len == 0) &&
- (cur_type->data.pointer.child_type->data.array.is_null_terminated ||
- !prev_type->data.pointer.child_type->data.array.is_null_terminated) &&
+ (
+ prev_type->data.pointer.child_type->data.array.sentinel == nullptr ||
+ (cur_type->data.pointer.child_type->data.array.sentinel != nullptr &&
+ const_values_equal(ira->codegen, prev_type->data.pointer.child_type->data.array.sentinel,
+ cur_type->data.pointer.child_type->data.array.sentinel))
+ ) &&
types_match_const_cast_only(ira,
cur_type->data.pointer.child_type->data.array.child_type,
prev_type->data.pointer.child_type->data.array.child_type,
@@ -10798,8 +10833,12 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
cur_type->data.pointer.child_type->id == ZigTypeIdArray &&
(prev_type->data.pointer.is_const || !cur_type->data.pointer.is_const ||
cur_type->data.pointer.child_type->data.array.len == 0) &&
- (prev_type->data.pointer.child_type->data.array.is_null_terminated ||
- !cur_type->data.pointer.child_type->data.array.is_null_terminated) &&
+ (
+ cur_type->data.pointer.child_type->data.array.sentinel == nullptr ||
+ (prev_type->data.pointer.child_type->data.array.sentinel != nullptr &&
+ const_values_equal(ira->codegen, cur_type->data.pointer.child_type->data.array.sentinel,
+ prev_type->data.pointer.child_type->data.array.sentinel))
+ ) &&
types_match_const_cast_only(ira,
prev_type->data.pointer.child_type->data.array.child_type,
cur_type->data.pointer.child_type->data.array.child_type,
@@ -10871,11 +10910,12 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
} else if (prev_inst->value.type->id == ZigTypeIdPointer) {
ZigType *array_type = prev_inst->value.type->data.pointer.child_type;
src_assert(array_type->id == ZigTypeIdArray, source_node);
- ZigType *ptr_type = get_pointer_to_type_extra(
+ ZigType *ptr_type = get_pointer_to_type_extra2(
ira->codegen, array_type->data.array.child_type,
prev_inst->value.type->data.pointer.is_const, false,
- array_type->data.array.is_null_terminated ? PtrLenNull : PtrLenUnknown,
- 0, 0, 0, false);
+ PtrLenUnknown,
+ 0, 0, 0, false,
+ VECTOR_INDEX_NONE, nullptr, array_type->data.array.sentinel);
ZigType *slice_type = get_slice_type(ira->codegen, ptr_type);
if (err_set_type != nullptr) {
return get_error_union_type(ira->codegen, err_set_type, slice_type);
@@ -11682,7 +11722,7 @@ static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *so
IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb,
source_instr->scope, source_instr->source_node);
const_instruction->base.value.special = ConstValSpecialStatic;
- if (types_have_same_zig_comptime_repr(wanted_type, payload_type)) {
+ if (types_have_same_zig_comptime_repr(ira->codegen, wanted_type, payload_type)) {
copy_const_val(&const_instruction->base.value, val, val->data.x_ptr.mut == ConstPtrMutComptimeConst);
} else {
const_instruction->base.value.data.x_optional = val;
@@ -12601,14 +12641,24 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa
break;
}
case ConstCastResultIdPtrLens: {
- ZigType *wanted_type = cast_result->data.bad_ptr_lens->wanted_type;
- ZigType *actual_type = cast_result->data.bad_ptr_lens->actual_type;
- bool wanted_null_term = wanted_type->data.pointer.ptr_len == PtrLenNull;
- bool actual_null_term = actual_type->data.pointer.ptr_len == PtrLenNull;
- if (wanted_null_term && !actual_null_term) {
- add_error_note(ira->codegen, parent_msg, source_node,
- buf_sprintf("destination type requires null termination"));
- }
+ add_error_note(ira->codegen, parent_msg, source_node,
+ buf_sprintf("pointer length mismatch"));
+ break;
+ }
+ case ConstCastResultIdPtrSentinel: {
+ ZigType *wanted_type = cast_result->data.bad_ptr_sentinel->wanted_type;
+ Buf *msg = buf_sprintf("destination pointer requires a terminating '");
+ render_const_value(ira->codegen, msg, wanted_type->data.pointer.sentinel);
+ buf_appendf(msg, "' sentinel value");
+ add_error_note(ira->codegen, parent_msg, source_node, msg);
+ break;
+ }
+ case ConstCastResultIdSentinelArrays: {
+ ZigType *wanted_type = cast_result->data.sentinel_arrays->wanted_type;
+ Buf *msg = buf_sprintf("destination array requires a terminating '");
+ render_const_value(ira->codegen, msg, wanted_type->data.pointer.sentinel);
+ buf_appendf(msg, "' sentinel value");
+ add_error_note(ira->codegen, parent_msg, source_node, msg);
break;
}
case ConstCastResultIdCV: {
@@ -12642,7 +12692,6 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa
case ConstCastResultIdUnresolvedInferredErrSet: // TODO
case ConstCastResultIdAsyncAllocatorType: // TODO
case ConstCastResultIdArrayChild: // TODO
- case ConstCastResultIdBadNullTermArrays: // TODO
break;
}
}
@@ -13013,16 +13062,18 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
// *[N]T to [*]T and [*c]T
if (wanted_type->id == ZigTypeIdPointer &&
- (wanted_type->data.pointer.ptr_len == PtrLenUnknown || wanted_type->data.pointer.ptr_len == PtrLenC ||
- wanted_type->data.pointer.ptr_len == PtrLenNull) &&
+ (wanted_type->data.pointer.ptr_len == PtrLenUnknown || wanted_type->data.pointer.ptr_len == PtrLenC) &&
actual_type->id == ZigTypeIdPointer &&
actual_type->data.pointer.ptr_len == PtrLenSingle &&
actual_type->data.pointer.child_type->id == ZigTypeIdArray &&
(!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) &&
(!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile))
{
- if (wanted_type->data.pointer.ptr_len != PtrLenNull ||
- actual_type->data.pointer.child_type->data.array.is_null_terminated)
+ ZigType *actual_array_type = actual_type->data.pointer.child_type;
+ if (wanted_type->data.pointer.sentinel == nullptr ||
+ (actual_array_type->data.array.sentinel != nullptr &&
+ const_values_equal(ira->codegen, wanted_type->data.pointer.sentinel,
+ actual_array_type->data.array.sentinel)))
{
if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
return ira->codegen->invalid_instruction;
@@ -14741,7 +14792,6 @@ static bool is_pointer_arithmetic_allowed(ZigType *lhs_type, IrBinOp op) {
case PtrLenSingle:
return lhs_type->data.pointer.child_type->id == ZigTypeIdArray;
case PtrLenUnknown:
- case PtrLenNull:
case PtrLenC:
return true;
}
@@ -15007,7 +15057,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
if (!op2_val)
return ira->codegen->invalid_instruction;
- bool is_null_terminated = false;
+ ConstExprValue *sentinel1 = nullptr;
ConstExprValue *op1_array_val;
size_t op1_array_index;
size_t op1_array_end;
@@ -15017,16 +15067,17 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
op1_array_val = op1_val;
op1_array_index = 0;
op1_array_end = op1_type->data.array.len;
+ sentinel1 = op1_type->data.array.sentinel;
} else if (op1_type->id == ZigTypeIdPointer &&
op1_type->data.pointer.child_type == ira->codegen->builtin_types.entry_u8 &&
- op1_type->data.pointer.ptr_len == PtrLenNull &&
+ op1_type->data.pointer.sentinel != nullptr &&
op1_val->data.x_ptr.special == ConstPtrSpecialBaseArray)
{
child_type = op1_type->data.pointer.child_type;
op1_array_val = op1_val->data.x_ptr.data.base_array.array_val;
op1_array_index = op1_val->data.x_ptr.data.base_array.elem_index;
op1_array_end = op1_array_val->type->data.array.len;
- is_null_terminated = true;
+ sentinel1 = op1_type->data.pointer.sentinel;
} else if (is_slice(op1_type)) {
ZigType *ptr_type = op1_type->data.structure.fields[slice_ptr_index]->type_entry;
child_type = ptr_type->data.pointer.child_type;
@@ -15036,6 +15087,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
op1_array_index = ptr_val->data.x_ptr.data.base_array.elem_index;
ConstExprValue *len_val = op1_val->data.x_struct.fields[slice_len_index];
op1_array_end = op1_array_index + bigint_as_usize(&len_val->data.x_bigint);
+ sentinel1 = ptr_type->data.pointer.sentinel;
} else if (op1_type->id == ZigTypeIdPointer && op1_type->data.pointer.ptr_len == PtrLenSingle &&
op1_type->data.pointer.child_type->id == ZigTypeIdArray)
{
@@ -15046,13 +15098,14 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
return ira->codegen->invalid_instruction;
op1_array_index = 0;
op1_array_end = array_type->data.array.len;
- is_null_terminated = is_null_terminated || array_type->data.array.is_null_terminated;
+ sentinel1 = array_type->data.array.sentinel;
} else {
ir_add_error(ira, op1,
buf_sprintf("expected array, found '%s'", buf_ptr(&op1->value.type->name)));
return ira->codegen->invalid_instruction;
}
+ ConstExprValue *sentinel2 = nullptr;
ConstExprValue *op2_array_val;
size_t op2_array_index;
size_t op2_array_end;
@@ -15062,15 +15115,17 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
op2_array_val = op2_val;
op2_array_index = 0;
op2_array_end = op2_array_val->type->data.array.len;
+ sentinel2 = op2_type->data.array.sentinel;
} else if (op2_type->id == ZigTypeIdPointer &&
- op2_type->data.pointer.ptr_len == PtrLenNull &&
+ op2_type->data.pointer.sentinel != nullptr &&
op2_val->data.x_ptr.special == ConstPtrSpecialBaseArray)
{
op2_type_valid = op2_type->data.pointer.child_type == child_type;
op2_array_val = op2_val->data.x_ptr.data.base_array.array_val;
op2_array_index = op2_val->data.x_ptr.data.base_array.elem_index;
op2_array_end = op2_array_val->type->data.array.len;
- is_null_terminated = true;
+
+ sentinel2 = op2_type->data.pointer.sentinel;
} else if (is_slice(op2_type)) {
ZigType *ptr_type = op2_type->data.structure.fields[slice_ptr_index]->type_entry;
op2_type_valid = ptr_type->data.pointer.child_type == child_type;
@@ -15080,6 +15135,8 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
op2_array_index = ptr_val->data.x_ptr.data.base_array.elem_index;
ConstExprValue *len_val = op2_val->data.x_struct.fields[slice_len_index];
op2_array_end = op2_array_index + bigint_as_usize(&len_val->data.x_bigint);
+
+ sentinel2 = ptr_type->data.pointer.sentinel;
} else if (op2_type->id == ZigTypeIdPointer && op2_type->data.pointer.ptr_len == PtrLenSingle &&
op2_type->data.pointer.child_type->id == ZigTypeIdArray)
{
@@ -15090,7 +15147,8 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
return ira->codegen->invalid_instruction;
op2_array_index = 0;
op2_array_end = array_type->data.array.len;
- is_null_terminated = is_null_terminated || array_type->data.array.is_null_terminated;
+
+ sentinel2 = array_type->data.array.sentinel;
} else {
ir_add_error(ira, op2,
buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op2->value.type->name)));
@@ -15103,6 +15161,19 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
return ira->codegen->invalid_instruction;
}
+ ConstExprValue *sentinel;
+ if (sentinel1 != nullptr && sentinel2 != nullptr) {
+ // When there is a sentinel mismatch, no sentinel on the result. The type system
+ // will catch this if it is a problem.
+ sentinel = const_values_equal(ira->codegen, sentinel1, sentinel2) ? sentinel1 : nullptr;
+ } else if (sentinel1 != nullptr) {
+ sentinel = sentinel1;
+ } else if (sentinel2 != nullptr) {
+ sentinel = sentinel2;
+ } else {
+ sentinel = nullptr;
+ }
+
// The type of result is populated in the following if blocks
IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
ConstExprValue *out_val = &result->value;
@@ -15110,24 +15181,25 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
ConstExprValue *out_array_val;
size_t new_len = (op1_array_end - op1_array_index) + (op2_array_end - op2_array_index);
if (op1_type->id == ZigTypeIdArray || op2_type->id == ZigTypeIdArray) {
- result->value.type = get_array_type(ira->codegen, child_type, new_len, false);
+ result->value.type = get_array_type(ira->codegen, child_type, new_len, sentinel);
out_array_val = out_val;
} else if (op1_type->id == ZigTypeIdPointer || op2_type->id == ZigTypeIdPointer) {
out_array_val = create_const_vals(1);
out_array_val->special = ConstValSpecialStatic;
- out_array_val->type = get_array_type(ira->codegen, child_type, new_len, is_null_terminated);
+ out_array_val->type = get_array_type(ira->codegen, child_type, new_len, sentinel);
out_val->data.x_ptr.special = ConstPtrSpecialRef;
out_val->data.x_ptr.data.ref.pointee = out_array_val;
out_val->type = get_pointer_to_type(ira->codegen, out_array_val->type, true);
} else if (is_slice(op1_type) || is_slice(op2_type)) {
- ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, child_type,
- true, false, PtrLenUnknown, 0, 0, 0, false);
+ ZigType *ptr_type = get_pointer_to_type_extra2(ira->codegen, child_type,
+ true, false, PtrLenUnknown, 0, 0, 0, false,
+ VECTOR_INDEX_NONE, nullptr, sentinel);
result->value.type = get_slice_type(ira->codegen, ptr_type);
out_array_val = create_const_vals(1);
out_array_val->special = ConstValSpecialStatic;
- out_array_val->type = get_array_type(ira->codegen, child_type, new_len, false);
+ out_array_val->type = get_array_type(ira->codegen, child_type, new_len, sentinel);
out_val->data.x_struct.fields = alloc_const_vals_ptrs(2);
@@ -15141,12 +15213,12 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
out_val->data.x_struct.fields[slice_len_index]->special = ConstValSpecialStatic;
bigint_init_unsigned(&out_val->data.x_struct.fields[slice_len_index]->data.x_bigint, new_len);
} else {
- result->value.type = get_pointer_to_type_extra(ira->codegen, child_type, true, false, PtrLenNull,
- 0, 0, 0, false);
+ result->value.type = get_pointer_to_type_extra2(ira->codegen, child_type, true, false, PtrLenUnknown,
+ 0, 0, 0, false, VECTOR_INDEX_NONE, nullptr, sentinel);
out_array_val = create_const_vals(1);
out_array_val->special = ConstValSpecialStatic;
- out_array_val->type = get_array_type(ira->codegen, child_type, new_len, false);
+ out_array_val->type = get_array_type(ira->codegen, child_type, new_len, sentinel);
out_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
out_val->data.x_ptr.data.base_array.array_val = out_array_val;
out_val->data.x_ptr.data.base_array.elem_index = 0;
@@ -15159,26 +15231,36 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
return result;
}
- out_array_val->data.x_array.data.s_none.elements = create_const_vals(new_len);
+ uint64_t full_len = new_len + ((sentinel != nullptr) ? 1 : 0);
+ out_array_val->data.x_array.data.s_none.elements = create_const_vals(full_len);
// TODO handle the buf case here for an optimization
expand_undef_array(ira->codegen, op1_array_val);
expand_undef_array(ira->codegen, op2_array_val);
size_t next_index = 0;
for (size_t i = op1_array_index; i < op1_array_end; i += 1, next_index += 1) {
- copy_const_val(&out_array_val->data.x_array.data.s_none.elements[next_index],
- &op1_array_val->data.x_array.data.s_none.elements[i], true);
+ ConstExprValue *elem_dest_val = &out_array_val->data.x_array.data.s_none.elements[next_index];
+ copy_const_val(elem_dest_val, &op1_array_val->data.x_array.data.s_none.elements[i], false);
+ elem_dest_val->parent.id = ConstParentIdArray;
+ elem_dest_val->parent.data.p_array.array_val = out_array_val;
+ elem_dest_val->parent.data.p_array.elem_index = next_index;
}
for (size_t i = op2_array_index; i < op2_array_end; i += 1, next_index += 1) {
- copy_const_val(&out_array_val->data.x_array.data.s_none.elements[next_index],
- &op2_array_val->data.x_array.data.s_none.elements[i], true);
- }
- if (next_index < new_len) {
- ConstExprValue *null_byte = &out_array_val->data.x_array.data.s_none.elements[next_index];
- init_const_unsigned_negative(null_byte, child_type, 0, false);
+ ConstExprValue *elem_dest_val = &out_array_val->data.x_array.data.s_none.elements[next_index];
+ copy_const_val(elem_dest_val, &op2_array_val->data.x_array.data.s_none.elements[i], false);
+ elem_dest_val->parent.id = ConstParentIdArray;
+ elem_dest_val->parent.data.p_array.array_val = out_array_val;
+ elem_dest_val->parent.data.p_array.elem_index = next_index;
+ }
+ if (next_index < full_len) {
+ ConstExprValue *elem_dest_val = &out_array_val->data.x_array.data.s_none.elements[next_index];
+ copy_const_val(elem_dest_val, sentinel, false);
+ elem_dest_val->parent.id = ConstParentIdArray;
+ elem_dest_val->parent.data.p_array.array_val = out_array_val;
+ elem_dest_val->parent.data.p_array.elem_index = next_index;
next_index += 1;
}
- assert(next_index == new_len);
+ assert(next_index == full_len);
return result;
}
@@ -15230,7 +15312,7 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp *
ZigType *child_type = array_type->data.array.child_type;
ZigType *result_array_type = get_array_type(ira->codegen, child_type, new_array_len,
- array_type->data.array.is_null_terminated);
+ array_type->data.array.sentinel);
IrInstruction *array_result;
if (array_val->special == ConstValSpecialUndef || array_val->data.x_array.special == ConstArraySpecialUndef) {
@@ -15250,7 +15332,7 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp *
// TODO optimize the buf case
expand_undef_array(ira->codegen, array_val);
- size_t extra_null_term = array_type->data.array.is_null_terminated ? 1 : 0;
+ size_t extra_null_term = (array_type->data.array.sentinel != nullptr) ? 1 : 0;
out_val->data.x_array.data.s_none.elements = create_const_vals(new_array_len + extra_null_term);
uint64_t i = 0;
@@ -15266,10 +15348,9 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp *
}
assert(i == new_array_len);
- if (array_type->data.array.is_null_terminated) {
- ConstExprValue *null_value = get_null_value(array_type->data.array.child_type);
+ if (array_type->data.array.sentinel != nullptr) {
ConstExprValue *elem_dest_val = &out_val->data.x_array.data.s_none.elements[i];
- copy_const_val(elem_dest_val, null_value, false);
+ copy_const_val(elem_dest_val, array_type->data.array.sentinel, false);
elem_dest_val->parent.id = ConstParentIdArray;
elem_dest_val->parent.data.p_array.array_val = out_val;
elem_dest_val->parent.data.p_array.elem_index = i;
@@ -17565,7 +17646,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
size_t dst_size = type_size(codegen, out_val->type);
if (dst_size <= src_size) {
- if (src_size == dst_size && types_have_same_zig_comptime_repr(out_val->type, pointee->type)) {
+ if (src_size == dst_size && types_have_same_zig_comptime_repr(codegen, out_val->type, pointee->type)) {
copy_const_val(out_val, pointee, ptr_val->data.x_ptr.mut != ConstPtrMutComptimeVar);
return ErrorNone;
}
@@ -18316,11 +18397,11 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
uint64_t index = bigint_as_u64(&casted_elem_index->value.data.x_bigint);
if (array_type->id == ZigTypeIdArray) {
uint64_t array_len = array_type->data.array.len;
- if (index == array_len && array_type->data.array.is_null_terminated) {
+ if (index == array_len && array_type->data.array.sentinel != nullptr) {
ZigType *elem_type = array_type->data.array.child_type;
- IrInstruction *null_element = ir_const(ira, &elem_ptr_instruction->base, elem_type);
- null_element->value = *get_null_value(elem_type);
- return ir_get_ref(ira, &elem_ptr_instruction->base, null_element, true, false);
+ IrInstruction *sentinel_elem = ir_const(ira, &elem_ptr_instruction->base, elem_type);
+ copy_const_val(&sentinel_elem->value, array_type->data.array.sentinel, false);
+ return ir_get_ref(ira, &elem_ptr_instruction->base, sentinel_elem, true, false);
}
if (index >= array_len) {
ir_add_error_node(ira, elem_ptr_instruction->base.source_node,
@@ -18337,7 +18418,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
elem_ptr_instruction->ptr_len,
get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, (uint32_t)index,
- nullptr);
+ nullptr, nullptr);
} else if (return_type->data.pointer.explicit_alignment != 0) {
// figure out the largest alignment possible
@@ -18457,7 +18538,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
new_index = offset + index;
ZigType *array_type = array_ptr_val->data.x_ptr.data.base_array.array_val->type;
mem_size = array_type->data.array.len;
- if (array_type->data.array.is_null_terminated) {
+ if (array_type->data.array.sentinel != nullptr) {
mem_size += 1;
}
old_size = mem_size - offset;
@@ -18579,7 +18660,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
elem_ptr_instruction->ptr_len,
get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, VECTOR_INDEX_RUNTIME,
- nullptr);
+ nullptr, nullptr);
} else {
// runtime known element index
switch (type_requires_comptime(ira->codegen, return_type)) {
@@ -18783,7 +18864,7 @@ static IrInstruction *ir_analyze_inferred_field_ptr(IrAnalyze *ira, Buf *field_n
ZigType *elem_type = ira->codegen->builtin_types.entry_var;
ZigType *field_ptr_type = get_pointer_to_type_extra2(ira->codegen, elem_type,
container_ptr_type->data.pointer.is_const, container_ptr_type->data.pointer.is_volatile,
- PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE, inferred_struct_field);
+ PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE, inferred_struct_field, nullptr);
if (instr_is_comptime(container_ptr)) {
IrInstruction *result = ir_const(ira, source_instr, field_ptr_type);
@@ -19565,6 +19646,12 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
return ira->codegen->invalid_instruction;
}
+ if (slice_type_instruction->sentinel != nullptr) {
+ lazy_slice_type->sentinel = slice_type_instruction->sentinel->child;
+ if (ir_resolve_const(ira, lazy_slice_type->sentinel, LazyOk) == nullptr)
+ return ira->codegen->invalid_instruction;
+ }
+
lazy_slice_type->elem_type = slice_type_instruction->child_type->child;
if (ir_resolve_type_lazy(ira, lazy_slice_type->elem_type) == nullptr)
return ira->codegen->invalid_instruction;
@@ -19572,7 +19659,6 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
lazy_slice_type->is_const = slice_type_instruction->is_const;
lazy_slice_type->is_volatile = slice_type_instruction->is_volatile;
lazy_slice_type->is_allowzero = slice_type_instruction->is_allow_zero;
- lazy_slice_type->is_null_terminated = slice_type_instruction->is_null_terminated;
return result;
}
@@ -19647,6 +19733,22 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,
ZigType *child_type = ir_resolve_type(ira, child_type_value);
if (type_is_invalid(child_type))
return ira->codegen->invalid_instruction;
+
+ ConstExprValue *sentinel_val;
+ if (array_type_instruction->sentinel != nullptr) {
+ IrInstruction *uncasted_sentinel = array_type_instruction->sentinel->child;
+ if (type_is_invalid(uncasted_sentinel->value.type))
+ return ira->codegen->invalid_instruction;
+ IrInstruction *sentinel = ir_implicit_cast(ira, uncasted_sentinel, child_type);
+ if (type_is_invalid(sentinel->value.type))
+ return ira->codegen->invalid_instruction;
+ sentinel_val = ir_resolve_const(ira, sentinel, UndefBad);
+ if (sentinel_val == nullptr)
+ return ira->codegen->invalid_instruction;
+ } else {
+ sentinel_val = nullptr;
+ }
+
switch (child_type->id) {
case ZigTypeIdInvalid: // handled above
zig_unreachable();
@@ -19682,8 +19784,7 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,
{
if ((err = type_resolve(ira->codegen, child_type, ResolveStatusSizeKnown)))
return ira->codegen->invalid_instruction;
- ZigType *result_type = get_array_type(ira->codegen, child_type, size,
- array_type_instruction->is_null_terminated);
+ ZigType *result_type = get_array_type(ira->codegen, child_type, size, sentinel_val);
return ir_const_type(ira, &array_type_instruction->base, result_type);
}
}
@@ -19802,7 +19903,7 @@ static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstr
ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type,
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0, false);
- bool same_comptime_repr = types_have_same_zig_comptime_repr(child_type, type_entry);
+ bool same_comptime_repr = types_have_same_zig_comptime_repr(ira->codegen, child_type, type_entry);
if (instr_is_comptime(base_ptr)) {
ConstExprValue *ptr_val = ir_resolve_const(ira, base_ptr, UndefBad);
@@ -20759,7 +20860,7 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira,
if (container_type->id == ZigTypeIdArray) {
ZigType *child_type = container_type->data.array.child_type;
if (container_type->data.array.len != elem_count) {
- ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count, false);
+ ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count, nullptr);
ir_add_error(ira, &instruction->base,
buf_sprintf("expected %s literal, found %s literal",
@@ -21246,7 +21347,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr
ConstExprValue *declaration_array = create_const_vals(1);
declaration_array->special = ConstValSpecialStatic;
- declaration_array->type = get_array_type(ira->codegen, type_info_declaration_type, declaration_count, false);
+ declaration_array->type = get_array_type(ira->codegen, type_info_declaration_type, declaration_count, nullptr);
declaration_array->data.x_array.special = ConstArraySpecialNone;
declaration_array->data.x_array.data.s_none.elements = create_const_vals(declaration_count);
init_const_slice(ira->codegen, out_val, declaration_array, 0, declaration_count, false);
@@ -21391,7 +21492,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr
ConstExprValue *fn_arg_name_array = create_const_vals(1);
fn_arg_name_array->special = ConstValSpecialStatic;
fn_arg_name_array->type = get_array_type(ira->codegen,
- get_slice_type(ira->codegen, u8_ptr), fn_arg_count, false);
+ get_slice_type(ira->codegen, u8_ptr), fn_arg_count, nullptr);
fn_arg_name_array->data.x_array.special = ConstArraySpecialNone;
fn_arg_name_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count);
@@ -21446,7 +21547,6 @@ static BuiltinPtrSize ptr_len_to_size_enum_index(PtrLen ptr_len) {
case PtrLenSingle:
return BuiltinPtrSizeOne;
case PtrLenUnknown:
- case PtrLenNull:
return BuiltinPtrSizeMany;
case PtrLenC:
return BuiltinPtrSizeC;
@@ -21527,11 +21627,21 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty
fields[5]->special = ConstValSpecialStatic;
fields[5]->type = ira->codegen->builtin_types.entry_bool;
fields[5]->data.x_bool = attrs_type->data.pointer.allow_zero;
- // is_null_terminated: bool
- ensure_field_index(result->type, "is_null_terminated", 6);
+ // sentinel: ?*const c_void
+ ZigType *ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_c_void, true);
+ ensure_field_index(result->type, "sentinel", 6);
fields[6]->special = ConstValSpecialStatic;
- fields[6]->type = ira->codegen->builtin_types.entry_bool;
- fields[6]->data.x_bool = attrs_type->data.pointer.ptr_len == PtrLenNull;
+ fields[6]->type = get_optional_type(ira->codegen, ptr_type);
+ if (attrs_type->data.pointer.sentinel == nullptr) {
+ fields[6]->data.x_optional = nullptr;
+ } else {
+ ConstExprValue *ptr_val = create_const_vals(1);
+ fields[6]->data.x_optional = ptr_val;
+ ptr_val->data.x_ptr.special = ConstPtrSpecialRef;
+ ptr_val->data.x_ptr.mut = ConstPtrMutComptimeConst;
+ ptr_val->data.x_ptr.data.ref.pointee = create_const_vals(1);
+ copy_const_val(ptr_val->data.x_ptr.data.ref.pointee, attrs_type->data.pointer.sentinel, false);
+ }
return result;
};
@@ -21652,11 +21762,22 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
fields[1]->special = ConstValSpecialStatic;
fields[1]->type = ira->codegen->builtin_types.entry_type;
fields[1]->data.x_type = type_entry->data.array.child_type;
- // is_null_terminated: bool
- ensure_field_index(result->type, "is_null_terminated", 2);
+ // sentinel: ?*const c_void
fields[2]->special = ConstValSpecialStatic;
- fields[2]->type = ira->codegen->builtin_types.entry_bool;
- fields[2]->data.x_bool = type_entry->data.array.is_null_terminated;
+ ZigType *ptr_type = get_pointer_to_type(ira->codegen,
+ ira->codegen->builtin_types.entry_c_void, true);
+ fields[2]->type = get_optional_type(ira->codegen, ptr_type);
+ if (type_entry->data.array.sentinel == nullptr) {
+ fields[2]->data.x_optional = nullptr;
+ } else {
+ ConstExprValue *ptr_val = create_const_vals(1);
+ fields[2]->data.x_optional = ptr_val;
+ ptr_val->type = ptr_type;
+ ptr_val->data.x_ptr.special = ConstPtrSpecialRef;
+ ptr_val->data.x_ptr.mut = ConstPtrMutComptimeConst;
+ ptr_val->data.x_ptr.data.ref.pointee = create_const_vals(1);
+ copy_const_val(ptr_val->data.x_ptr.data.ref.pointee, type_entry->data.array.sentinel, false);
+ }
break;
}
@@ -21744,7 +21865,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
ConstExprValue *enum_field_array = create_const_vals(1);
enum_field_array->special = ConstValSpecialStatic;
- enum_field_array->type = get_array_type(ira->codegen, type_info_enum_field_type, enum_field_count, false);
+ enum_field_array->type = get_array_type(ira->codegen, type_info_enum_field_type, enum_field_count, nullptr);
enum_field_array->data.x_array.special = ConstArraySpecialNone;
enum_field_array->data.x_array.data.s_none.elements = create_const_vals(enum_field_count);
@@ -21792,7 +21913,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
uint32_t error_count = type_entry->data.error_set.err_count;
ConstExprValue *error_array = create_const_vals(1);
error_array->special = ConstValSpecialStatic;
- error_array->type = get_array_type(ira->codegen, type_info_error_type, error_count, false);
+ error_array->type = get_array_type(ira->codegen, type_info_error_type, error_count, nullptr);
error_array->data.x_array.special = ConstArraySpecialNone;
error_array->data.x_array.data.s_none.elements = create_const_vals(error_count);
@@ -21888,7 +22009,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
ConstExprValue *union_field_array = create_const_vals(1);
union_field_array->special = ConstValSpecialStatic;
- union_field_array->type = get_array_type(ira->codegen, type_info_union_field_type, union_field_count, false);
+ union_field_array->type = get_array_type(ira->codegen, type_info_union_field_type, union_field_count, nullptr);
union_field_array->data.x_array.special = ConstArraySpecialNone;
union_field_array->data.x_array.data.s_none.elements = create_const_vals(union_field_count);
@@ -21968,7 +22089,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
ConstExprValue *struct_field_array = create_const_vals(1);
struct_field_array->special = ConstValSpecialStatic;
- struct_field_array->type = get_array_type(ira->codegen, type_info_struct_field_type, struct_field_count, false);
+ struct_field_array->type = get_array_type(ira->codegen, type_info_struct_field_type, struct_field_count, nullptr);
struct_field_array->data.x_array.special = ConstArraySpecialNone;
struct_field_array->data.x_array.data.s_none.elements = create_const_vals(struct_field_count);
@@ -22071,7 +22192,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
ConstExprValue *fn_arg_array = create_const_vals(1);
fn_arg_array->special = ConstValSpecialStatic;
- fn_arg_array->type = get_array_type(ira->codegen, type_info_fn_arg_type, fn_arg_count, false);
+ fn_arg_array->type = get_array_type(ira->codegen, type_info_fn_arg_type, fn_arg_count, nullptr);
fn_arg_array->data.x_array.special = ConstArraySpecialNone;
fn_arg_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count);
@@ -22169,6 +22290,17 @@ static ConstExprValue *get_const_field(IrAnalyze *ira, ConstExprValue *struct_va
return struct_value->data.x_struct.fields[field_index];
}
+static ConstExprValue *get_const_field_variant(IrAnalyze *ira, ConstExprValue *struct_value,
+ const char *name, size_t field_index)
+{
+ ConstExprValue *field_val = get_const_field(ira, struct_value, name, field_index);
+ assert(field_val->type->id == ZigTypeIdOptional);
+ ConstExprValue *opt_val = field_val->data.x_optional;
+ if (opt_val == nullptr) return nullptr;
+ assert(opt_val->type->id == ZigTypeIdPointer);
+ return const_ptr_pointee_unchecked(ira->codegen, opt_val);
+}
+
static bool get_const_field_bool(IrAnalyze *ira, ConstExprValue *struct_value, const char *name, size_t field_index)
{
ConstExprValue *value = get_const_field(ira, struct_value, name, field_index);
@@ -22232,7 +22364,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInstruction *instruction, Zi
assert(size_value->type == ir_type_info_get_type(ira, "Size", type_info_pointer_type));
BuiltinPtrSize size_enum_index = (BuiltinPtrSize)bigint_as_u32(&size_value->data.x_enum_tag);
PtrLen ptr_len = size_enum_index_to_ptr_len(size_enum_index);
- ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen,
+ ZigType *ptr_type = get_pointer_to_type_extra2(ira->codegen,
get_const_field_meta_type(ira, payload, "child", 4),
get_const_field_bool(ira, payload, "is_const", 1),
get_const_field_bool(ira, payload, "is_volatile", 2),
@@ -22240,7 +22372,10 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInstruction *instruction, Zi
bigint_as_u32(get_const_field_lit_int(ira, payload, "alignment", 3)),
0, // bit_offset_in_host
0, // host_int_bytes
- get_const_field_bool(ira, payload, "is_allowzero", 5)
+ get_const_field_bool(ira, payload, "is_allowzero", 5),
+ VECTOR_INDEX_NONE,
+ nullptr,
+ get_const_field_variant(ira, payload, "sentinel", 6)
);
if (size_enum_index != 2)
return ptr_type;
@@ -22252,7 +22387,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInstruction *instruction, Zi
return get_array_type(ira->codegen,
get_const_field_meta_type(ira, payload, "child", 1),
bigint_as_u64(get_const_field_lit_int(ira, payload, "len", 0)),
- get_const_field_bool(ira, payload, "is_null_terminated", 2)
+ get_const_field_variant(ira, payload, "sentinel", 2)
);
case ZigTypeIdComptimeFloat:
return ira->codegen->builtin_types.entry_num_lit_float;
@@ -22635,7 +22770,7 @@ static IrInstruction *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstru
}
ZigType *result_type = get_array_type(ira->codegen,
- ira->codegen->builtin_types.entry_u8, buf_len(file_contents), false);
+ ira->codegen->builtin_types.entry_u8, buf_len(file_contents), nullptr);
IrInstruction *result = ir_const(ira, &instruction->base, result_type);
init_const_str_lit(ira->codegen, &result->value, file_contents);
return result;
@@ -25858,6 +25993,12 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct
result->value.data.x_lazy = &lazy_ptr_type->base;
lazy_ptr_type->base.id = LazyValueIdPtrType;
+ if (instruction->sentinel != nullptr) {
+ lazy_ptr_type->sentinel = instruction->sentinel->child;
+ if (ir_resolve_const(ira, lazy_ptr_type->sentinel, LazyOk) == nullptr)
+ return ira->codegen->invalid_instruction;
+ }
+
lazy_ptr_type->elem_type = instruction->child_type->child;
if (ir_resolve_type_lazy(ira, lazy_ptr_type->elem_type) == nullptr)
return ira->codegen->invalid_instruction;
@@ -27804,6 +27945,20 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {
if (type_is_invalid(elem_type))
return ErrorSemanticAnalyzeFail;
+ ConstExprValue *sentinel_val;
+ if (lazy_slice_type->sentinel != nullptr) {
+ if (type_is_invalid(lazy_slice_type->sentinel->value.type))
+ return ErrorSemanticAnalyzeFail;
+ IrInstruction *sentinel = ir_implicit_cast(ira, lazy_slice_type->sentinel, elem_type);
+ if (type_is_invalid(sentinel->value.type))
+ return ErrorSemanticAnalyzeFail;
+ sentinel_val = ir_resolve_const(ira, sentinel, UndefBad);
+ if (sentinel_val == nullptr)
+ return ErrorSemanticAnalyzeFail;
+ } else {
+ sentinel_val = nullptr;
+ }
+
uint32_t align_bytes = 0;
if (lazy_slice_type->align_inst != nullptr) {
if (!ir_resolve_align(ira, lazy_slice_type->align_inst, elem_type, &align_bytes))
@@ -27849,11 +28004,12 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {
ResolveStatusZeroBitsKnown : ResolveStatusAlignmentKnown;
if ((err = type_resolve(ira->codegen, elem_type, needed_status)))
return err;
- ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, elem_type,
+ ZigType *slice_ptr_type = get_pointer_to_type_extra2(ira->codegen, elem_type,
lazy_slice_type->is_const, lazy_slice_type->is_volatile,
- lazy_slice_type->is_null_terminated ? PtrLenNull : PtrLenUnknown,
+ PtrLenUnknown,
align_bytes,
- 0, 0, lazy_slice_type->is_allowzero);
+ 0, 0, lazy_slice_type->is_allowzero,
+ VECTOR_INDEX_NONE, nullptr, sentinel_val);
val->special = ConstValSpecialStatic;
assert(val->type->id == ZigTypeIdMetaType);
val->data.x_type = get_slice_type(ira->codegen, slice_ptr_type);
@@ -27867,6 +28023,20 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {
if (type_is_invalid(elem_type))
return ErrorSemanticAnalyzeFail;
+ ConstExprValue *sentinel_val;
+ if (lazy_ptr_type->sentinel != nullptr) {
+ if (type_is_invalid(lazy_ptr_type->sentinel->value.type))
+ return ErrorSemanticAnalyzeFail;
+ IrInstruction *sentinel = ir_implicit_cast(ira, lazy_ptr_type->sentinel, elem_type);
+ if (type_is_invalid(sentinel->value.type))
+ return ErrorSemanticAnalyzeFail;
+ sentinel_val = ir_resolve_const(ira, sentinel, UndefBad);
+ if (sentinel_val == nullptr)
+ return ErrorSemanticAnalyzeFail;
+ } else {
+ sentinel_val = nullptr;
+ }
+
uint32_t align_bytes = 0;
if (lazy_ptr_type->align_inst != nullptr) {
if (!ir_resolve_align(ira, lazy_ptr_type->align_inst, elem_type, &align_bytes))
@@ -27909,10 +28079,10 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {
}
bool allow_zero = lazy_ptr_type->is_allowzero || lazy_ptr_type->ptr_len == PtrLenC;
assert(val->type->id == ZigTypeIdMetaType);
- val->data.x_type = get_pointer_to_type_extra(ira->codegen, elem_type,
+ val->data.x_type = get_pointer_to_type_extra2(ira->codegen, elem_type,
lazy_ptr_type->is_const, lazy_ptr_type->is_volatile, lazy_ptr_type->ptr_len, align_bytes,
lazy_ptr_type->bit_offset_in_host, lazy_ptr_type->host_int_bytes,
- allow_zero);
+ allow_zero, VECTOR_INDEX_NONE, nullptr, sentinel_val);
val->special = ConstValSpecialStatic;
return ErrorNone;
}
diff --git a/src/parser.cpp b/src/parser.cpp
index c3f719425b..61f3120d0e 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -1833,8 +1833,10 @@ static AstNode *ast_parse_labeled_type_expr(ParseContext *pc) {
return loop;
}
- if (label != nullptr)
- ast_invalid_token_error(pc, peek_token(pc));
+ if (label != nullptr) {
+ put_back_token(pc);
+ put_back_token(pc);
+ }
return nullptr;
}
@@ -1931,15 +1933,11 @@ static AstNode *ast_parse_asm_output(ParseContext *pc) {
// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN
static AsmOutput *ast_parse_asm_output_item(ParseContext *pc) {
- Token *sym_name = eat_token_if(pc, TokenIdBracketUnderscoreBracket);
- if (sym_name == nullptr) {
- if (eat_token_if(pc, TokenIdLBracket) == nullptr) {
- return nullptr;
- } else {
- sym_name = expect_token(pc, TokenIdSymbol);
- expect_token(pc, TokenIdRBracket);
- }
- }
+ if (eat_token_if(pc, TokenIdLBracket) == nullptr)
+ return nullptr;
+
+ Token *sym_name = expect_token(pc, TokenIdSymbol);
+ expect_token(pc, TokenIdRBracket);
Token *str = expect_token(pc, TokenIdStringLiteral);
expect_token(pc, TokenIdLParen);
@@ -1954,7 +1952,7 @@ static AsmOutput *ast_parse_asm_output_item(ParseContext *pc) {
expect_token(pc, TokenIdRParen);
AsmOutput *res = allocate(1);
- res->asm_symbolic_name = (sym_name->id == TokenIdBracketUnderscoreBracket) ? buf_create_from_str("_") : token_buf(sym_name);
+ res->asm_symbolic_name = token_buf(sym_name);
res->constraint = token_buf(str);
res->variable_name = token_buf(var_name);
res->return_type = return_type;
@@ -1977,15 +1975,11 @@ static AstNode *ast_parse_asm_input(ParseContext *pc) {
// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN
static AsmInput *ast_parse_asm_input_item(ParseContext *pc) {
- Token *sym_name = eat_token_if(pc, TokenIdBracketUnderscoreBracket);
- if (sym_name == nullptr) {
- if (eat_token_if(pc, TokenIdLBracket) == nullptr) {
- return nullptr;
- } else {
- sym_name = expect_token(pc, TokenIdSymbol);
- expect_token(pc, TokenIdRBracket);
- }
- }
+ if (eat_token_if(pc, TokenIdLBracket) == nullptr)
+ return nullptr;
+
+ Token *sym_name = expect_token(pc, TokenIdSymbol);
+ expect_token(pc, TokenIdRBracket);
Token *constraint = expect_token(pc, TokenIdStringLiteral);
expect_token(pc, TokenIdLParen);
@@ -1993,7 +1987,7 @@ static AsmInput *ast_parse_asm_input_item(ParseContext *pc) {
expect_token(pc, TokenIdRParen);
AsmInput *res = allocate(1);
- res->asm_symbolic_name = (sym_name->id == TokenIdBracketUnderscoreBracket) ? buf_create_from_str("_") : token_buf(sym_name);
+ res->asm_symbolic_name = token_buf(sym_name);
res->constraint = token_buf(constraint);
res->expr = expr;
return res;
@@ -2613,42 +2607,28 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) {
put_back_token(pc);
}
- AstNode *array = ast_parse_array_type_start(pc);
- if (array != nullptr) {
- assert(array->type == NodeTypeArrayType);
- while (true) {
- if (eat_token_if(pc, TokenIdKeywordNull) != nullptr) {
- array->data.array_type.is_null_terminated = true;
- continue;
- }
-
- Token *allowzero_token = eat_token_if(pc, TokenIdKeywordAllowZero);
- if (allowzero_token != nullptr) {
- array->data.array_type.allow_zero_token = allowzero_token;
- continue;
- }
-
- AstNode *align_expr = ast_parse_byte_align(pc);
- if (align_expr != nullptr) {
- array->data.array_type.align_expr = align_expr;
- continue;
- }
-
- if (eat_token_if(pc, TokenIdKeywordConst) != nullptr) {
- array->data.array_type.is_const = true;
- continue;
- }
-
- if (eat_token_if(pc, TokenIdKeywordVolatile) != nullptr) {
- array->data.array_type.is_volatile = true;
- continue;
+ Token *arr_init_lbracket = eat_token_if(pc, TokenIdLBracket);
+ if (arr_init_lbracket != nullptr) {
+ Token *underscore = eat_token_if(pc, TokenIdSymbol);
+ if (underscore == nullptr) {
+ put_back_token(pc);
+ } else if (!buf_eql_str(token_buf(underscore), "_")) {
+ put_back_token(pc);
+ put_back_token(pc);
+ } else {
+ AstNode *sentinel = nullptr;
+ Token *colon = eat_token_if(pc, TokenIdColon);
+ if (colon != nullptr) {
+ sentinel = ast_expect(pc, ast_parse_expr);
}
- break;
+ expect_token(pc, TokenIdRBracket);
+ AstNode *node = ast_create_node(pc, NodeTypeInferredArrayType, arr_init_lbracket);
+ node->data.inferred_array_type.sentinel = sentinel;
+ return node;
}
-
- return array;
}
+
AstNode *ptr = ast_parse_ptr_type_start(pc);
if (ptr != nullptr) {
assert(ptr->type == NodeTypePointerType);
@@ -2657,11 +2637,6 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) {
if (child == nullptr)
child = ptr;
while (true) {
- if (eat_token_if(pc, TokenIdKeywordNull) != nullptr) {
- child->data.pointer_type.is_null_terminated = true;
- continue;
- }
-
Token *allowzero_token = eat_token_if(pc, TokenIdKeywordAllowZero);
if (allowzero_token != nullptr) {
child->data.pointer_type.allow_zero_token = allowzero_token;
@@ -2699,9 +2674,35 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) {
return ptr;
}
- Token *arr_init = eat_token_if(pc, TokenIdBracketUnderscoreBracket);
- if (arr_init != nullptr) {
- return ast_create_node(pc, NodeTypeInferredArrayType, arr_init);
+ AstNode *array = ast_parse_array_type_start(pc);
+ if (array != nullptr) {
+ assert(array->type == NodeTypeArrayType);
+ while (true) {
+ Token *allowzero_token = eat_token_if(pc, TokenIdKeywordAllowZero);
+ if (allowzero_token != nullptr) {
+ array->data.array_type.allow_zero_token = allowzero_token;
+ continue;
+ }
+
+ AstNode *align_expr = ast_parse_byte_align(pc);
+ if (align_expr != nullptr) {
+ array->data.array_type.align_expr = align_expr;
+ continue;
+ }
+
+ if (eat_token_if(pc, TokenIdKeywordConst) != nullptr) {
+ array->data.array_type.is_const = true;
+ continue;
+ }
+
+ if (eat_token_if(pc, TokenIdKeywordVolatile) != nullptr) {
+ array->data.array_type.is_volatile = true;
+ continue;
+ }
+ break;
+ }
+
+ return array;
}
@@ -2775,9 +2776,15 @@ static AstNode *ast_parse_array_type_start(ParseContext *pc) {
return nullptr;
AstNode *size = ast_parse_expr(pc);
+ AstNode *sentinel = nullptr;
+ Token *colon = eat_token_if(pc, TokenIdColon);
+ if (colon != nullptr) {
+ sentinel = ast_expect(pc, ast_parse_expr);
+ }
expect_token(pc, TokenIdRBracket);
AstNode *res = ast_create_node(pc, NodeTypeArrayType, lbracket);
res->data.array_type.size = size;
+ res->data.array_type.sentinel = sentinel;
return res;
}
@@ -2787,35 +2794,63 @@ static AstNode *ast_parse_array_type_start(ParseContext *pc) {
// / PTRUNKNOWN
// / PTRC
static AstNode *ast_parse_ptr_type_start(ParseContext *pc) {
+ AstNode *sentinel = nullptr;
+
Token *asterisk = eat_token_if(pc, TokenIdStar);
if (asterisk != nullptr) {
+ Token *colon = eat_token_if(pc, TokenIdColon);
+ if (colon != nullptr) {
+ sentinel = ast_expect(pc, ast_parse_expr);
+ }
AstNode *res = ast_create_node(pc, NodeTypePointerType, asterisk);
res->data.pointer_type.star_token = asterisk;
+ res->data.pointer_type.sentinel = sentinel;
return res;
}
Token *asterisk2 = eat_token_if(pc, TokenIdStarStar);
if (asterisk2 != nullptr) {
+ Token *colon = eat_token_if(pc, TokenIdColon);
+ if (colon != nullptr) {
+ sentinel = ast_expect(pc, ast_parse_expr);
+ }
AstNode *res = ast_create_node(pc, NodeTypePointerType, asterisk2);
AstNode *res2 = ast_create_node(pc, NodeTypePointerType, asterisk2);
res->data.pointer_type.star_token = asterisk2;
res2->data.pointer_type.star_token = asterisk2;
+ res2->data.pointer_type.sentinel = sentinel;
res->data.pointer_type.op_expr = res2;
return res;
}
- Token *multptr = eat_token_if(pc, TokenIdBracketStarBracket);
- if (multptr != nullptr) {
- AstNode *res = ast_create_node(pc, NodeTypePointerType, multptr);
- res->data.pointer_type.star_token = multptr;
- return res;
- }
+ Token *lbracket = eat_token_if(pc, TokenIdLBracket);
+ if (lbracket != nullptr) {
+ Token *star = eat_token_if(pc, TokenIdStar);
+ if (star == nullptr) {
+ put_back_token(pc);
+ } else {
+ Token *c_tok = eat_token_if(pc, TokenIdSymbol);
+ if (c_tok != nullptr) {
+ if (!buf_eql_str(token_buf(c_tok), "c")) {
+ put_back_token(pc); // c symbol
+ } else {
+ expect_token(pc, TokenIdRBracket);
+ AstNode *res = ast_create_node(pc, NodeTypePointerType, lbracket);
+ res->data.pointer_type.star_token = c_tok;
+ return res;
+ }
+ }
- Token *cptr = eat_token_if(pc, TokenIdBracketStarCBracket);
- if (cptr != nullptr) {
- AstNode *res = ast_create_node(pc, NodeTypePointerType, cptr);
- res->data.pointer_type.star_token = cptr;
- return res;
+ Token *colon = eat_token_if(pc, TokenIdColon);
+ if (colon != nullptr) {
+ sentinel = ast_expect(pc, ast_parse_expr);
+ }
+ expect_token(pc, TokenIdRBracket);
+ AstNode *res = ast_create_node(pc, NodeTypePointerType, lbracket);
+ res->data.pointer_type.star_token = lbracket;
+ res->data.pointer_type.sentinel = sentinel;
+ return res;
+ }
}
return nullptr;
@@ -3093,10 +3128,12 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
break;
case NodeTypeArrayType:
visit_field(&node->data.array_type.size, visit, context);
+ visit_field(&node->data.array_type.sentinel, visit, context);
visit_field(&node->data.array_type.child_type, visit, context);
visit_field(&node->data.array_type.align_expr, visit, context);
break;
case NodeTypeInferredArrayType:
+ visit_field(&node->data.array_type.sentinel, visit, context);
visit_field(&node->data.array_type.child_type, visit, context);
break;
case NodeTypeAnyFrameType:
@@ -3106,6 +3143,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
// none
break;
case NodeTypePointerType:
+ visit_field(&node->data.pointer_type.sentinel, visit, context);
visit_field(&node->data.pointer_type.align_expr, visit, context);
visit_field(&node->data.pointer_type.op_expr, visit, context);
break;
diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp
index 5088fbdbf8..f8b5059bf1 100644
--- a/src/tokenizer.cpp
+++ b/src/tokenizer.cpp
@@ -222,10 +222,6 @@ enum TokenizeState {
TokenizeStateSawAtSign,
TokenizeStateCharCode,
TokenizeStateError,
- TokenizeStateLBracket,
- TokenizeStateLBracketStar,
- TokenizeStateLBracketStarC,
- TokenizeStateLBracketUnderscore,
};
@@ -480,8 +476,8 @@ void tokenize(Buf *buf, Tokenization *out) {
end_token(&t);
break;
case '[':
- t.state = TokenizeStateLBracket;
begin_token(&t, TokenIdLBracket);
+ end_token(&t);
break;
case ']':
begin_token(&t, TokenIdRBracket);
@@ -775,62 +771,6 @@ void tokenize(Buf *buf, Tokenization *out) {
continue;
}
break;
- case TokenizeStateLBracket:
- switch (c) {
- case '*':
- t.state = TokenizeStateLBracketStar;
- break;
- case '_':
- t.state = TokenizeStateLBracketUnderscore;
- break;
- default:
- // reinterpret as just an lbracket
- t.pos -= 1;
- end_token(&t);
- t.state = TokenizeStateStart;
- continue;
- }
- break;
- case TokenizeStateLBracketUnderscore:
- switch (c) {
- case ']':
- set_token_id(&t, t.cur_tok, TokenIdBracketUnderscoreBracket);
- end_token(&t);
- t.state = TokenizeStateStart;
- break;
- default:
- // reinterpret as just an lbracket
- t.pos -= 2;
- end_token(&t);
- t.state = TokenizeStateStart;
- continue;
- }
- break;
- case TokenizeStateLBracketStar:
- switch (c) {
- case 'c':
- t.state = TokenizeStateLBracketStarC;
- set_token_id(&t, t.cur_tok, TokenIdBracketStarCBracket);
- break;
- case ']':
- set_token_id(&t, t.cur_tok, TokenIdBracketStarBracket);
- end_token(&t);
- t.state = TokenizeStateStart;
- break;
- default:
- invalid_char_error(&t, c);
- }
- break;
- case TokenizeStateLBracketStarC:
- switch (c) {
- case ']':
- end_token(&t);
- t.state = TokenizeStateStart;
- break;
- default:
- invalid_char_error(&t, c);
- }
- break;
case TokenizeStateSawPlusPercent:
switch (c) {
case '=':
@@ -1525,7 +1465,6 @@ void tokenize(Buf *buf, Tokenization *out) {
case TokenizeStateLineString:
case TokenizeStateLineStringEnd:
case TokenizeStateSawBarBar:
- case TokenizeStateLBracket:
case TokenizeStateDocComment:
case TokenizeStateContainerDocComment:
end_token(&t);
@@ -1534,9 +1473,6 @@ void tokenize(Buf *buf, Tokenization *out) {
case TokenizeStateSawBackslash:
case TokenizeStateLineStringContinue:
case TokenizeStateLineStringContinueC:
- case TokenizeStateLBracketStar:
- case TokenizeStateLBracketStarC:
- case TokenizeStateLBracketUnderscore:
tokenize_error(&t, "unexpected EOF");
break;
case TokenizeStateLineComment:
@@ -1576,8 +1512,6 @@ const char * token_name(TokenId id) {
case TokenIdBitShiftRight: return ">>";
case TokenIdBitShiftRightEq: return ">>=";
case TokenIdBitXorEq: return "^=";
- case TokenIdBracketStarBracket: return "[*]";
- case TokenIdBracketStarCBracket: return "[*c]";
case TokenIdCharLiteral: return "CharLiteral";
case TokenIdCmpEq: return "==";
case TokenIdCmpGreaterOrEq: return ">=";
@@ -1681,7 +1615,6 @@ const char * token_name(TokenId id) {
case TokenIdTimesPercent: return "*%";
case TokenIdTimesPercentEq: return "*%=";
case TokenIdBarBarEq: return "||=";
- case TokenIdBracketUnderscoreBracket: return "[_]";
case TokenIdCount:
zig_unreachable();
}
diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp
index b152eb079c..084512a576 100644
--- a/src/tokenizer.hpp
+++ b/src/tokenizer.hpp
@@ -28,9 +28,6 @@ enum TokenId {
TokenIdBitShiftRight,
TokenIdBitShiftRightEq,
TokenIdBitXorEq,
- TokenIdBracketStarBracket,
- TokenIdBracketStarCBracket,
- TokenIdBracketUnderscoreBracket,
TokenIdCharLiteral,
TokenIdCmpEq,
TokenIdCmpGreaterOrEq,
diff --git a/src/translate_c.cpp b/src/translate_c.cpp
index 5dd6064984..3fe5fced07 100644
--- a/src/translate_c.cpp
+++ b/src/translate_c.cpp
@@ -291,10 +291,9 @@ static TokenId ptr_len_to_token_id(PtrLen ptr_len) {
case PtrLenSingle:
return TokenIdStar;
case PtrLenUnknown:
- case PtrLenNull:
- return TokenIdBracketStarBracket;
+ return TokenIdLBracket;
case PtrLenC:
- return TokenIdBracketStarCBracket;
+ return TokenIdSymbol;
}
zig_unreachable();
}
@@ -303,7 +302,6 @@ static AstNode *trans_create_node_ptr_type(Context *c, bool is_const, bool is_vo
AstNode *node = trans_create_node(c, NodeTypePointerType);
node->data.pointer_type.star_token = allocate(1);
node->data.pointer_type.star_token->id = ptr_len_to_token_id(ptr_len);
- node->data.pointer_type.is_null_terminated = (ptr_len == PtrLenNull);
node->data.pointer_type.is_const = is_const;
node->data.pointer_type.is_volatile = is_volatile;
node->data.pointer_type.op_expr = child_node;
diff --git a/test/stage1/behavior/array.zig b/test/stage1/behavior/array.zig
index b9000125b3..47e74cd310 100644
--- a/test/stage1/behavior/array.zig
+++ b/test/stage1/behavior/array.zig
@@ -351,7 +351,7 @@ test "anonymous literal in array" {
test "access the null element of a null terminated array" {
const S = struct {
fn doTheTest() void {
- var array: [4]null u8 = .{'a', 'o', 'e', 'u'};
+ var array: [4:0]u8 = .{'a', 'o', 'e', 'u'};
comptime expect(array[4] == 0);
var len: usize = 4;
expect(array[len] == 0);
diff --git a/test/stage1/behavior/cast.zig b/test/stage1/behavior/cast.zig
index affd7afe5e..9fccff51e3 100644
--- a/test/stage1/behavior/cast.zig
+++ b/test/stage1/behavior/cast.zig
@@ -226,7 +226,7 @@ fn testCastConstArrayRefToConstSlice() void {
{
const blah = "aoeu".*;
const const_array_ref = &blah;
- expect(@typeOf(const_array_ref) == *const [4]null u8);
+ expect(@typeOf(const_array_ref) == *const [4:0]u8);
const slice: []const u8 = const_array_ref;
expect(mem.eql(u8, slice, "aoeu"));
}
diff --git a/test/stage1/behavior/misc.zig b/test/stage1/behavior/misc.zig
index a0188dcedd..6ac745f5c5 100644
--- a/test/stage1/behavior/misc.zig
+++ b/test/stage1/behavior/misc.zig
@@ -362,8 +362,8 @@ test "string concatenation" {
const a = "OK" ++ " IT " ++ "WORKED";
const b = "OK IT WORKED";
- comptime expect(@typeOf(a) == *const [12]null u8);
- comptime expect(@typeOf(b) == *const [12]null u8);
+ comptime expect(@typeOf(a) == *const [12:0]u8);
+ comptime expect(@typeOf(b) == *const [12:0]u8);
const len = mem.len(u8, b);
const len_with_null = len + 1;
diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig
index 7d8bdea569..6529a59059 100644
--- a/test/stage1/behavior/pointers.zig
+++ b/test/stage1/behavior/pointers.zig
@@ -205,7 +205,7 @@ test "null terminated pointer" {
const S = struct {
fn doTheTest() void {
var array_with_zero = [_]u8{'h', 'e', 'l', 'l', 'o', 0};
- var zero_ptr: [*]null const u8 = @ptrCast([*]null const u8, &array_with_zero);
+ var zero_ptr: [*:0]const u8 = @ptrCast([*:0]const u8, &array_with_zero);
var no_zero_ptr: [*]const u8 = zero_ptr;
expect(std.mem.eql(u8, std.mem.toSliceConst(u8, no_zero_ptr), "hello"));
}
diff --git a/test/stage1/behavior/type.zig b/test/stage1/behavior/type.zig
index b1bb2e85bd..e3ce4d0904 100644
--- a/test/stage1/behavior/type.zig
+++ b/test/stage1/behavior/type.zig
@@ -98,21 +98,21 @@ test "Type.Array" {
.Array = TypeInfo.Array{
.len = 123,
.child = u8,
- .is_null_terminated = false,
+ .sentinel = null,
},
}));
testing.expect([2]u32 == @Type(TypeInfo{
.Array = TypeInfo.Array{
.len = 2,
.child = u32,
- .is_null_terminated = false,
+ .sentinel = null,
},
}));
- testing.expect([2]null u32 == @Type(TypeInfo{
+ testing.expect([2:0]u32 == @Type(TypeInfo{
.Array = TypeInfo.Array{
.len = 2,
.child = u32,
- .is_null_terminated = true,
+ .sentinel = &0,
},
}));
testTypes([_]type{ [1]u8, [30]usize, [7]bool });
diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig
index 4da2bb3ca2..dcd4da3d0f 100644
--- a/test/stage1/behavior/type_info.zig
+++ b/test/stage1/behavior/type_info.zig
@@ -71,17 +71,17 @@ test "type info: null terminated pointer type info" {
}
fn testNullTerminatedPtr() void {
- const ptr_info = @typeInfo([*]null u8);
+ const ptr_info = @typeInfo([*:0]u8);
expect(@as(TypeId, ptr_info) == TypeId.Pointer);
expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
expect(ptr_info.Pointer.is_const == false);
expect(ptr_info.Pointer.is_volatile == false);
expect(ptr_info.Pointer.is_null_terminated == true);
- expect(@typeInfo([]null u8).Pointer.is_null_terminated == true);
- expect(@typeInfo([10]null u8).Array.is_null_terminated == true);
- expect(@typeInfo([10]null u8).Array.len == 10);
- expect(@sizeOf([10]null u8) == 11);
+ expect(@typeInfo([:0]u8).Pointer.sentinel != null);
+ expect(@typeInfo([10:0]u8).Array.sentinel != null);
+ expect(@typeInfo([10:0]u8).Array.len == 10);
+ expect(@sizeOf([10:0]u8) == 11);
}
test "type info: C pointer type info" {
--
cgit v1.2.3
From f25182f46dd672eb5b10533c67ed462a3e5df999 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sat, 23 Nov 2019 17:51:37 -0500
Subject: structs can have fields with type `var`
behavior tests passing now
---
lib/std/builtin.zig | 12 ++--
src/all_types.hpp | 1 +
src/analyze.cpp | 8 +++
src/ast_render.cpp | 6 ++
src/ir.cpp | 115 +++++++++++++++++++++----------------
src/parser.cpp | 8 ++-
test/stage1/behavior/type.zig | 2 +-
test/stage1/behavior/type_info.zig | 6 +-
8 files changed, 97 insertions(+), 61 deletions(-)
(limited to 'src/analyze.cpp')
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig
index 64fc68e4cc..af045c5231 100644
--- a/lib/std/builtin.zig
+++ b/lib/std/builtin.zig
@@ -146,10 +146,8 @@ pub const TypeInfo = union(enum) {
is_allowzero: bool,
/// The type of the sentinel is the element type of the pointer, which is
/// the value of the `child` field in this struct. However there is no way
- /// to refer to that type here, so this is a pointer to an opaque value.
- /// It will be known at compile-time to be the correct type. Dereferencing
- /// this pointer will work at compile-time.
- sentinel: ?*const c_void,
+ /// to refer to that type here, so we use `var`.
+ sentinel: var,
/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
@@ -168,10 +166,8 @@ pub const TypeInfo = union(enum) {
child: type,
/// The type of the sentinel is the element type of the array, which is
/// the value of the `child` field in this struct. However there is no way
- /// to refer to that type here, so this is a pointer to an opaque value.
- /// It will be known at compile-time to be the correct type. Dereferencing
- /// this pointer will work at compile-time.
- sentinel: ?*const c_void,
+ /// to refer to that type here, so we use `var`.
+ sentinel: var,
};
/// This data structure is used by the Zig language code generation and
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 1f785a63f3..3b5a067ffc 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -601,6 +601,7 @@ enum NodeType {
NodeTypeSuspend,
NodeTypeAnyFrameType,
NodeTypeEnumLiteral,
+ NodeTypeVarFieldType,
};
enum CallingConvention {
diff --git a/src/analyze.cpp b/src/analyze.cpp
index aa58d64aa4..d065f85c67 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -1179,6 +1179,10 @@ Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, ZigType *
Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_val, bool *is_opaque_type) {
if (type_val->special != ConstValSpecialLazy) {
assert(type_val->special == ConstValSpecialStatic);
+ if (type_val->data.x_type == g->builtin_types.entry_var) {
+ *is_opaque_type = false;
+ return ErrorNone;
+ }
*is_opaque_type = (type_val->data.x_type->id == ZigTypeIdOpaque);
return ErrorNone;
}
@@ -3667,6 +3671,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
case NodeTypeEnumLiteral:
case NodeTypeAnyFrameType:
case NodeTypeErrorSetField:
+ case NodeTypeVarFieldType:
zig_unreachable();
}
}
@@ -5587,6 +5592,9 @@ ConstExprValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) {
ReqCompTime type_requires_comptime(CodeGen *g, ZigType *ty) {
Error err;
+ if (ty == g->builtin_types.entry_var) {
+ return ReqCompTimeYes;
+ }
switch (ty->id) {
case ZigTypeIdInvalid:
zig_unreachable();
diff --git a/src/ast_render.cpp b/src/ast_render.cpp
index f4f97c3730..531fcf1852 100644
--- a/src/ast_render.cpp
+++ b/src/ast_render.cpp
@@ -268,6 +268,8 @@ static const char *node_type_str(NodeType node_type) {
return "EnumLiteral";
case NodeTypeErrorSetField:
return "ErrorSetField";
+ case NodeTypeVarFieldType:
+ return "VarFieldType";
}
zig_unreachable();
}
@@ -1184,6 +1186,10 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
fprintf(ar->f, ".%s", buf_ptr(&node->data.enum_literal.identifier->data.str_lit.str));
break;
}
+ case NodeTypeVarFieldType: {
+ fprintf(ar->f, "var");
+ break;
+ }
case NodeTypeParamDecl:
case NodeTypeTestDecl:
case NodeTypeStructField:
diff --git a/src/ir.cpp b/src/ir.cpp
index a7a3fc51e4..df76d3f963 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -8556,6 +8556,9 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
add_node_error(irb->codegen, node,
buf_sprintf("inferred array size invalid here"));
return irb->codegen->invalid_instruction;
+ case NodeTypeVarFieldType:
+ return ir_lval_wrap(irb, scope,
+ ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_var), lval, result_loc);
}
zig_unreachable();
}
@@ -8715,6 +8718,9 @@ ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprVal
assert(val != nullptr);
assert(const_val->type->id == ZigTypeIdPointer);
ZigType *expected_type = const_val->type->data.pointer.child_type;
+ if (expected_type == codegen->builtin_types.entry_var) {
+ return val;
+ }
switch (type_has_one_possible_value(codegen, expected_type)) {
case OnePossibleValueInvalid:
return nullptr;
@@ -13502,6 +13508,9 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
}
if (ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) {
ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
+ if (child_type == ira->codegen->builtin_types.entry_var) {
+ child_type = pointee->type;
+ }
if (pointee->special != ConstValSpecialRuntime) {
IrInstruction *result = ir_const(ira, source_instruction, child_type);
@@ -19857,13 +19866,24 @@ static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIns
return ir_analyze_test_non_null(ira, &instruction->base, value);
}
+static ZigType *get_ptr_elem_type(CodeGen *g, IrInstruction *ptr) {
+ ir_assert(ptr->value.type->id == ZigTypeIdPointer, ptr);
+ ZigType *elem_type = ptr->value.type->data.pointer.child_type;
+ if (elem_type != g->builtin_types.entry_var)
+ return elem_type;
+
+ if (ir_resolve_lazy(g, ptr->source_node, &ptr->value))
+ return g->builtin_types.entry_invalid;
+
+ assert(value_is_comptime(&ptr->value));
+ ConstExprValue *pointee = const_ptr_pointee_unchecked(g, &ptr->value);
+ return pointee->type;
+}
+
static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr,
IrInstruction *base_ptr, bool safety_check_on, bool initializing)
{
- ZigType *ptr_type = base_ptr->value.type;
- assert(ptr_type->id == ZigTypeIdPointer);
-
- ZigType *type_entry = ptr_type->data.pointer.child_type;
+ ZigType *type_entry = get_ptr_elem_type(ira->codegen, base_ptr);
if (type_is_invalid(type_entry))
return ira->codegen->invalid_instruction;
@@ -19901,7 +19921,8 @@ static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstr
ZigType *child_type = type_entry->data.maybe.child_type;
ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type,
- ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0, false);
+ base_ptr->value.type->data.pointer.is_const, base_ptr->value.type->data.pointer.is_volatile,
+ PtrLenSingle, 0, 0, 0, false);
bool same_comptime_repr = types_have_same_zig_comptime_repr(ira->codegen, child_type, type_entry);
@@ -21627,20 +21648,15 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty
fields[5]->special = ConstValSpecialStatic;
fields[5]->type = ira->codegen->builtin_types.entry_bool;
fields[5]->data.x_bool = attrs_type->data.pointer.allow_zero;
- // sentinel: ?*const c_void
- ZigType *ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_c_void, true);
+ // sentinel: var
ensure_field_index(result->type, "sentinel", 6);
fields[6]->special = ConstValSpecialStatic;
- fields[6]->type = get_optional_type(ira->codegen, ptr_type);
- if (attrs_type->data.pointer.sentinel == nullptr) {
- fields[6]->data.x_optional = nullptr;
+ if (attrs_type->data.pointer.sentinel != nullptr) {
+ fields[6]->type = get_optional_type(ira->codegen, attrs_type->data.pointer.child_type);
+ fields[6]->data.x_optional = attrs_type->data.pointer.sentinel;
} else {
- ConstExprValue *ptr_val = create_const_vals(1);
- fields[6]->data.x_optional = ptr_val;
- ptr_val->data.x_ptr.special = ConstPtrSpecialRef;
- ptr_val->data.x_ptr.mut = ConstPtrMutComptimeConst;
- ptr_val->data.x_ptr.data.ref.pointee = create_const_vals(1);
- copy_const_val(ptr_val->data.x_ptr.data.ref.pointee, attrs_type->data.pointer.sentinel, false);
+ fields[6]->type = ira->codegen->builtin_types.entry_null;
+ fields[6]->data.x_optional = nullptr;
}
return result;
@@ -21762,23 +21778,10 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
fields[1]->special = ConstValSpecialStatic;
fields[1]->type = ira->codegen->builtin_types.entry_type;
fields[1]->data.x_type = type_entry->data.array.child_type;
- // sentinel: ?*const c_void
+ // sentinel: var
fields[2]->special = ConstValSpecialStatic;
- ZigType *ptr_type = get_pointer_to_type(ira->codegen,
- ira->codegen->builtin_types.entry_c_void, true);
- fields[2]->type = get_optional_type(ira->codegen, ptr_type);
- if (type_entry->data.array.sentinel == nullptr) {
- fields[2]->data.x_optional = nullptr;
- } else {
- ConstExprValue *ptr_val = create_const_vals(1);
- fields[2]->data.x_optional = ptr_val;
- ptr_val->type = ptr_type;
- ptr_val->data.x_ptr.special = ConstPtrSpecialRef;
- ptr_val->data.x_ptr.mut = ConstPtrMutComptimeConst;
- ptr_val->data.x_ptr.data.ref.pointee = create_const_vals(1);
- copy_const_val(ptr_val->data.x_ptr.data.ref.pointee, type_entry->data.array.sentinel, false);
- }
-
+ fields[2]->type = get_optional_type(ira->codegen, type_entry->data.array.child_type);
+ fields[2]->data.x_optional = type_entry->data.array.sentinel;
break;
}
case ZigTypeIdVector: {
@@ -22290,15 +22293,18 @@ static ConstExprValue *get_const_field(IrAnalyze *ira, ConstExprValue *struct_va
return struct_value->data.x_struct.fields[field_index];
}
-static ConstExprValue *get_const_field_variant(IrAnalyze *ira, ConstExprValue *struct_value,
- const char *name, size_t field_index)
+static Error get_const_field_sentinel(IrAnalyze *ira, IrInstruction *source_instr, ConstExprValue *struct_value,
+ const char *name, size_t field_index, ZigType *elem_type, ConstExprValue **result)
{
ConstExprValue *field_val = get_const_field(ira, struct_value, name, field_index);
- assert(field_val->type->id == ZigTypeIdOptional);
- ConstExprValue *opt_val = field_val->data.x_optional;
- if (opt_val == nullptr) return nullptr;
- assert(opt_val->type->id == ZigTypeIdPointer);
- return const_ptr_pointee_unchecked(ira->codegen, opt_val);
+ IrInstruction *field_inst = ir_const(ira, source_instr, field_val->type);
+ IrInstruction *casted_field_inst = ir_implicit_cast(ira, field_inst,
+ get_optional_type(ira->codegen, elem_type));
+ if (type_is_invalid(casted_field_inst->value.type))
+ return ErrorSemanticAnalyzeFail;
+
+ *result = casted_field_inst->value.data.x_optional;
+ return ErrorNone;
}
static bool get_const_field_bool(IrAnalyze *ira, ConstExprValue *struct_value, const char *name, size_t field_index)
@@ -22323,6 +22329,7 @@ static ZigType *get_const_field_meta_type(IrAnalyze *ira, ConstExprValue *struct
}
static ZigType *type_info_to_type(IrAnalyze *ira, IrInstruction *instruction, ZigTypeId tagTypeId, ConstExprValue *payload) {
+ Error err;
switch (tagTypeId) {
case ZigTypeIdInvalid:
zig_unreachable();
@@ -22364,8 +22371,16 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInstruction *instruction, Zi
assert(size_value->type == ir_type_info_get_type(ira, "Size", type_info_pointer_type));
BuiltinPtrSize size_enum_index = (BuiltinPtrSize)bigint_as_u32(&size_value->data.x_enum_tag);
PtrLen ptr_len = size_enum_index_to_ptr_len(size_enum_index);
+ ZigType *elem_type = get_const_field_meta_type(ira, payload, "child", 4);
+ ConstExprValue *sentinel;
+ if ((err = get_const_field_sentinel(ira, instruction, payload, "sentinel", 6,
+ elem_type, &sentinel)))
+ {
+ return nullptr;
+ }
+
ZigType *ptr_type = get_pointer_to_type_extra2(ira->codegen,
- get_const_field_meta_type(ira, payload, "child", 4),
+ elem_type,
get_const_field_bool(ira, payload, "is_const", 1),
get_const_field_bool(ira, payload, "is_volatile", 2),
ptr_len,
@@ -22373,22 +22388,26 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInstruction *instruction, Zi
0, // bit_offset_in_host
0, // host_int_bytes
get_const_field_bool(ira, payload, "is_allowzero", 5),
- VECTOR_INDEX_NONE,
- nullptr,
- get_const_field_variant(ira, payload, "sentinel", 6)
- );
+ VECTOR_INDEX_NONE, nullptr, sentinel);
if (size_enum_index != 2)
return ptr_type;
return get_slice_type(ira->codegen, ptr_type);
}
- case ZigTypeIdArray:
+ case ZigTypeIdArray: {
assert(payload->special == ConstValSpecialStatic);
assert(payload->type == ir_type_info_get_type(ira, "Array", nullptr));
+ ZigType *elem_type = get_const_field_meta_type(ira, payload, "child", 1);
+ ConstExprValue *sentinel;
+ if ((err = get_const_field_sentinel(ira, instruction, payload, "sentinel", 2,
+ elem_type, &sentinel)))
+ {
+ return nullptr;
+ }
return get_array_type(ira->codegen,
- get_const_field_meta_type(ira, payload, "child", 1),
+ elem_type,
bigint_as_u64(get_const_field_lit_int(ira, payload, "len", 0)),
- get_const_field_variant(ira, payload, "sentinel", 2)
- );
+ sentinel);
+ }
case ZigTypeIdComptimeFloat:
return ira->codegen->builtin_types.entry_num_lit_float;
case ZigTypeIdComptimeInt:
diff --git a/src/parser.cpp b/src/parser.cpp
index 61f3120d0e..429566ecc1 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -848,7 +848,12 @@ static AstNode *ast_parse_container_field(ParseContext *pc) {
AstNode *type_expr = nullptr;
if (eat_token_if(pc, TokenIdColon) != nullptr) {
- type_expr = ast_expect(pc, ast_parse_type_expr);
+ Token *var_tok = eat_token_if(pc, TokenIdKeywordVar);
+ if (var_tok != nullptr) {
+ type_expr = ast_create_node(pc, NodeTypeVarFieldType, var_tok);
+ } else {
+ type_expr = ast_expect(pc, ast_parse_type_expr);
+ }
}
AstNode *align_expr = ast_parse_byte_align(pc);
AstNode *expr = nullptr;
@@ -3163,6 +3168,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
visit_field(&node->data.suspend.block, visit, context);
break;
case NodeTypeEnumLiteral:
+ case NodeTypeVarFieldType:
break;
}
}
diff --git a/test/stage1/behavior/type.zig b/test/stage1/behavior/type.zig
index e3ce4d0904..f083359d1d 100644
--- a/test/stage1/behavior/type.zig
+++ b/test/stage1/behavior/type.zig
@@ -112,7 +112,7 @@ test "Type.Array" {
.Array = TypeInfo.Array{
.len = 2,
.child = u32,
- .sentinel = &0,
+ .sentinel = 0,
},
}));
testTypes([_]type{ [1]u8, [30]usize, [7]bool });
diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig
index dcd4da3d0f..598bbca6be 100644
--- a/test/stage1/behavior/type_info.zig
+++ b/test/stage1/behavior/type_info.zig
@@ -46,7 +46,7 @@ fn testPointer() void {
expect(u32_ptr_info.Pointer.is_volatile == false);
expect(u32_ptr_info.Pointer.alignment == @alignOf(u32));
expect(u32_ptr_info.Pointer.child == u32);
- expect(u32_ptr_info.Pointer.is_null_terminated == false);
+ expect(u32_ptr_info.Pointer.sentinel == null);
}
test "type info: unknown length pointer type info" {
@@ -60,7 +60,7 @@ fn testUnknownLenPtr() void {
expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
expect(u32_ptr_info.Pointer.is_const == true);
expect(u32_ptr_info.Pointer.is_volatile == true);
- expect(u32_ptr_info.Pointer.is_null_terminated == false);
+ expect(u32_ptr_info.Pointer.sentinel == null);
expect(u32_ptr_info.Pointer.alignment == @alignOf(f64));
expect(u32_ptr_info.Pointer.child == f64);
}
@@ -76,7 +76,7 @@ fn testNullTerminatedPtr() void {
expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
expect(ptr_info.Pointer.is_const == false);
expect(ptr_info.Pointer.is_volatile == false);
- expect(ptr_info.Pointer.is_null_terminated == true);
+ expect(ptr_info.Pointer.sentinel.? == 0);
expect(@typeInfo([:0]u8).Pointer.sentinel != null);
expect(@typeInfo([10:0]u8).Array.sentinel != null);
--
cgit v1.2.3
From 4c7b52503b064b8be2f2afd4152311aff1941d92 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sun, 24 Nov 2019 02:14:21 -0500
Subject: all tests passing
---
doc/docgen.zig | 2 --
doc/langref.html.in | 40 ++++++++++++----------------------------
src/analyze.cpp | 18 +-----------------
src/codegen.cpp | 5 +++--
src/ir.cpp | 19 +++++++++++++++----
test/compile_errors.zig | 17 +++++++++--------
test/stage1/behavior/slice.zig | 13 +++++++++++++
7 files changed, 53 insertions(+), 61 deletions(-)
(limited to 'src/analyze.cpp')
diff --git a/doc/docgen.zig b/doc/docgen.zig
index 502ffda784..bf53bed717 100644
--- a/doc/docgen.zig
+++ b/doc/docgen.zig
@@ -954,8 +954,6 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
.AngleBracketAngleBracketRight,
.AngleBracketAngleBracketRightEqual,
.Tilde,
- .BracketStarBracket,
- .BracketStarCBracket,
=> try writeEscaped(out, src[token.start..token.end]),
.Invalid, .Invalid_ampersands => return parseError(
diff --git a/doc/langref.html.in b/doc/langref.html.in
index 0084e7e199..be6f09a93e 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -563,7 +563,7 @@ const mem = @import("std").mem;
test "string literals" {
const bytes = "hello";
- assert(@typeOf(bytes) == *const [5]null u8);
+ assert(@typeOf(bytes) == *const [5:0]u8);
assert(bytes.len == 5);
assert(bytes[1] == 'e');
assert(bytes[5] == 0);
@@ -1795,7 +1795,7 @@ test "null terminated array" {
assert(@typeOf(array) == [4:0]u8);
assert(array.len == 4);
- assert(slice[4] == 0);
+ assert(array[4] == 0);
}
{#code_end#}
{#see_also|Sentinel-Terminated Pointers|Sentinel-Terminated Slices#}
@@ -4863,7 +4863,7 @@ const assert = std.debug.assert;
const mem = std.mem;
test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
- const window_name = [1][*]const u8{c"window name"};
+ const window_name = [1][*]const u8{"window name"};
const x: [*]const ?[*]const u8 = &window_name;
assert(mem.eql(u8, std.mem.toSliceConst(u8, x[0].?), "window name"));
}
@@ -4905,7 +4905,7 @@ test "float widening" {
{#code_end#}
{#header_close#}
{#header_open|Type Coercion: Arrays and Pointers#}
- {#code_begin|test#}
+ {#code_begin|test|coerce_arrays_and_ptrs#}
const std = @import("std");
const assert = std.debug.assert;
@@ -4944,7 +4944,7 @@ test "[N]T to ?[]const T" {
// In this cast, the array length becomes the slice length.
test "*[N]T to []T" {
- var buf: [5]u8 = "hello";
+ var buf: [5]u8 = "hello".*;
const x: []u8 = &buf;
assert(std.mem.eql(u8, x, "hello"));
@@ -4956,7 +4956,7 @@ test "*[N]T to []T" {
// Single-item pointers to arrays can be coerced to
// unknown length pointers.
test "*[N]T to [*]T" {
- var buf: [5]u8 = "hello";
+ var buf: [5]u8 = "hello".*;
const x: [*]u8 = &buf;
assert(x[4] == 'o');
// x[5] would be an uncaught out of bounds pointer dereference!
@@ -4964,7 +4964,7 @@ test "*[N]T to [*]T" {
// Likewise, it works when the destination type is an optional.
test "*[N]T to ?[*]T" {
- var buf: [5]u8 = "hello";
+ var buf: [5]u8 = "hello".*;
const x: ?[*]u8 = &buf;
assert(x.?[4] == 'o');
}
@@ -5135,7 +5135,7 @@ test "coercion of zero bit types" {
This kind of type resolution chooses a type that all peer types can coerce into. Here are
some examples:
- {#code_begin|test#}
+ {#code_begin|test|peer_type_resolution#}
const std = @import("std");
const assert = std.debug.assert;
const mem = std.mem;
@@ -5202,13 +5202,13 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {
}
test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" {
{
- var data = "hi";
+ var data = "hi".*;
const slice = data[0..];
assert((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0);
assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
}
comptime {
- var data = "hi";
+ var data = "hi".*;
const slice = data[0..];
assert((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0);
assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
@@ -8673,7 +8673,7 @@ pub fn main() void {
At compile-time:
{#code_begin|test_err|index 5 outside array of size 5#}
comptime {
- const array = "hello";
+ const array: [5]u8 = "hello".*;
const garbage = array[5];
}
{#code_end#}
@@ -9649,22 +9649,6 @@ test "assert in release fast mode" {
{#see_also|Primitive Types#}
{#header_close#}
- {#header_open|C String Literals#}
- {#code_begin|exe#}
- {#link_libc#}
-extern fn puts([*]const u8) void;
-
-pub fn main() void {
- puts(c"this has a null terminator");
- puts(
- c\\and so
- c\\does this
- c\\multiline C string literal
- );
-}
- {#code_end#}
- {#see_also|String Literals and Character Literals#}
- {#header_close#}
{#header_open|Import from C Header File#}
@@ -9679,7 +9663,7 @@ const c = @cImport({
@cInclude("stdio.h");
});
pub fn main() void {
- _ = c.printf(c"hello\n");
+ _ = c.printf("hello\n");
}
{#code_end#}
diff --git a/src/analyze.cpp b/src/analyze.cpp
index d065f85c67..c41f5b652e 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -496,7 +496,7 @@ static void append_ptr_type_attrs(Buf *type_name, ZigType *ptr_type) {
} else if (ptr_type->data.pointer.vector_index != VECTOR_INDEX_NONE) {
buf_appendf(type_name, ":%" PRIu32, ptr_type->data.pointer.vector_index);
}
- buf_appendf(type_name, ")");
+ buf_appendf(type_name, ") ");
}
buf_appendf(type_name, "%s%s%s", const_str, volatile_str, allow_zero_str);
if (ptr_type->data.pointer.inferred_struct_field != nullptr) {
@@ -861,22 +861,6 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
entry->data.structure.fields[slice_len_index]->gen_index = 0;
}
- ZigType *child_type = ptr_type->data.pointer.child_type;
- if (ptr_type->data.pointer.is_const || ptr_type->data.pointer.is_volatile ||
- ptr_type->data.pointer.explicit_alignment != 0 || ptr_type->data.pointer.allow_zero)
- {
- ZigType *peer_ptr_type = get_pointer_to_type_extra(g, child_type, false, false,
- PtrLenUnknown, 0, 0, 0, false);
- ZigType *peer_slice_type = get_slice_type(g, peer_ptr_type);
-
- entry->size_in_bits = peer_slice_type->size_in_bits;
- entry->abi_size = peer_slice_type->abi_size;
- entry->abi_align = peer_slice_type->abi_align;
-
- *parent_pointer = entry;
- return entry;
- }
-
if (type_has_bits(ptr_type)) {
entry->size_in_bits = ptr_type->size_in_bits + g->builtin_types.entry_usize->size_in_bits;
entry->abi_size = ptr_type->abi_size + g->builtin_types.entry_usize->abi_size;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 9a269ec41f..3e2744efc6 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -3752,7 +3752,7 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type);
assert(array_type->data.structure.is_slice);
- ZigType *ptr_type = instruction->base.value.type;
+ ZigType *ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry;
if (!type_has_bits(ptr_type)) {
if (safety_check_on) {
assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMIntegerTypeKind);
@@ -3769,7 +3769,8 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
assert(len_index != SIZE_MAX);
LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, (unsigned)len_index, "");
LLVMValueRef len = gen_load_untyped(g, len_ptr, 0, false, "");
- add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, len);
+ LLVMIntPredicate upper_op = (ptr_type->data.pointer.sentinel != nullptr) ? LLVMIntULE : LLVMIntULT;
+ add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, upper_op, len);
}
size_t ptr_index = array_type->data.structure.fields[slice_ptr_index]->gen_index;
diff --git a/src/ir.cpp b/src/ir.cpp
index df76d3f963..5e051c9781 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -18244,13 +18244,16 @@ static IrInstruction *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstructi
static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align) {
assert(ptr_type->id == ZigTypeIdPointer);
- return get_pointer_to_type_extra(g,
+ return get_pointer_to_type_extra2(g,
ptr_type->data.pointer.child_type,
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
ptr_type->data.pointer.ptr_len,
new_align,
ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes,
- ptr_type->data.pointer.allow_zero);
+ ptr_type->data.pointer.allow_zero,
+ ptr_type->data.pointer.vector_index,
+ ptr_type->data.pointer.inferred_struct_field,
+ ptr_type->data.pointer.sentinel);
}
static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align) {
@@ -18595,8 +18598,11 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
ConstExprValue *len_field = array_ptr_val->data.x_struct.fields[slice_len_index];
IrInstruction *result = ir_const(ira, &elem_ptr_instruction->base, return_type);
ConstExprValue *out_val = &result->value;
+ ZigType *slice_ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry;
uint64_t slice_len = bigint_as_u64(&len_field->data.x_bigint);
- if (index >= slice_len) {
+ uint64_t full_slice_len = slice_len +
+ ((slice_ptr_type->data.pointer.sentinel != nullptr) ? 1 : 0);
+ if (index >= full_slice_len) {
ir_add_error_node(ira, elem_ptr_instruction->base.source_node,
buf_sprintf("index %" ZIG_PRI_u64 " outside slice of size %" ZIG_PRI_u64,
index, slice_len));
@@ -18615,8 +18621,13 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
{
size_t offset = ptr_field->data.x_ptr.data.base_array.elem_index;
uint64_t new_index = offset + index;
- ir_assert(new_index < ptr_field->data.x_ptr.data.base_array.array_val->type->data.array.len,
+ if (ptr_field->data.x_ptr.data.base_array.array_val->data.x_array.special !=
+ ConstArraySpecialBuf)
+ {
+ ir_assert(new_index <
+ ptr_field->data.x_ptr.data.base_array.array_val->type->data.array.len,
&elem_ptr_instruction->base);
+ }
out_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
out_val->data.x_ptr.data.base_array.array_val =
ptr_field->data.x_ptr.data.base_array.array_val;
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 20122b681a..d92808858a 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -70,14 +70,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
cases.add(
"disallow coercion from non-null-terminated pointer to null-terminated pointer",
- \\extern fn puts(s: [*]null const u8) c_int;
+ \\extern fn puts(s: [*:0]const u8) c_int;
\\pub fn main() void {
\\ const no_zero_array = [_]u8{'h', 'e', 'l', 'l', 'o'};
\\ const no_zero_ptr: [*]const u8 = &no_zero_array;
\\ _ = puts(no_zero_ptr);
\\}
,
- "tmp.zig:5:14: error: expected type '[*]null const u8', found '[*]const u8'",
+ "tmp.zig:5:14: error: expected type '[*:0]const u8', found '[*]const u8'",
);
cases.add(
@@ -784,7 +784,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ strValue = strValue orelse "";
\\}
,
- "tmp.zig:3:32: error: expected type '[*c]u8', found '*const [0]null u8'",
+ "tmp.zig:3:32: error: expected type '[*c]u8', found '*const [0:0]u8'",
"tmp.zig:3:32: note: cast discards const qualifier",
);
@@ -2442,12 +2442,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
);
cases.add(
- "var not allowed in structs",
+ "var makes structs required to be comptime known",
\\export fn entry() void {
- \\ var s = (struct{v: var}){.v=@as(i32, 10)};
+ \\ const S = struct{v: var};
+ \\ var s = S{.v=@as(i32, 10)};
\\}
,
- "tmp.zig:2:23: error: invalid token: 'var'",
+ "tmp.zig:3:4: error: variable of type 'S' must be const or comptime",
);
cases.add(
@@ -3357,7 +3358,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return a;
\\}
,
- "tmp.zig:3:12: error: expected type 'i32', found '*const [1]null u8'",
+ "tmp.zig:3:12: error: expected type 'i32', found '*const [1:0]u8'",
);
cases.add(
@@ -6212,7 +6213,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\pub extern fn foo(format: *const u8, ...) void;
,
- "tmp.zig:2:16: error: expected type '*const u8', found '[5]null u8'",
+ "tmp.zig:2:16: error: expected type '*const u8', found '[5:0]u8'",
);
cases.add(
diff --git a/test/stage1/behavior/slice.zig b/test/stage1/behavior/slice.zig
index ea0a6fe9f4..3c394e39a1 100644
--- a/test/stage1/behavior/slice.zig
+++ b/test/stage1/behavior/slice.zig
@@ -65,3 +65,16 @@ test "slice type with custom alignment" {
slice[1].anything = 42;
expect(array[1].anything == 42);
}
+
+test "access len index of sentinel-terminated slice" {
+ const S = struct {
+ fn doTheTest() void {
+ var slice: [:0]const u8 = "hello";
+
+ expect(slice.len == 5);
+ expect(slice[5] == 0);
+ }
+ };
+ S.doTheTest();
+ comptime S.doTheTest();
+}
--
cgit v1.2.3
From 15d415e10b81a66fa3b887fb2a0c20bbcd614d94 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sun, 24 Nov 2019 21:12:01 -0500
Subject: make std.mem.toSlice use null terminated pointers
and fix the fallout
---
lib/std/buffer.zig | 9 ++------
lib/std/c.zig | 2 +-
lib/std/fs.zig | 2 +-
lib/std/mem.zig | 6 +++---
lib/std/net.zig | 4 ++--
lib/std/os.zig | 31 ++++++++++++++-------------
lib/std/os/linux/vdso.zig | 6 ++++--
lib/std/special/start.zig | 12 +++++------
src-self-hosted/clang.zig | 6 +++---
src-self-hosted/compilation.zig | 6 +++---
src-self-hosted/llvm.zig | 44 +++++++++++++++++++--------------------
src-self-hosted/stage1.zig | 4 ++--
src-self-hosted/translate_c.zig | 2 +-
src-self-hosted/util.zig | 6 +++---
src/analyze.cpp | 6 ++++--
test/stage1/behavior/cast.zig | 2 +-
test/stage1/behavior/pointers.zig | 3 ++-
17 files changed, 76 insertions(+), 75 deletions(-)
(limited to 'src/analyze.cpp')
diff --git a/lib/std/buffer.zig b/lib/std/buffer.zig
index 24bd23fa74..37414d64d2 100644
--- a/lib/std/buffer.zig
+++ b/lib/std/buffer.zig
@@ -72,11 +72,11 @@ pub const Buffer = struct {
self.list.deinit();
}
- pub fn toSlice(self: Buffer) []u8 {
+ pub fn toSlice(self: Buffer) [:0]u8 {
return self.list.toSlice()[0..self.len()];
}
- pub fn toSliceConst(self: Buffer) []const u8 {
+ pub fn toSliceConst(self: Buffer) [:0]const u8 {
return self.list.toSliceConst()[0..self.len()];
}
@@ -131,11 +131,6 @@ pub const Buffer = struct {
try self.resize(m.len);
mem.copy(u8, self.list.toSlice(), m);
}
-
- /// For passing to C functions.
- pub fn ptr(self: Buffer) [*]u8 {
- return self.list.items.ptr;
- }
};
test "simple Buffer" {
diff --git a/lib/std/c.zig b/lib/std/c.zig
index fac13efc69..33061b6620 100644
--- a/lib/std/c.zig
+++ b/lib/std/c.zig
@@ -110,7 +110,7 @@ pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;
pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;
pub extern "c" fn rmdir(path: [*]const u8) c_int;
-pub extern "c" fn getenv(name: [*]const u8) ?[*]u8;
+pub extern "c" fn getenv(name: [*:0]const u8) ?[*:0]u8;
pub extern "c" fn sysctl(name: [*]const c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int;
diff --git a/lib/std/fs.zig b/lib/std/fs.zig
index 0b9c6559d7..d5a7930970 100644
--- a/lib/std/fs.zig
+++ b/lib/std/fs.zig
@@ -533,7 +533,7 @@ pub const Dir = struct {
const next_index = self.index + linux_entry.reclen();
self.index = next_index;
- const name = mem.toSlice(u8, @ptrCast([*]u8, &linux_entry.d_name));
+ const name = mem.toSlice(u8, @ptrCast([*:0]u8, &linux_entry.d_name));
// skip . and .. entries
if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
diff --git a/lib/std/mem.zig b/lib/std/mem.zig
index f790dd683b..412bf9b649 100644
--- a/lib/std/mem.zig
+++ b/lib/std/mem.zig
@@ -356,17 +356,17 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
return true;
}
-pub fn len(comptime T: type, ptr: [*]const T) usize {
+pub fn len(comptime T: type, ptr: [*:0]const T) usize {
var count: usize = 0;
while (ptr[count] != 0) : (count += 1) {}
return count;
}
-pub fn toSliceConst(comptime T: type, ptr: [*]const T) []const T {
+pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T {
return ptr[0..len(T, ptr)];
}
-pub fn toSlice(comptime T: type, ptr: [*]T) []T {
+pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T {
return ptr[0..len(T, ptr)];
}
diff --git a/lib/std/net.zig b/lib/std/net.zig
index 5e194d73ca..9a602c0105 100644
--- a/lib/std/net.zig
+++ b/lib/std/net.zig
@@ -360,7 +360,7 @@ pub const Address = extern union {
unreachable;
}
- const path_len = std.mem.len(u8, &self.un.path);
+ const path_len = std.mem.len(u8, @ptrCast([*:0]const u8, &self.un.path));
return @intCast(os.socklen_t, @sizeOf(os.sockaddr_un) - self.un.path.len + path_len);
},
else => unreachable,
@@ -1271,7 +1271,7 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8)
var tmp: [256]u8 = undefined;
// Returns len of compressed name. strlen to get canon name.
_ = try os.dn_expand(packet, data, &tmp);
- const canon_name = mem.toSliceConst(u8, &tmp);
+ const canon_name = mem.toSliceConst(u8, @ptrCast([*:0]const u8, &tmp));
if (isValidHostName(canon_name)) {
try ctx.canon.replaceContents(canon_name);
}
diff --git a/lib/std/os.zig b/lib/std/os.zig
index 28a88beb04..9035d8ecbd 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -66,12 +66,12 @@ pub const system = if (builtin.link_libc) std.c else switch (builtin.os) {
pub usingnamespace @import("os/bits.zig");
/// See also `getenv`. Populated by startup code before main().
-pub var environ: [][*]u8 = undefined;
+pub var environ: [][*:0]u8 = undefined;
/// Populated by startup code before main().
/// Not available on Windows. See `std.process.args`
/// for obtaining the process arguments.
-pub var argv: [][*]u8 = undefined;
+pub var argv: [][*:0]u8 = undefined;
/// To obtain errno, call this function with the return value of the
/// system function call. For some systems this will obtain the value directly
@@ -784,7 +784,7 @@ pub fn execveC(path: [*]const u8, child_argv: [*]const ?[*]const u8, envp: [*]co
/// matching the syscall API on all targets. This removes the need for an allocator.
/// This function also uses the PATH environment variable to get the full path to the executable.
/// If `file` is an absolute path, this is the same as `execveC`.
-pub fn execvpeC(file: [*]const u8, child_argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) ExecveError {
+pub fn execvpeC(file: [*:0]const u8, child_argv: [*]const ?[*:0]const u8, envp: [*]const ?[*:0]const u8) ExecveError {
const file_slice = mem.toSliceConst(u8, file);
if (mem.indexOfScalar(u8, file_slice, '/') != null) return execveC(file, child_argv, envp);
@@ -820,8 +820,8 @@ pub fn execvpe(
argv_slice: []const []const u8,
env_map: *const std.BufMap,
) (ExecveError || error{OutOfMemory}) {
- const argv_buf = try allocator.alloc(?[*]u8, argv_slice.len + 1);
- mem.set(?[*]u8, argv_buf, null);
+ const argv_buf = try allocator.alloc(?[*:0]u8, argv_slice.len + 1);
+ mem.set(?[*:0]u8, argv_buf, null);
defer {
for (argv_buf) |arg| {
const arg_buf = if (arg) |ptr| mem.toSlice(u8, ptr) else break;
@@ -834,7 +834,8 @@ pub fn execvpe(
@memcpy(arg_buf.ptr, arg.ptr, arg.len);
arg_buf[arg.len] = 0;
- argv_buf[i] = arg_buf.ptr;
+ // TODO avoid @ptrCast using slice syntax with https://github.com/ziglang/zig/issues/3731
+ argv_buf[i] = @ptrCast([*:0]u8, arg_buf.ptr);
}
argv_buf[argv_slice.len] = null;
@@ -844,10 +845,10 @@ pub fn execvpe(
return execvpeC(argv_buf.ptr[0].?, argv_buf.ptr, envp_buf.ptr);
}
-pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std.BufMap) ![]?[*]u8 {
+pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std.BufMap) ![]?[*:0]u8 {
const envp_count = env_map.count();
- const envp_buf = try allocator.alloc(?[*]u8, envp_count + 1);
- mem.set(?[*]u8, envp_buf, null);
+ const envp_buf = try allocator.alloc(?[*:0]u8, envp_count + 1);
+ mem.set(?[*:0]u8, envp_buf, null);
errdefer freeNullDelimitedEnvMap(allocator, envp_buf);
{
var it = env_map.iterator();
@@ -859,7 +860,8 @@ pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std.
@memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len);
env_buf[env_buf.len - 1] = 0;
- envp_buf[i] = env_buf.ptr;
+ // TODO avoid @ptrCast using slice syntax with https://github.com/ziglang/zig/issues/3731
+ envp_buf[i] = @ptrCast([*:0]u8, env_buf.ptr);
}
assert(i == envp_count);
}
@@ -867,7 +869,7 @@ pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std.
return envp_buf;
}
-pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*]u8) void {
+pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8) void {
for (envp_buf) |env| {
const env_buf = if (env) |ptr| ptr[0 .. mem.len(u8, ptr) + 1] else break;
allocator.free(env_buf);
@@ -896,8 +898,7 @@ pub fn getenv(key: []const u8) ?[]const u8 {
/// Get an environment variable with a null-terminated name.
/// See also `getenv`.
-/// TODO https://github.com/ziglang/zig/issues/265
-pub fn getenvC(key: [*]const u8) ?[]const u8 {
+pub fn getenvC(key: [*:0]const u8) ?[]const u8 {
if (builtin.link_libc) {
const value = system.getenv(key) orelse return null;
return mem.toSliceConst(u8, value);
@@ -922,7 +923,7 @@ pub fn getcwd(out_buffer: []u8) GetCwdError![]u8 {
break :blk errno(system.getcwd(out_buffer.ptr, out_buffer.len));
};
switch (err) {
- 0 => return mem.toSlice(u8, out_buffer.ptr),
+ 0 => return mem.toSlice(u8, @ptrCast([*:0]u8, out_buffer.ptr)),
EFAULT => unreachable,
EINVAL => unreachable,
ENOENT => return error.CurrentWorkingDirectoryUnlinked,
@@ -2865,7 +2866,7 @@ pub fn gethostname(name_buffer: *[HOST_NAME_MAX]u8) GetHostNameError![]u8 {
var uts: utsname = undefined;
switch (errno(system.uname(&uts))) {
0 => {
- const hostname = mem.toSlice(u8, &uts.nodename);
+ const hostname = mem.toSlice(u8, @ptrCast([*:0]u8, &uts.nodename));
mem.copy(u8, name_buffer, hostname);
return name_buffer[0..hostname.len];
},
diff --git a/lib/std/os/linux/vdso.zig b/lib/std/os/linux/vdso.zig
index d3e00b8673..868eb26c69 100644
--- a/lib/std/os/linux/vdso.zig
+++ b/lib/std/os/linux/vdso.zig
@@ -65,7 +65,8 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
if (0 == (@as(u32, 1) << @intCast(u5, syms[i].st_info & 0xf) & OK_TYPES)) continue;
if (0 == (@as(u32, 1) << @intCast(u5, syms[i].st_info >> 4) & OK_BINDS)) continue;
if (0 == syms[i].st_shndx) continue;
- if (!mem.eql(u8, name, mem.toSliceConst(u8, strings + syms[i].st_name))) continue;
+ const sym_name = @ptrCast([*:0]const u8, strings + syms[i].st_name);
+ if (!mem.eql(u8, name, mem.toSliceConst(u8, sym_name))) continue;
if (maybe_versym) |versym| {
if (!checkver(maybe_verdef.?, versym[i], vername, strings))
continue;
@@ -87,5 +88,6 @@ fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [
def = @intToPtr(*elf.Verdef, @ptrToInt(def) + def.vd_next);
}
const aux = @intToPtr(*elf.Verdaux, @ptrToInt(def) + def.vd_aux);
- return mem.eql(u8, vername, mem.toSliceConst(u8, strings + aux.vda_name));
+ const vda_name = @ptrCast([*:0]const u8, strings + aux.vda_name);
+ return mem.eql(u8, vername, mem.toSliceConst(u8, vda_name));
}
diff --git a/lib/std/special/start.zig b/lib/std/special/start.zig
index c56d50d7c4..6d99618d2e 100644
--- a/lib/std/special/start.zig
+++ b/lib/std/special/start.zig
@@ -123,12 +123,12 @@ fn posixCallMainAndExit() noreturn {
@setAlignStack(16);
}
const argc = starting_stack_ptr[0];
- const argv = @ptrCast([*][*]u8, starting_stack_ptr + 1);
+ const argv = @ptrCast([*][*:0]u8, starting_stack_ptr + 1);
- const envp_optional = @ptrCast([*]?[*]u8, argv + argc + 1);
+ const envp_optional = @ptrCast([*:null]?[*:0]u8, argv + argc + 1);
var envp_count: usize = 0;
while (envp_optional[envp_count]) |_| : (envp_count += 1) {}
- const envp = @ptrCast([*][*]u8, envp_optional)[0..envp_count];
+ const envp = @ptrCast([*][*:0]u8, envp_optional)[0..envp_count];
if (builtin.os == .linux) {
// Find the beginning of the auxiliary vector
@@ -168,7 +168,7 @@ fn posixCallMainAndExit() noreturn {
std.os.exit(@inlineCall(callMainWithArgs, argc, argv, envp));
}
-fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 {
+fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 {
std.os.argv = argv[0..argc];
std.os.environ = envp;
@@ -177,10 +177,10 @@ fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 {
return initEventLoopAndCallMain();
}
-extern fn main(c_argc: i32, c_argv: [*][*]u8, c_envp: [*]?[*]u8) i32 {
+extern fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) i32 {
var env_count: usize = 0;
while (c_envp[env_count] != null) : (env_count += 1) {}
- const envp = @ptrCast([*][*]u8, c_envp)[0..env_count];
+ const envp = @ptrCast([*][*:0]u8, c_envp)[0..env_count];
return @inlineCall(callMainWithArgs, @intCast(usize, c_argc), c_argv, envp);
}
diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig
index 8f3e539162..31907ff266 100644
--- a/src-self-hosted/clang.zig
+++ b/src-self-hosted/clang.zig
@@ -708,7 +708,7 @@ pub const ZigClangStringLiteral_StringKind = extern enum {
};
pub extern fn ZigClangSourceManager_getSpellingLoc(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) struct_ZigClangSourceLocation;
-pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*]const u8;
+pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*:0]const u8;
pub extern fn ZigClangSourceManager_getSpellingLineNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint;
pub extern fn ZigClangSourceManager_getSpellingColumnNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint;
pub extern fn ZigClangSourceManager_getCharacterData(self: ?*const struct_ZigClangSourceManager, SL: struct_ZigClangSourceLocation) [*c]const u8;
@@ -746,7 +746,7 @@ pub extern fn ZigClangQualType_isRestrictQualified(self: struct_ZigClangQualType
pub extern fn ZigClangType_getTypeClass(self: ?*const struct_ZigClangType) ZigClangTypeClass;
pub extern fn ZigClangType_getPointeeType(self: ?*const struct_ZigClangType) struct_ZigClangQualType;
pub extern fn ZigClangType_isVoidType(self: ?*const struct_ZigClangType) bool;
-pub extern fn ZigClangType_getTypeClassName(self: *const struct_ZigClangType) [*]const u8;
+pub extern fn ZigClangType_getTypeClassName(self: *const struct_ZigClangType) [*:0]const u8;
pub extern fn ZigClangStmt_getBeginLoc(self: *const struct_ZigClangStmt) struct_ZigClangSourceLocation;
pub extern fn ZigClangStmt_getStmtClass(self: ?*const struct_ZigClangStmt) ZigClangStmtClass;
pub extern fn ZigClangStmt_classof_Expr(self: ?*const struct_ZigClangStmt) bool;
@@ -904,7 +904,7 @@ pub extern fn ZigClangLoadFromCommandLine(
) ?*ZigClangASTUnit;
pub extern fn ZigClangDecl_getKind(decl: *const ZigClangDecl) ZigClangDeclKind;
-pub extern fn ZigClangDecl_getDeclKindName(decl: *const struct_ZigClangDecl) [*]const u8;
+pub extern fn ZigClangDecl_getDeclKindName(decl: *const struct_ZigClangDecl) [*:0]const u8;
pub const ZigClangCompoundStmt_const_body_iterator = [*c]const *struct_ZigClangStmt;
diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig
index 1d4ed757d9..2f0de0c521 100644
--- a/src-self-hosted/compilation.zig
+++ b/src-self-hosted/compilation.zig
@@ -490,8 +490,8 @@ pub const Compilation = struct {
// LLVM creates invalid binaries on Windows sometimes.
// See https://github.com/ziglang/zig/issues/508
// As a workaround we do not use target native features on Windows.
- var target_specific_cpu_args: ?[*]u8 = null;
- var target_specific_cpu_features: ?[*]u8 = null;
+ var target_specific_cpu_args: ?[*:0]u8 = null;
+ var target_specific_cpu_features: ?[*:0]u8 = null;
defer llvm.DisposeMessage(target_specific_cpu_args);
defer llvm.DisposeMessage(target_specific_cpu_features);
if (target == Target.Native and !target.isWindows()) {
@@ -501,7 +501,7 @@ pub const Compilation = struct {
comp.target_machine = llvm.CreateTargetMachine(
comp.llvm_target,
- comp.llvm_triple.ptr(),
+ comp.llvm_triple.toSliceConst(),
target_specific_cpu_args orelse "",
target_specific_cpu_features orelse "",
opt_level,
diff --git a/src-self-hosted/llvm.zig b/src-self-hosted/llvm.zig
index c8eba2cd2d..af42adb97d 100644
--- a/src-self-hosted/llvm.zig
+++ b/src-self-hosted/llvm.zig
@@ -83,16 +83,16 @@ pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext;
pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext;
pub const AddGlobal = LLVMAddGlobal;
-extern fn LLVMAddGlobal(M: *Module, Ty: *Type, Name: [*]const u8) ?*Value;
+extern fn LLVMAddGlobal(M: *Module, Ty: *Type, Name: [*:0]const u8) ?*Value;
pub const ConstStringInContext = LLVMConstStringInContext;
-extern fn LLVMConstStringInContext(C: *Context, Str: [*]const u8, Length: c_uint, DontNullTerminate: Bool) ?*Value;
+extern fn LLVMConstStringInContext(C: *Context, Str: [*:0]const u8, Length: c_uint, DontNullTerminate: Bool) ?*Value;
pub const ConstInt = LLVMConstInt;
extern fn LLVMConstInt(IntTy: *Type, N: c_ulonglong, SignExtend: Bool) ?*Value;
pub const BuildLoad = LLVMBuildLoad;
-extern fn LLVMBuildLoad(arg0: *Builder, PointerVal: *Value, Name: [*]const u8) ?*Value;
+extern fn LLVMBuildLoad(arg0: *Builder, PointerVal: *Value, Name: [*:0]const u8) ?*Value;
pub const ConstNull = LLVMConstNull;
extern fn LLVMConstNull(Ty: *Type) ?*Value;
@@ -110,24 +110,24 @@ pub const CreateEnumAttribute = LLVMCreateEnumAttribute;
extern fn LLVMCreateEnumAttribute(C: *Context, KindID: c_uint, Val: u64) ?*Attribute;
pub const AddFunction = LLVMAddFunction;
-extern fn LLVMAddFunction(M: *Module, Name: [*]const u8, FunctionTy: *Type) ?*Value;
+extern fn LLVMAddFunction(M: *Module, Name: [*:0]const u8, FunctionTy: *Type) ?*Value;
pub const CreateCompileUnit = ZigLLVMCreateCompileUnit;
extern fn ZigLLVMCreateCompileUnit(
dibuilder: *DIBuilder,
lang: c_uint,
difile: *DIFile,
- producer: [*]const u8,
+ producer: [*:0]const u8,
is_optimized: bool,
- flags: [*]const u8,
+ flags: [*:0]const u8,
runtime_version: c_uint,
- split_name: [*]const u8,
+ split_name: [*:0]const u8,
dwo_id: u64,
emit_debug_info: bool,
) ?*DICompileUnit;
pub const CreateFile = ZigLLVMCreateFile;
-extern fn ZigLLVMCreateFile(dibuilder: *DIBuilder, filename: [*]const u8, directory: [*]const u8) ?*DIFile;
+extern fn ZigLLVMCreateFile(dibuilder: *DIBuilder, filename: [*:0]const u8, directory: [*:0]const u8) ?*DIFile;
pub const ArrayType = LLVMArrayType;
extern fn LLVMArrayType(ElementType: *Type, ElementCount: c_uint) ?*Type;
@@ -145,7 +145,7 @@ pub const IntTypeInContext = LLVMIntTypeInContext;
extern fn LLVMIntTypeInContext(C: *Context, NumBits: c_uint) ?*Type;
pub const ModuleCreateWithNameInContext = LLVMModuleCreateWithNameInContext;
-extern fn LLVMModuleCreateWithNameInContext(ModuleID: [*]const u8, C: *Context) ?*Module;
+extern fn LLVMModuleCreateWithNameInContext(ModuleID: [*:0]const u8, C: *Context) ?*Module;
pub const VoidTypeInContext = LLVMVoidTypeInContext;
extern fn LLVMVoidTypeInContext(C: *Context) ?*Type;
@@ -157,7 +157,7 @@ pub const ContextDispose = LLVMContextDispose;
extern fn LLVMContextDispose(C: *Context) void;
pub const CopyStringRepOfTargetData = LLVMCopyStringRepOfTargetData;
-extern fn LLVMCopyStringRepOfTargetData(TD: *TargetData) ?[*]u8;
+extern fn LLVMCopyStringRepOfTargetData(TD: *TargetData) ?[*:0]u8;
pub const CreateTargetDataLayout = LLVMCreateTargetDataLayout;
extern fn LLVMCreateTargetDataLayout(T: *TargetMachine) ?*TargetData;
@@ -165,9 +165,9 @@ extern fn LLVMCreateTargetDataLayout(T: *TargetMachine) ?*TargetData;
pub const CreateTargetMachine = ZigLLVMCreateTargetMachine;
extern fn ZigLLVMCreateTargetMachine(
T: *Target,
- Triple: [*]const u8,
- CPU: [*]const u8,
- Features: [*]const u8,
+ Triple: [*:0]const u8,
+ CPU: [*:0]const u8,
+ Features: [*:0]const u8,
Level: CodeGenOptLevel,
Reloc: RelocMode,
CodeModel: CodeModel,
@@ -175,10 +175,10 @@ extern fn ZigLLVMCreateTargetMachine(
) ?*TargetMachine;
pub const GetHostCPUName = LLVMGetHostCPUName;
-extern fn LLVMGetHostCPUName() ?[*]u8;
+extern fn LLVMGetHostCPUName() ?[*:0]u8;
pub const GetNativeFeatures = ZigLLVMGetNativeFeatures;
-extern fn ZigLLVMGetNativeFeatures() ?[*]u8;
+extern fn ZigLLVMGetNativeFeatures() ?[*:0]u8;
pub const GetElementType = LLVMGetElementType;
extern fn LLVMGetElementType(Ty: *Type) *Type;
@@ -190,16 +190,16 @@ pub const BuildStore = LLVMBuildStore;
extern fn LLVMBuildStore(arg0: *Builder, Val: *Value, Ptr: *Value) ?*Value;
pub const BuildAlloca = LLVMBuildAlloca;
-extern fn LLVMBuildAlloca(arg0: *Builder, Ty: *Type, Name: ?[*]const u8) ?*Value;
+extern fn LLVMBuildAlloca(arg0: *Builder, Ty: *Type, Name: ?[*:0]const u8) ?*Value;
pub const ConstInBoundsGEP = LLVMConstInBoundsGEP;
pub extern fn LLVMConstInBoundsGEP(ConstantVal: *Value, ConstantIndices: [*]*Value, NumIndices: c_uint) ?*Value;
pub const GetTargetFromTriple = LLVMGetTargetFromTriple;
-extern fn LLVMGetTargetFromTriple(Triple: [*]const u8, T: **Target, ErrorMessage: ?*[*]u8) Bool;
+extern fn LLVMGetTargetFromTriple(Triple: [*:0]const u8, T: **Target, ErrorMessage: ?*[*:0]u8) Bool;
pub const VerifyModule = LLVMVerifyModule;
-extern fn LLVMVerifyModule(M: *Module, Action: VerifierFailureAction, OutMessage: *?[*]u8) Bool;
+extern fn LLVMVerifyModule(M: *Module, Action: VerifierFailureAction, OutMessage: *?[*:0]u8) Bool;
pub const GetInsertBlock = LLVMGetInsertBlock;
extern fn LLVMGetInsertBlock(Builder: *Builder) *BasicBlock;
@@ -216,7 +216,7 @@ pub const GetParam = LLVMGetParam;
extern fn LLVMGetParam(Fn: *Value, Index: c_uint) *Value;
pub const AppendBasicBlockInContext = LLVMAppendBasicBlockInContext;
-extern fn LLVMAppendBasicBlockInContext(C: *Context, Fn: *Value, Name: [*]const u8) ?*BasicBlock;
+extern fn LLVMAppendBasicBlockInContext(C: *Context, Fn: *Value, Name: [*:0]const u8) ?*BasicBlock;
pub const PositionBuilderAtEnd = LLVMPositionBuilderAtEnd;
extern fn LLVMPositionBuilderAtEnd(Builder: *Builder, Block: *BasicBlock) void;
@@ -278,14 +278,14 @@ pub const TargetMachineEmitToFile = ZigLLVMTargetMachineEmitToFile;
extern fn ZigLLVMTargetMachineEmitToFile(
targ_machine_ref: *TargetMachine,
module_ref: *Module,
- filename: [*]const u8,
+ filename: [*:0]const u8,
output_type: EmitOutputType,
- error_message: *[*]u8,
+ error_message: *[*:0]u8,
is_debug: bool,
is_small: bool,
) bool;
pub const BuildCall = ZigLLVMBuildCall;
-extern fn ZigLLVMBuildCall(B: *Builder, Fn: *Value, Args: [*]*Value, NumArgs: c_uint, CC: c_uint, fn_inline: FnInline, Name: [*]const u8) ?*Value;
+extern fn ZigLLVMBuildCall(B: *Builder, Fn: *Value, Args: [*]*Value, NumArgs: c_uint, CC: c_uint, fn_inline: FnInline, Name: [*:0]const u8) ?*Value;
pub const PrivateLinkage = c.LLVMLinkage.LLVMPrivateLinkage;
diff --git a/src-self-hosted/stage1.zig b/src-self-hosted/stage1.zig
index c746cb5bef..7220c3d0d9 100644
--- a/src-self-hosted/stage1.zig
+++ b/src-self-hosted/stage1.zig
@@ -144,7 +144,7 @@ export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error {
// TODO: just use the actual self-hosted zig fmt. Until https://github.com/ziglang/zig/issues/2377,
// we use a blocking implementation.
-export fn stage2_fmt(argc: c_int, argv: [*]const [*]const u8) c_int {
+export fn stage2_fmt(argc: c_int, argv: [*]const [*:0]const u8) c_int {
if (std.debug.runtime_safety) {
fmtMain(argc, argv) catch unreachable;
} else {
@@ -156,7 +156,7 @@ export fn stage2_fmt(argc: c_int, argv: [*]const [*]const u8) c_int {
return 0;
}
-fn fmtMain(argc: c_int, argv: [*]const [*]const u8) !void {
+fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void {
const allocator = std.heap.c_allocator;
var args_list = std.ArrayList([]const u8).init(allocator);
const argc_usize = @intCast(usize, argc);
diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig
index ebc23e2ce4..0470ab92dc 100644
--- a/src-self-hosted/translate_c.zig
+++ b/src-self-hosted/translate_c.zig
@@ -113,7 +113,7 @@ const Context = struct {
}
/// Convert a null-terminated C string to a slice allocated in the arena
- fn str(c: *Context, s: [*]const u8) ![]u8 {
+ fn str(c: *Context, s: [*:0]const u8) ![]u8 {
return std.mem.dupe(c.a(), u8, std.mem.toSliceConst(u8, s));
}
diff --git a/src-self-hosted/util.zig b/src-self-hosted/util.zig
index c1e2393d0f..f1d892411f 100644
--- a/src-self-hosted/util.zig
+++ b/src-self-hosted/util.zig
@@ -172,9 +172,9 @@ pub fn getDarwinArchString(self: Target) []const u8 {
pub fn llvmTargetFromTriple(triple: std.Buffer) !*llvm.Target {
var result: *llvm.Target = undefined;
- var err_msg: [*]u8 = undefined;
- if (llvm.GetTargetFromTriple(triple.ptr(), &result, &err_msg) != 0) {
- std.debug.warn("triple: {s} error: {s}\n", triple.ptr(), err_msg);
+ var err_msg: [*:0]u8 = undefined;
+ if (llvm.GetTargetFromTriple(triple.toSlice(), &result, &err_msg) != 0) {
+ std.debug.warn("triple: {s} error: {s}\n", triple.toSlice(), err_msg);
return error.UnsupportedTarget;
}
return result;
diff --git a/src/analyze.cpp b/src/analyze.cpp
index cd00e4d301..7c9171d74a 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -7792,7 +7792,8 @@ static void resolve_llvm_types_slice(CodeGen *g, ZigType *type, ResolveStatus wa
bool done = false;
if (ptr_type->data.pointer.is_const || ptr_type->data.pointer.is_volatile ||
- ptr_type->data.pointer.explicit_alignment != 0 || ptr_type->data.pointer.allow_zero)
+ ptr_type->data.pointer.explicit_alignment != 0 || ptr_type->data.pointer.allow_zero ||
+ ptr_type->data.pointer.sentinel != nullptr)
{
ZigType *peer_ptr_type = get_pointer_to_type_extra(g, child_type, false, false,
PtrLenUnknown, 0, 0, 0, false);
@@ -7811,7 +7812,8 @@ static void resolve_llvm_types_slice(CodeGen *g, ZigType *type, ResolveStatus wa
ZigType *child_ptr_type = child_type->data.structure.fields[slice_ptr_index]->type_entry;
assert(child_ptr_type->id == ZigTypeIdPointer);
if (child_ptr_type->data.pointer.is_const || child_ptr_type->data.pointer.is_volatile ||
- child_ptr_type->data.pointer.explicit_alignment != 0 || child_ptr_type->data.pointer.allow_zero)
+ child_ptr_type->data.pointer.explicit_alignment != 0 || child_ptr_type->data.pointer.allow_zero ||
+ child_ptr_type->data.pointer.sentinel != nullptr)
{
ZigType *grand_child_type = child_ptr_type->data.pointer.child_type;
ZigType *bland_child_ptr_type = get_pointer_to_type_extra(g, grand_child_type, false, false,
diff --git a/test/stage1/behavior/cast.zig b/test/stage1/behavior/cast.zig
index 868b8d12e1..fec4494ad9 100644
--- a/test/stage1/behavior/cast.zig
+++ b/test/stage1/behavior/cast.zig
@@ -348,7 +348,7 @@ fn testCastPtrOfArrayToSliceAndPtr() void {
test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
const window_name = [1][*]const u8{"window name"};
const x: [*]const ?[*]const u8 = &window_name;
- expect(mem.eql(u8, std.mem.toSliceConst(u8, x[0].?), "window name"));
+ expect(mem.eql(u8, std.mem.toSliceConst(u8, @ptrCast([*:0]const u8, x[0].?)), "window name"));
}
test "@intCast comptime_int" {
diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig
index 89c6b29871..58a46b539c 100644
--- a/test/stage1/behavior/pointers.zig
+++ b/test/stage1/behavior/pointers.zig
@@ -207,7 +207,8 @@ test "null terminated pointer" {
var array_with_zero = [_:0]u8{'h', 'e', 'l', 'l', 'o'};
var zero_ptr: [*:0]const u8 = @ptrCast([*:0]const u8, &array_with_zero);
var no_zero_ptr: [*]const u8 = zero_ptr;
- expect(std.mem.eql(u8, std.mem.toSliceConst(u8, no_zero_ptr), "hello"));
+ var zero_ptr_again = @ptrCast([*:0]const u8, no_zero_ptr);
+ expect(std.mem.eql(u8, std.mem.toSliceConst(u8, zero_ptr_again), "hello"));
}
};
S.doTheTest();
--
cgit v1.2.3
From 29e438fd1f77a13c3a3f128434198ac024d3e195 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 25 Nov 2019 00:30:28 -0500
Subject: more sentinel-terminated pointers std lib integration
See #3767
---
doc/langref.html.in | 2 +-
lib/std/c.zig | 2 +-
lib/std/debug.zig | 16 +++++------
lib/std/dynamic_library.zig | 8 +++---
lib/std/event/fs.zig | 6 ++--
lib/std/fs.zig | 44 ++++++++++++++--------------
lib/std/fs/file.zig | 14 ++++-----
lib/std/os.zig | 70 ++++++++++++++++++++++++---------------------
lib/std/os/bits/darwin.zig | 2 +-
lib/std/os/bits/linux.zig | 2 +-
lib/std/os/wasi.zig | 4 +--
lib/std/os/windows.zig | 16 +++++------
lib/std/process.zig | 4 +--
src/analyze.cpp | 2 +-
14 files changed, 98 insertions(+), 94 deletions(-)
(limited to 'src/analyze.cpp')
diff --git a/doc/langref.html.in b/doc/langref.html.in
index be6f09a93e..324906c36f 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -4865,7 +4865,7 @@ const mem = std.mem;
test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
const window_name = [1][*]const u8{"window name"};
const x: [*]const ?[*]const u8 = &window_name;
- assert(mem.eql(u8, std.mem.toSliceConst(u8, x[0].?), "window name"));
+ assert(mem.eql(u8, std.mem.toSliceConst(u8, @ptrCast([*:0]const u8, x[0].?)), "window name"));
}
{#code_end#}
{#header_close#}
diff --git a/lib/std/c.zig b/lib/std/c.zig
index 33061b6620..19c3c8feb8 100644
--- a/lib/std/c.zig
+++ b/lib/std/c.zig
@@ -102,7 +102,7 @@ pub extern "c" fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [
pub extern "c" fn dup(fd: fd_t) c_int;
pub extern "c" fn dup2(old_fd: fd_t, new_fd: fd_t) c_int;
pub extern "c" fn readlink(noalias path: [*]const u8, noalias buf: [*]u8, bufsize: usize) isize;
-pub extern "c" fn realpath(noalias file_name: [*]const u8, noalias resolved_name: [*]u8) ?[*]u8;
+pub extern "c" fn realpath(noalias file_name: [*]const u8, noalias resolved_name: [*]u8) ?[*:0]u8;
pub extern "c" fn sigprocmask(how: c_int, noalias set: *const sigset_t, noalias oset: ?*sigset_t) c_int;
pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
pub extern "c" fn sigaction(sig: c_int, noalias act: *const Sigaction, noalias oact: ?*Sigaction) c_int;
diff --git a/lib/std/debug.zig b/lib/std/debug.zig
index 7698443ce8..dd4edf832b 100644
--- a/lib/std/debug.zig
+++ b/lib/std/debug.zig
@@ -401,7 +401,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres
const vaddr_start = coff_section.header.virtual_address + proc_sym.CodeOffset;
const vaddr_end = vaddr_start + proc_sym.CodeSize;
if (relative_address >= vaddr_start and relative_address < vaddr_end) {
- break mem.toSliceConst(u8, @ptrCast([*]u8, proc_sym) + @sizeOf(pdb.ProcSym));
+ break mem.toSliceConst(u8, @ptrCast([*:0]u8, proc_sym) + @sizeOf(pdb.ProcSym));
}
},
else => {},
@@ -703,9 +703,9 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt
return;
};
- const symbol_name = mem.toSliceConst(u8, di.strings.ptr + symbol.nlist.n_strx);
+ const symbol_name = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + symbol.nlist.n_strx));
const compile_unit_name = if (symbol.ofile) |ofile| blk: {
- const ofile_path = mem.toSliceConst(u8, di.strings.ptr + ofile.n_strx);
+ const ofile_path = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + ofile.n_strx));
break :blk fs.path.basename(ofile_path);
} else "???";
if (getLineNumberInfoMacOs(di, symbol.*, adjusted_addr)) |line_info| {
@@ -915,7 +915,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
for (present) |_| {
const name_offset = try pdb_stream.stream.readIntLittle(u32);
const name_index = try pdb_stream.stream.readIntLittle(u32);
- const name = mem.toSlice(u8, name_bytes.ptr + name_offset);
+ const name = mem.toSlice(u8, @ptrCast([*:0]u8, name_bytes.ptr + name_offset));
if (mem.eql(u8, name, "/names")) {
break :str_tab_index name_index;
}
@@ -1708,7 +1708,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
const gop = try di.ofiles.getOrPut(ofile);
const mach_o_file = if (gop.found_existing) &gop.kv.value else blk: {
errdefer _ = di.ofiles.remove(ofile);
- const ofile_path = mem.toSliceConst(u8, di.strings.ptr + ofile.n_strx);
+ const ofile_path = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + ofile.n_strx));
gop.kv.value = MachOFile{
.bytes = try std.fs.Dir.cwd().readFileAllocAligned(
@@ -1741,7 +1741,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
if (sect.flags & macho.SECTION_TYPE == macho.S_REGULAR and
(sect.flags & macho.SECTION_ATTRIBUTES) & macho.S_ATTR_DEBUG == macho.S_ATTR_DEBUG)
{
- const sect_name = mem.toSliceConst(u8, §.sectname);
+ const sect_name = mem.toSliceConst(u8, @ptrCast([*:0]const u8, §.sectname));
if (mem.eql(u8, sect_name, "__debug_line")) {
gop.kv.value.sect_debug_line = sect;
} else if (mem.eql(u8, sect_name, "__debug_info")) {
@@ -2323,8 +2323,8 @@ fn readInitialLengthMem(ptr: *[*]const u8, is_64: *bool) !u64 {
}
}
-fn readStringMem(ptr: *[*]const u8) []const u8 {
- const result = mem.toSliceConst(u8, ptr.*);
+fn readStringMem(ptr: *[*]const u8) [:0]const u8 {
+ const result = mem.toSliceConst(u8, @ptrCast([*:0]const u8, ptr.*));
ptr.* += result.len + 1;
return result;
}
diff --git a/lib/std/dynamic_library.zig b/lib/std/dynamic_library.zig
index 0e8792ca90..a4da9a8b03 100644
--- a/lib/std/dynamic_library.zig
+++ b/lib/std/dynamic_library.zig
@@ -140,7 +140,7 @@ pub const LinuxDynLib = struct {
};
pub const ElfLib = struct {
- strings: [*]u8,
+ strings: [*:0]u8,
syms: [*]elf.Sym,
hashtab: [*]os.Elf_Symndx,
versym: ?[*]u16,
@@ -175,7 +175,7 @@ pub const ElfLib = struct {
const dynv = maybe_dynv orelse return error.MissingDynamicLinkingInformation;
if (base == maxInt(usize)) return error.BaseNotFound;
- var maybe_strings: ?[*]u8 = null;
+ var maybe_strings: ?[*:0]u8 = null;
var maybe_syms: ?[*]elf.Sym = null;
var maybe_hashtab: ?[*]os.Elf_Symndx = null;
var maybe_versym: ?[*]u16 = null;
@@ -186,7 +186,7 @@ pub const ElfLib = struct {
while (dynv[i] != 0) : (i += 2) {
const p = base + dynv[i + 1];
switch (dynv[i]) {
- elf.DT_STRTAB => maybe_strings = @intToPtr([*]u8, p),
+ elf.DT_STRTAB => maybe_strings = @intToPtr([*:0]u8, p),
elf.DT_SYMTAB => maybe_syms = @intToPtr([*]elf.Sym, p),
elf.DT_HASH => maybe_hashtab = @intToPtr([*]os.Elf_Symndx, p),
elf.DT_VERSYM => maybe_versym = @intToPtr([*]u16, p),
@@ -230,7 +230,7 @@ pub const ElfLib = struct {
}
};
-fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [*]u8) bool {
+fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [*:0]u8) bool {
var def = def_arg;
const vsym = @bitCast(u32, vsym_arg) & 0x7fff;
while (true) {
diff --git a/lib/std/event/fs.zig b/lib/std/event/fs.zig
index eef5cfae7d..965302e1e6 100644
--- a/lib/std/event/fs.zig
+++ b/lib/std/event/fs.zig
@@ -58,8 +58,7 @@ pub const Request = struct {
};
pub const Open = struct {
- /// must be null terminated. TODO https://github.com/ziglang/zig/issues/265
- path: []const u8,
+ path: [:0]const u8,
flags: u32,
mode: File.Mode,
result: Error!fd_t,
@@ -68,8 +67,7 @@ pub const Request = struct {
};
pub const WriteFile = struct {
- /// must be null terminated. TODO https://github.com/ziglang/zig/issues/265
- path: []const u8,
+ path: [:0]const u8,
contents: []const u8,
mode: File.Mode,
result: Error!void,
diff --git a/lib/std/fs.zig b/lib/std/fs.zig
index d5a7930970..9fd204ae23 100644
--- a/lib/std/fs.zig
+++ b/lib/std/fs.zig
@@ -28,6 +28,7 @@ pub const GetAppDataDirError = @import("fs/get_app_data_dir.zig").GetAppDataDirE
/// This represents the maximum size of a UTF-8 encoded file path.
/// All file system operations which return a path are guaranteed to
/// fit into a UTF-8 encoded array of this length.
+/// The byte count includes room for a null sentinel byte.
pub const MAX_PATH_BYTES = switch (builtin.os) {
.linux, .macosx, .ios, .freebsd, .netbsd, .dragonfly => os.PATH_MAX,
// Each UTF-16LE character may be expanded to 3 UTF-8 bytes.
@@ -227,7 +228,7 @@ pub const AtomicFile = struct {
try crypto.randomBytes(rand_buf[0..]);
b64_fs_encoder.encode(tmp_path_buf[dirname_component_len..tmp_path_len], rand_buf);
- const file = File.openWriteNoClobberC(&tmp_path_buf, mode) catch |err| switch (err) {
+ const file = File.openWriteNoClobberC(@ptrCast([*:0]u8, &tmp_path_buf), mode) catch |err| switch (err) {
error.PathAlreadyExists => continue,
// TODO zig should figure out that this error set does not include PathAlreadyExists since
// it is handled in the above switch
@@ -247,7 +248,7 @@ pub const AtomicFile = struct {
pub fn deinit(self: *AtomicFile) void {
if (!self.finished) {
self.file.close();
- deleteFileC(&self.tmp_path_buf) catch {};
+ deleteFileC(@ptrCast([*:0]u8, &self.tmp_path_buf)) catch {};
self.finished = true;
}
}
@@ -258,11 +259,11 @@ pub const AtomicFile = struct {
self.finished = true;
if (builtin.os == .windows) {
const dest_path_w = try os.windows.sliceToPrefixedFileW(self.dest_path);
- const tmp_path_w = try os.windows.cStrToPrefixedFileW(&self.tmp_path_buf);
+ const tmp_path_w = try os.windows.cStrToPrefixedFileW(@ptrCast([*:0]u8, &self.tmp_path_buf));
return os.renameW(&tmp_path_w, &dest_path_w);
}
const dest_path_c = try os.toPosixPath(self.dest_path);
- return os.renameC(&self.tmp_path_buf, &dest_path_c);
+ return os.renameC(@ptrCast([*:0]u8, &self.tmp_path_buf), &dest_path_c);
}
};
@@ -274,12 +275,12 @@ pub fn makeDir(dir_path: []const u8) !void {
}
/// Same as `makeDir` except the parameter is a null-terminated UTF8-encoded string.
-pub fn makeDirC(dir_path: [*]const u8) !void {
+pub fn makeDirC(dir_path: [*:0]const u8) !void {
return os.mkdirC(dir_path, default_new_dir_mode);
}
/// Same as `makeDir` except the parameter is a null-terminated UTF16LE-encoded string.
-pub fn makeDirW(dir_path: [*]const u16) !void {
+pub fn makeDirW(dir_path: [*:0]const u16) !void {
return os.mkdirW(dir_path, default_new_dir_mode);
}
@@ -327,12 +328,12 @@ pub fn deleteDir(dir_path: []const u8) !void {
}
/// Same as `deleteDir` except the parameter is a null-terminated UTF8-encoded string.
-pub fn deleteDirC(dir_path: [*]const u8) !void {
+pub fn deleteDirC(dir_path: [*:0]const u8) !void {
return os.rmdirC(dir_path);
}
/// Same as `deleteDir` except the parameter is a null-terminated UTF16LE-encoded string.
-pub fn deleteDirW(dir_path: [*]const u16) !void {
+pub fn deleteDirW(dir_path: [*:0]const u16) !void {
return os.rmdirW(dir_path);
}
@@ -688,7 +689,7 @@ pub const Dir = struct {
}
/// Same as `open` except the parameter is null-terminated.
- pub fn openC(dir_path_c: [*]const u8) OpenError!Dir {
+ pub fn openC(dir_path_c: [*:0]const u8) OpenError!Dir {
return cwd().openDirC(dir_path_c);
}
@@ -708,7 +709,7 @@ pub const Dir = struct {
}
/// Call `File.close` on the result when done.
- pub fn openReadC(self: Dir, sub_path: [*]const u8) File.OpenError!File {
+ pub fn openReadC(self: Dir, sub_path: [*:0]const u8) File.OpenError!File {
if (builtin.os == .windows) {
const path_w = try os.windows.cStrToPrefixedFileW(sub_path);
return self.openReadW(&path_w);
@@ -719,7 +720,7 @@ pub const Dir = struct {
return File.openHandle(fd);
}
- pub fn openReadW(self: Dir, sub_path_w: [*]const u16) File.OpenError!File {
+ pub fn openReadW(self: Dir, sub_path_w: [*:0]const u16) File.OpenError!File {
const w = os.windows;
var result = File{ .handle = undefined };
@@ -786,7 +787,7 @@ pub const Dir = struct {
}
/// Same as `openDir` except the parameter is null-terminated.
- pub fn openDirC(self: Dir, sub_path_c: [*]const u8) OpenError!Dir {
+ pub fn openDirC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir {
if (builtin.os == .windows) {
const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);
return self.openDirW(&sub_path_w);
@@ -805,7 +806,7 @@ pub const Dir = struct {
/// Same as `openDir` except the path parameter is UTF16LE, NT-prefixed.
/// This function is Windows-only.
- pub fn openDirW(self: Dir, sub_path_w: [*]const u16) OpenError!Dir {
+ pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16) OpenError!Dir {
const w = os.windows;
var result = Dir{
@@ -868,7 +869,7 @@ pub const Dir = struct {
}
/// Same as `deleteFile` except the parameter is null-terminated.
- pub fn deleteFileC(self: Dir, sub_path_c: [*]const u8) DeleteFileError!void {
+ pub fn deleteFileC(self: Dir, sub_path_c: [*:0]const u8) DeleteFileError!void {
os.unlinkatC(self.fd, sub_path_c, 0) catch |err| switch (err) {
error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR
else => |e| return e,
@@ -903,7 +904,7 @@ pub const Dir = struct {
}
/// Same as `deleteDir` except the parameter is null-terminated.
- pub fn deleteDirC(self: Dir, sub_path_c: [*]const u8) DeleteDirError!void {
+ pub fn deleteDirC(self: Dir, sub_path_c: [*:0]const u8) DeleteDirError!void {
os.unlinkatC(self.fd, sub_path_c, os.AT_REMOVEDIR) catch |err| switch (err) {
error.IsDir => unreachable, // not possible since we pass AT_REMOVEDIR
else => |e| return e,
@@ -912,7 +913,7 @@ pub const Dir = struct {
/// Same as `deleteDir` except the parameter is UTF16LE, NT prefixed.
/// This function is Windows-only.
- pub fn deleteDirW(self: Dir, sub_path_w: [*]const u16) DeleteDirError!void {
+ pub fn deleteDirW(self: Dir, sub_path_w: [*:0]const u16) DeleteDirError!void {
os.unlinkatW(self.fd, sub_path_w, os.AT_REMOVEDIR) catch |err| switch (err) {
error.IsDir => unreachable, // not possible since we pass AT_REMOVEDIR
else => |e| return e,
@@ -927,7 +928,7 @@ pub const Dir = struct {
}
/// Same as `readLink`, except the `pathname` parameter is null-terminated.
- pub fn readLinkC(self: Dir, sub_path_c: [*]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
+ pub fn readLinkC(self: Dir, sub_path_c: [*:0]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
return os.readlinkatC(self.fd, sub_path_c, buffer);
}
@@ -1250,7 +1251,8 @@ pub fn openSelfExe() OpenSelfExeError!File {
var buf: [MAX_PATH_BYTES]u8 = undefined;
const self_exe_path = try selfExePath(&buf);
buf[self_exe_path.len] = 0;
- return File.openReadC(self_exe_path.ptr);
+ // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731
+ return File.openReadC(@ptrCast([*:0]u8, self_exe_path.ptr));
}
test "openSelfExe" {
@@ -1277,7 +1279,7 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]u8 {
var u32_len: u32 = out_buffer.len;
const rc = std.c._NSGetExecutablePath(out_buffer, &u32_len);
if (rc != 0) return error.NameTooLong;
- return mem.toSlice(u8, out_buffer);
+ return mem.toSlice(u8, @ptrCast([*:0]u8, out_buffer));
}
switch (builtin.os) {
.linux => return os.readlinkC("/proc/self/exe", out_buffer),
@@ -1306,9 +1308,9 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]u8 {
}
/// The result is UTF16LE-encoded.
-pub fn selfExePathW() []const u16 {
+pub fn selfExePathW() [:0]const u16 {
const image_path_name = &os.windows.peb().ProcessParameters.ImagePathName;
- return mem.toSliceConst(u16, image_path_name.Buffer);
+ return mem.toSliceConst(u16, @ptrCast([*:0]const u16, image_path_name.Buffer));
}
/// `selfExeDirPath` except allocates the result on the heap.
diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig
index cd50fcdece..9cfdad3885 100644
--- a/lib/std/fs/file.zig
+++ b/lib/std/fs/file.zig
@@ -31,7 +31,7 @@ pub const File = struct {
}
/// Deprecated; call `std.fs.Dir.openReadC` directly.
- pub fn openReadC(path_c: [*]const u8) OpenError!File {
+ pub fn openReadC(path_c: [*:0]const u8) OpenError!File {
return std.fs.Dir.cwd().openReadC(path_c);
}
@@ -61,7 +61,7 @@ pub const File = struct {
/// Same as `openWriteMode` except `path` is null-terminated.
/// TODO: deprecate this and move it to `std.fs.Dir`.
- pub fn openWriteModeC(path: [*]const u8, file_mode: Mode) OpenError!File {
+ pub fn openWriteModeC(path: [*:0]const u8, file_mode: Mode) OpenError!File {
if (builtin.os == .windows) {
const path_w = try windows.cStrToPrefixedFileW(path);
return openWriteModeW(&path_w, file_mode);
@@ -74,7 +74,7 @@ pub const File = struct {
/// Same as `openWriteMode` except `path` is null-terminated and UTF16LE encoded
/// TODO: deprecate this and move it to `std.fs.Dir`.
- pub fn openWriteModeW(path_w: [*]const u16, file_mode: Mode) OpenError!File {
+ pub fn openWriteModeW(path_w: [*:0]const u16, file_mode: Mode) OpenError!File {
const handle = try windows.CreateFileW(
path_w,
windows.GENERIC_WRITE,
@@ -101,7 +101,7 @@ pub const File = struct {
}
/// TODO: deprecate this and move it to `std.fs.Dir`.
- pub fn openWriteNoClobberC(path: [*]const u8, file_mode: Mode) OpenError!File {
+ pub fn openWriteNoClobberC(path: [*:0]const u8, file_mode: Mode) OpenError!File {
if (builtin.os == .windows) {
const path_w = try windows.cStrToPrefixedFileW(path);
return openWriteNoClobberW(&path_w, file_mode);
@@ -113,7 +113,7 @@ pub const File = struct {
}
/// TODO: deprecate this and move it to `std.fs.Dir`.
- pub fn openWriteNoClobberW(path_w: [*]const u16, file_mode: Mode) OpenError!File {
+ pub fn openWriteNoClobberW(path_w: [*:0]const u16, file_mode: Mode) OpenError!File {
const handle = try windows.CreateFileW(
path_w,
windows.GENERIC_WRITE,
@@ -142,13 +142,13 @@ pub const File = struct {
/// Same as `access` except the parameter is null-terminated.
/// TODO: deprecate this and move it to `std.fs.Dir`.
- pub fn accessC(path: [*]const u8) !void {
+ pub fn accessC(path: [*:0]const u8) !void {
return os.accessC(path, os.F_OK);
}
/// Same as `access` except the parameter is null-terminated UTF16LE-encoded.
/// TODO: deprecate this and move it to `std.fs.Dir`.
- pub fn accessW(path: [*]const u16) !void {
+ pub fn accessW(path: [*:0]const u16) !void {
return os.accessW(path, os.F_OK);
}
diff --git a/lib/std/os.zig b/lib/std/os.zig
index 9035d8ecbd..cda65b7ea7 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -655,8 +655,7 @@ pub fn open(file_path: []const u8, flags: u32, perm: usize) OpenError!fd_t {
/// Open and possibly create a file. Keeps trying if it gets interrupted.
/// See also `open`.
-/// TODO https://github.com/ziglang/zig/issues/265
-pub fn openC(file_path: [*]const u8, flags: u32, perm: usize) OpenError!fd_t {
+pub fn openC(file_path: [*:0]const u8, flags: u32, perm: usize) OpenError!fd_t {
while (true) {
const rc = system.open(file_path, flags, perm);
switch (errno(rc)) {
@@ -697,7 +696,7 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: usize) Open
/// Open and possibly create a file. Keeps trying if it gets interrupted.
/// `file_path` is relative to the open directory handle `dir_fd`.
/// See also `openat`.
-pub fn openatC(dir_fd: fd_t, file_path: [*]const u8, flags: u32, mode: usize) OpenError!fd_t {
+pub fn openatC(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: usize) OpenError!fd_t {
while (true) {
const rc = system.openat(dir_fd, file_path, flags, mode);
switch (errno(rc)) {
@@ -757,7 +756,7 @@ pub const ExecveError = error{
/// Like `execve` except the parameters are null-terminated,
/// matching the syscall API on all targets. This removes the need for an allocator.
/// This function ignores PATH environment variable. See `execvpeC` for that.
-pub fn execveC(path: [*]const u8, child_argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) ExecveError {
+pub fn execveC(path: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) ExecveError {
switch (errno(system.execve(path, child_argv, envp))) {
0 => unreachable,
EFAULT => unreachable,
@@ -784,7 +783,7 @@ pub fn execveC(path: [*]const u8, child_argv: [*]const ?[*]const u8, envp: [*]co
/// matching the syscall API on all targets. This removes the need for an allocator.
/// This function also uses the PATH environment variable to get the full path to the executable.
/// If `file` is an absolute path, this is the same as `execveC`.
-pub fn execvpeC(file: [*:0]const u8, child_argv: [*]const ?[*:0]const u8, envp: [*]const ?[*:0]const u8) ExecveError {
+pub fn execvpeC(file: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) ExecveError {
const file_slice = mem.toSliceConst(u8, file);
if (mem.indexOfScalar(u8, file_slice, '/') != null) return execveC(file, child_argv, envp);
@@ -799,7 +798,8 @@ pub fn execvpeC(file: [*:0]const u8, child_argv: [*]const ?[*:0]const u8, envp:
path_buf[search_path.len] = '/';
mem.copy(u8, path_buf[search_path.len + 1 ..], file_slice);
path_buf[search_path.len + file_slice.len + 1] = 0;
- err = execveC(&path_buf, child_argv, envp);
+ // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731
+ err = execveC(@ptrCast([*:0]u8, &path_buf), child_argv, envp);
switch (err) {
error.AccessDenied => seen_eacces = true,
error.FileNotFound, error.NotDir => {},
@@ -842,10 +842,13 @@ pub fn execvpe(
const envp_buf = try createNullDelimitedEnvMap(allocator, env_map);
defer freeNullDelimitedEnvMap(allocator, envp_buf);
- return execvpeC(argv_buf.ptr[0].?, argv_buf.ptr, envp_buf.ptr);
+ // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731
+ const argv_ptr = @ptrCast([*:null]?[*:0]u8, argv_buf.ptr);
+
+ return execvpeC(argv_buf.ptr[0].?, argv_ptr, envp_buf.ptr);
}
-pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std.BufMap) ![]?[*:0]u8 {
+pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std.BufMap) ![:null]?[*:0]u8 {
const envp_count = env_map.count();
const envp_buf = try allocator.alloc(?[*:0]u8, envp_count + 1);
mem.set(?[*:0]u8, envp_buf, null);
@@ -860,13 +863,14 @@ pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std.
@memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len);
env_buf[env_buf.len - 1] = 0;
- // TODO avoid @ptrCast using slice syntax with https://github.com/ziglang/zig/issues/3731
+ // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731
envp_buf[i] = @ptrCast([*:0]u8, env_buf.ptr);
}
assert(i == envp_count);
}
+ // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731
assert(envp_buf[envp_count] == null);
- return envp_buf;
+ return @ptrCast([*:null]?[*:0]u8, envp_buf.ptr)[0..envp_count];
}
pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8) void {
@@ -967,7 +971,7 @@ pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError!
/// This is the same as `symlink` except the parameters are null-terminated pointers.
/// See also `symlink`.
-pub fn symlinkC(target_path: [*]const u8, sym_link_path: [*]const u8) SymLinkError!void {
+pub fn symlinkC(target_path: [*:0]const u8, sym_link_path: [*:0]const u8) SymLinkError!void {
if (builtin.os == .windows) {
const target_path_w = try windows.cStrToPrefixedFileW(target_path);
const sym_link_path_w = try windows.cStrToPrefixedFileW(sym_link_path);
@@ -999,7 +1003,7 @@ pub fn symlinkat(target_path: []const u8, newdirfd: fd_t, sym_link_path: []const
return symlinkatC(target_path_c, newdirfd, sym_link_path_c);
}
-pub fn symlinkatC(target_path: [*]const u8, newdirfd: fd_t, sym_link_path: [*]const u8) SymLinkError!void {
+pub fn symlinkatC(target_path: [*:0]const u8, newdirfd: fd_t, sym_link_path: [*:0]const u8) SymLinkError!void {
switch (errno(system.symlinkat(target_path, newdirfd, sym_link_path))) {
0 => return,
EFAULT => unreachable,
@@ -1053,7 +1057,7 @@ pub fn unlink(file_path: []const u8) UnlinkError!void {
}
/// Same as `unlink` except the parameter is a null terminated UTF8-encoded string.
-pub fn unlinkC(file_path: [*]const u8) UnlinkError!void {
+pub fn unlinkC(file_path: [*:0]const u8) UnlinkError!void {
if (builtin.os == .windows) {
const file_path_w = try windows.cStrToPrefixedFileW(file_path);
return windows.DeleteFileW(&file_path_w);
@@ -1093,7 +1097,7 @@ pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!vo
}
/// Same as `unlinkat` but `file_path` is a null-terminated string.
-pub fn unlinkatC(dirfd: fd_t, file_path_c: [*]const u8, flags: u32) UnlinkatError!void {
+pub fn unlinkatC(dirfd: fd_t, file_path_c: [*:0]const u8, flags: u32) UnlinkatError!void {
if (builtin.os == .windows) {
const file_path_w = try windows.cStrToPrefixedFileW(file_path_c);
return unlinkatW(dirfd, &file_path_w, flags);
@@ -1122,7 +1126,7 @@ pub fn unlinkatC(dirfd: fd_t, file_path_c: [*]const u8, flags: u32) UnlinkatErro
}
/// Same as `unlinkat` but `sub_path_w` is UTF16LE, NT prefixed. Windows only.
-pub fn unlinkatW(dirfd: fd_t, sub_path_w: [*]const u16, flags: u32) UnlinkatError!void {
+pub fn unlinkatW(dirfd: fd_t, sub_path_w: [*:0]const u16, flags: u32) UnlinkatError!void {
const w = windows;
const want_rmdir_behavior = (flags & AT_REMOVEDIR) != 0;
@@ -1217,7 +1221,7 @@ pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void {
}
/// Same as `rename` except the parameters are null-terminated byte arrays.
-pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) RenameError!void {
+pub fn renameC(old_path: [*:0]const u8, new_path: [*:0]const u8) RenameError!void {
if (builtin.os == .windows) {
const old_path_w = try windows.cStrToPrefixedFileW(old_path);
const new_path_w = try windows.cStrToPrefixedFileW(new_path);
@@ -1249,7 +1253,7 @@ pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) RenameError!void {
/// Same as `rename` except the parameters are null-terminated UTF16LE encoded byte arrays.
/// Assumes target is Windows.
-pub fn renameW(old_path: [*]const u16, new_path: [*]const u16) RenameError!void {
+pub fn renameW(old_path: [*:0]const u16, new_path: [*:0]const u16) RenameError!void {
const flags = windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH;
return windows.MoveFileExW(old_path, new_path, flags);
}
@@ -1283,7 +1287,7 @@ pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void {
}
/// Same as `mkdir` but the parameter is a null-terminated UTF8-encoded string.
-pub fn mkdirC(dir_path: [*]const u8, mode: u32) MakeDirError!void {
+pub fn mkdirC(dir_path: [*:0]const u8, mode: u32) MakeDirError!void {
if (builtin.os == .windows) {
const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);
return windows.CreateDirectoryW(&dir_path_w, null);
@@ -1333,7 +1337,7 @@ pub fn rmdir(dir_path: []const u8) DeleteDirError!void {
}
/// Same as `rmdir` except the parameter is null-terminated.
-pub fn rmdirC(dir_path: [*]const u8) DeleteDirError!void {
+pub fn rmdirC(dir_path: [*:0]const u8) DeleteDirError!void {
if (builtin.os == .windows) {
const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);
return windows.RemoveDirectoryW(&dir_path_w);
@@ -1380,7 +1384,7 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {
}
/// Same as `chdir` except the parameter is null-terminated.
-pub fn chdirC(dir_path: [*]const u8) ChangeCurDirError!void {
+pub fn chdirC(dir_path: [*:0]const u8) ChangeCurDirError!void {
if (builtin.os == .windows) {
const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);
@compileError("TODO implement chdir for Windows");
@@ -1422,7 +1426,7 @@ pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
}
/// Same as `readlink` except `file_path` is null-terminated.
-pub fn readlinkC(file_path: [*]const u8, out_buffer: []u8) ReadLinkError![]u8 {
+pub fn readlinkC(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 {
if (builtin.os == .windows) {
const file_path_w = try windows.cStrToPrefixedFileW(file_path);
@compileError("TODO implement readlink for Windows");
@@ -1443,7 +1447,7 @@ pub fn readlinkC(file_path: [*]const u8, out_buffer: []u8) ReadLinkError![]u8 {
}
}
-pub fn readlinkatC(dirfd: fd_t, file_path: [*]const u8, out_buffer: []u8) ReadLinkError![]u8 {
+pub fn readlinkatC(dirfd: fd_t, file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 {
if (builtin.os == .windows) {
const file_path_w = try windows.cStrToPrefixedFileW(file_path);
@compileError("TODO implement readlink for Windows");
@@ -2130,7 +2134,7 @@ pub fn inotify_add_watch(inotify_fd: i32, pathname: []const u8, mask: u32) INoti
}
/// Same as `inotify_add_watch` except pathname is null-terminated.
-pub fn inotify_add_watchC(inotify_fd: i32, pathname: [*]const u8, mask: u32) INotifyAddWatchError!i32 {
+pub fn inotify_add_watchC(inotify_fd: i32, pathname: [*:0]const u8, mask: u32) INotifyAddWatchError!i32 {
const rc = system.inotify_add_watch(inotify_fd, pathname, mask);
switch (errno(rc)) {
0 => return @intCast(i32, rc),
@@ -2287,7 +2291,7 @@ pub fn access(path: []const u8, mode: u32) AccessError!void {
}
/// Same as `access` except `path` is null-terminated.
-pub fn accessC(path: [*]const u8, mode: u32) AccessError!void {
+pub fn accessC(path: [*:0]const u8, mode: u32) AccessError!void {
if (builtin.os == .windows) {
const path_w = try windows.cStrToPrefixedFileW(path);
_ = try windows.GetFileAttributesW(&path_w);
@@ -2314,7 +2318,7 @@ 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 {
+pub fn accessW(path: [*:0]const u16, mode: u32) windows.GetFileAttributesError!void {
const ret = try windows.GetFileAttributesW(path);
if (ret != windows.INVALID_FILE_ATTRIBUTES) {
return;
@@ -2381,7 +2385,7 @@ pub fn sysctl(
}
pub fn sysctlbynameC(
- name: [*]const u8,
+ name: [*:0]const u8,
oldp: ?*c_void,
oldlenp: ?*usize,
newp: ?*c_void,
@@ -2563,7 +2567,7 @@ pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathE
}
/// Same as `realpath` except `pathname` is null-terminated.
-pub fn realpathC(pathname: [*]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
+pub fn realpathC(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
if (builtin.os == .windows) {
const pathname_w = try windows.cStrToPrefixedFileW(pathname);
return realpathW(&pathname_w, out_buffer);
@@ -2572,10 +2576,10 @@ pub fn realpathC(pathname: [*]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPat
const fd = try openC(pathname, linux.O_PATH | linux.O_NONBLOCK | linux.O_CLOEXEC, 0);
defer close(fd);
- var procfs_buf: ["/proc/self/fd/-2147483648\x00".len]u8 = undefined;
+ var procfs_buf: ["/proc/self/fd/-2147483648".len:0]u8 = undefined;
const proc_path = std.fmt.bufPrint(procfs_buf[0..], "/proc/self/fd/{}\x00", fd) catch unreachable;
- return readlinkC(proc_path.ptr, out_buffer);
+ return readlinkC(@ptrCast([*:0]const u8, proc_path.ptr), out_buffer);
}
const result_path = std.c.realpath(pathname, out_buffer) orelse switch (std.c._errno().*) {
EINVAL => unreachable,
@@ -2594,7 +2598,7 @@ pub fn realpathC(pathname: [*]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPat
}
/// Same as `realpath` except `pathname` is null-terminated and UTF16LE-encoded.
-pub fn realpathW(pathname: [*]const u16, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
+pub fn realpathW(pathname: [*:0]const u16, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
const h_file = try windows.CreateFileW(
pathname,
windows.GENERIC_READ,
@@ -2749,8 +2753,8 @@ pub fn sched_getaffinity(pid: pid_t) SchedGetAffinityError!cpu_set_t {
/// Used to convert a slice to a null terminated slice on the stack.
/// TODO https://github.com/ziglang/zig/issues/287
-pub fn toPosixPath(file_path: []const u8) ![PATH_MAX]u8 {
- var path_with_null: [PATH_MAX]u8 = undefined;
+pub fn toPosixPath(file_path: []const u8) ![PATH_MAX-1:0]u8 {
+ var path_with_null: [PATH_MAX-1:0]u8 = undefined;
// >= rather than > to make room for the null byte
if (file_path.len >= PATH_MAX) return error.NameTooLong;
mem.copy(u8, &path_with_null, file_path);
@@ -2855,7 +2859,7 @@ pub const GetHostNameError = error{PermissionDenied} || UnexpectedError;
pub fn gethostname(name_buffer: *[HOST_NAME_MAX]u8) GetHostNameError![]u8 {
if (builtin.link_libc) {
switch (errno(system.gethostname(name_buffer, name_buffer.len))) {
- 0 => return mem.toSlice(u8, name_buffer),
+ 0 => return mem.toSlice(u8, @ptrCast([*:0]u8, name_buffer)),
EFAULT => unreachable,
ENAMETOOLONG => unreachable, // HOST_NAME_MAX prevents this
EPERM => return error.PermissionDenied,
diff --git a/lib/std/os/bits/darwin.zig b/lib/std/os/bits/darwin.zig
index 9451df6e19..26c9e7ec9b 100644
--- a/lib/std/os/bits/darwin.zig
+++ b/lib/std/os/bits/darwin.zig
@@ -1205,7 +1205,7 @@ pub const addrinfo = extern struct {
socktype: i32,
protocol: i32,
addrlen: socklen_t,
- canonname: ?[*]u8,
+ canonname: ?[*:0]u8,
addr: ?*sockaddr,
next: ?*addrinfo,
};
diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig
index e101337c3a..0fdf1dc036 100644
--- a/lib/std/os/bits/linux.zig
+++ b/lib/std/os/bits/linux.zig
@@ -1355,7 +1355,7 @@ pub const addrinfo = extern struct {
protocol: i32,
addrlen: socklen_t,
addr: ?*sockaddr,
- canonname: ?[*]u8,
+ canonname: ?[*:0]u8,
next: ?*addrinfo,
};
diff --git a/lib/std/os/wasi.zig b/lib/std/os/wasi.zig
index fce29ef0b3..7661be1f85 100644
--- a/lib/std/os/wasi.zig
+++ b/lib/std/os/wasi.zig
@@ -19,13 +19,13 @@ comptime {
pub const iovec_t = iovec;
pub const ciovec_t = iovec_const;
-pub extern "wasi_unstable" fn args_get(argv: [*][*]u8, argv_buf: [*]u8) errno_t;
+pub extern "wasi_unstable" fn args_get(argv: [*][*:0]u8, argv_buf: [*]u8) errno_t;
pub extern "wasi_unstable" fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t;
pub extern "wasi_unstable" fn clock_res_get(clock_id: clockid_t, resolution: *timestamp_t) errno_t;
pub extern "wasi_unstable" fn clock_time_get(clock_id: clockid_t, precision: timestamp_t, timestamp: *timestamp_t) errno_t;
-pub extern "wasi_unstable" fn environ_get(environ: [*]?[*]u8, environ_buf: [*]u8) errno_t;
+pub extern "wasi_unstable" fn environ_get(environ: [*]?[*:0]u8, environ_buf: [*]u8) errno_t;
pub extern "wasi_unstable" fn environ_sizes_get(environ_count: *usize, environ_buf_size: *usize) errno_t;
pub extern "wasi_unstable" fn fd_advise(fd: fd_t, offset: filesize_t, len: filesize_t, advice: advice_t) errno_t;
diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig
index a04e351799..ecb0462db1 100644
--- a/lib/std/os/windows.zig
+++ b/lib/std/os/windows.zig
@@ -192,7 +192,7 @@ pub const FindFirstFileError = error{
};
pub fn FindFirstFile(dir_path: []const u8, find_file_data: *WIN32_FIND_DATAW) FindFirstFileError!HANDLE {
- const dir_path_w = try sliceToPrefixedSuffixedFileW(dir_path, [_]u16{ '\\', '*', 0 });
+ const dir_path_w = try sliceToPrefixedSuffixedFileW(dir_path, [_]u16{ '\\', '*'});
const handle = kernel32.FindFirstFileW(&dir_path_w, find_file_data);
if (handle == INVALID_HANDLE_VALUE) {
@@ -919,18 +919,18 @@ pub fn nanoSecondsToFileTime(ns: i64) FILETIME {
};
}
-pub fn cStrToPrefixedFileW(s: [*]const u8) ![PATH_MAX_WIDE + 1]u16 {
+pub fn cStrToPrefixedFileW(s: [*:0]const u8) ![PATH_MAX_WIDE:0]u16 {
return sliceToPrefixedFileW(mem.toSliceConst(u8, s));
}
-pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE + 1]u16 {
- return sliceToPrefixedSuffixedFileW(s, [_]u16{0});
+pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE:0]u16 {
+ return sliceToPrefixedSuffixedFileW(s, &[_]u16{});
}
/// Assumes an absolute path.
-pub fn wToPrefixedFileW(s: []const u16) ![PATH_MAX_WIDE + 1]u16 {
+pub fn wToPrefixedFileW(s: []const u16) ![PATH_MAX_WIDE:0]u16 {
// TODO https://github.com/ziglang/zig/issues/2765
- var result: [PATH_MAX_WIDE + 1]u16 = undefined;
+ var result: [PATH_MAX_WIDE:0]u16 = undefined;
const start_index = if (mem.startsWith(u16, s, [_]u16{'\\', '?'})) 0 else blk: {
const prefix = [_]u16{ '\\', '?', '?', '\\' };
@@ -945,9 +945,9 @@ pub fn wToPrefixedFileW(s: []const u16) ![PATH_MAX_WIDE + 1]u16 {
}
-pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) ![PATH_MAX_WIDE + suffix.len]u16 {
+pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) ![PATH_MAX_WIDE + suffix.len:0]u16 {
// TODO https://github.com/ziglang/zig/issues/2765
- var result: [PATH_MAX_WIDE + suffix.len]u16 = undefined;
+ var result: [PATH_MAX_WIDE + suffix.len:0]u16 = undefined;
// > File I/O functions in the Windows API convert "/" to "\" as part of
// > converting the name to an NT-style name, except when using the "\\?\"
// > prefix as detailed in the following sections.
diff --git a/lib/std/process.zig b/lib/std/process.zig
index 3f065de8fc..9880108465 100644
--- a/lib/std/process.zig
+++ b/lib/std/process.zig
@@ -77,7 +77,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap {
// TODO: Verify that the documentation is incorrect
// https://github.com/WebAssembly/WASI/issues/27
- var environ = try allocator.alloc(?[*]u8, environ_count + 1);
+ var environ = try allocator.alloc(?[*:0]u8, environ_count + 1);
defer allocator.free(environ);
var environ_buf = try std.heap.wasm_allocator.alloc(u8, environ_buf_size);
defer allocator.free(environ_buf);
@@ -397,7 +397,7 @@ pub fn argsAlloc(allocator: *mem.Allocator) ![][]u8 {
return os.unexpectedErrno(args_sizes_get_ret);
}
- var argv = try allocator.alloc([*]u8, count);
+ var argv = try allocator.alloc([*:0]u8, count);
defer allocator.free(argv);
var argv_buf = try allocator.alloc(u8, buf_size);
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 7c9171d74a..70dfd4f181 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -6550,7 +6550,7 @@ static bool const_values_equal_array(CodeGen *g, ConstExprValue *a, ConstExprVal
}
bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) {
- assert(a->type->id == b->type->id);
+ if (a->type->id != b->type->id) return false;
assert(a->special == ConstValSpecialStatic);
assert(b->special == ConstValSpecialStatic);
if (a->type == b->type) {
--
cgit v1.2.3