parent
6b623b5ea2
commit
7597735bad
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
|
@ -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 {
|
||||
|
221
src/analyze.cpp
221
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,56 +565,35 @@ 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)) {
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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<LLVMValueRef>(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<ConstGlobalRefs>(1);
|
||||
|
||||
g->const_zero_byte.special = ConstValSpecialStatic;
|
||||
g->const_zero_byte.type = g->builtin_types.entry_u8;
|
||||
g->const_zero_byte.global_refs = allocate<ConstGlobalRefs>(1);
|
||||
bigint_init_unsigned(&g->const_zero_byte.data.x_bigint, 0);
|
||||
|
||||
{
|
||||
ConstGlobalRefs *global_refs = allocate<ConstGlobalRefs>(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);
|
||||
|
||||
|
@ -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;
|
||||
|
452
src/ir.cpp
452
src/ir.cpp
File diff suppressed because it is too large
Load Diff
184
src/parser.cpp
184
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<AsmOutput>(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<AsmInput>(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 *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);
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -28,9 +28,6 @@ enum TokenId {
|
||||
TokenIdBitShiftRight,
|
||||
TokenIdBitShiftRightEq,
|
||||
TokenIdBitXorEq,
|
||||
TokenIdBracketStarBracket,
|
||||
TokenIdBracketStarCBracket,
|
||||
TokenIdBracketUnderscoreBracket,
|
||||
TokenIdCharLiteral,
|
||||
TokenIdCmpEq,
|
||||
TokenIdCmpGreaterOrEq,
|
||||
|
@ -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<ZigToken>(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;
|
||||
|
@ -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);
|
||||
|
@ -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"));
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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"));
|
||||
}
|
||||
|
@ -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 });
|
||||
|
@ -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" {
|
||||
|
Loading…
x
Reference in New Issue
Block a user