Merge remote-tracking branch 'origin/master' into llvm6

master
Andrew Kelley 2018-02-07 17:27:30 -05:00
commit aa043a6339
17 changed files with 375 additions and 97 deletions

View File

@ -201,29 +201,29 @@ else()
COMPILE_FLAGS ${ZIG_LLD_COMPILE_FLAGS}
LINK_FLAGS " "
)
target_include_directories(embedded_lld_lib PUBLIC
target_include_directories(embedded_lld_lib PRIVATE
"${CMAKE_SOURCE_DIR}/deps/lld/include"
"${CMAKE_SOURCE_DIR}/deps/lld-prebuilt"
)
target_include_directories(embedded_lld_elf PUBLIC
target_include_directories(embedded_lld_elf PRIVATE
"${CMAKE_SOURCE_DIR}/deps/lld/ELF"
"${CMAKE_SOURCE_DIR}/deps/lld/include"
"${CMAKE_SOURCE_DIR}/deps/lld-prebuilt/ELF"
"${CMAKE_SOURCE_DIR}/deps/lld-prebuilt"
)
target_include_directories(embedded_lld_coff PUBLIC
target_include_directories(embedded_lld_coff PRIVATE
"${CMAKE_SOURCE_DIR}/deps/lld/COFF"
"${CMAKE_SOURCE_DIR}/deps/lld/include"
"${CMAKE_SOURCE_DIR}/deps/lld-prebuilt/COFF"
"${CMAKE_SOURCE_DIR}/deps/lld-prebuilt"
)
target_include_directories(embedded_lld_mingw PUBLIC
target_include_directories(embedded_lld_mingw PRIVATE
"${CMAKE_SOURCE_DIR}/deps/lld/MinGW"
"${CMAKE_SOURCE_DIR}/deps/lld/include"
"${CMAKE_SOURCE_DIR}/deps/lld-prebuilt/MinGW"
"${CMAKE_SOURCE_DIR}/deps/lld-prebuilt"
)
target_include_directories(embedded_lld_wasm PUBLIC
target_include_directories(embedded_lld_wasm PRIVATE
"${CMAKE_SOURCE_DIR}/deps/lld/wasm"
"${CMAKE_SOURCE_DIR}/deps/lld/include"
"${CMAKE_SOURCE_DIR}/deps/lld-prebuilt/wasm"
@ -482,10 +482,10 @@ set(ZIG_STD_FILES
"os/darwin_errno.zig"
"os/get_user_id.zig"
"os/index.zig"
"os/linux.zig"
"os/linux_errno.zig"
"os/linux_i386.zig"
"os/linux_x86_64.zig"
"os/linux/index.zig"
"os/linux/errno.zig"
"os/linux/i386.zig"
"os/linux/x86_64.zig"
"os/path.zig"
"os/windows/error.zig"
"os/windows/index.zig"

View File

@ -36,25 +36,47 @@
code {
font-size: 12pt;
}
@media screen and (min-width: 28.75em) {
pre > code {
display: block;
overflow: auto;
}
.table-wrapper {
width: 100%;
overflow-y: auto;
}
/* Desktop */
@media screen and (min-width: 56.25em) {
#nav {
width: 20em;
height: 100%;
overflow-y: scroll;
position: fixed;
overflow-y: scroll;
left: 0;
top: 0;
padding-left: 1em;
}
#contents {
max-width: 50em;
max-width: 60em;
padding-left: 22em;
padding: 1em;
padding-left: 24em;
}
}
/* Mobile */
@media screen and (max-width: 56.25em) {
body, code {
font-size: small;
}
#nav {
border-bottom: 1px solid grey;
}
}
</style>
</head>
<body>
<div id="nav">
{#nav#}
<h3>Index</h3>
{#nav#}
</div>
<div id="contents">
{#header_open|Introduction#}
@ -112,16 +134,6 @@ pub fn main() void {
</p>
{#see_also|Values|@import|Errors|Root Source File#}
{#header_close#}
{#header_open|Source Encoding#}
<p>Zig source code is encoded in UTF-8. An invalid UTF-8 byte sequence results in a compile error.</p>
<p>Throughout all zig source code (including in comments), some codepoints are never allowed:</p>
<ul>
<li>Ascii control characters, except for U+000a (LF): U+0000 - U+0009, U+000b - U+0001f, U+007f. (Note that Windows line endings (CRLF) are not allowed, and hard tabs are not allowed.)</li>
<li>Non-Ascii Unicode line endings: U+0085 (NEL), U+2028 (LS), U+2029 (PS).</li>
</ul>
<p>The codepoint U+000a (LF) (which is encoded as the single-byte value 0x0a) is the line terminator character. This character always terminates a line of zig source code (except possbly the last line of the file).</p>
<p>For some discussion on the rationale behind these design decisions, see <a href="https://github.com/zig-lang/zig/issues/663">issue #663</a></p>
{#header_close#}
{#header_open|Values#}
{#code_begin|exe|values#}
const std = @import("std");
@ -173,6 +185,7 @@ pub fn main() %void {
}
{#code_end#}
{#header_open|Primitive Types#}
<div class="table-wrapper">
<table>
<tr>
<th>
@ -398,9 +411,11 @@ pub fn main() %void {
<td>an error code</td>
</tr>
</table>
</div>
{#see_also|Integers|Floats|void|Errors#}
{#header_close#}
{#header_open|Primitive Values#}
<div class="table-wrapper">
<table>
<tr>
<th>
@ -427,6 +442,7 @@ pub fn main() %void {
<td>refers to the thing in immediate scope</td>
</tr>
</table>
</div>
{#see_also|Nullables|this#}
{#header_close#}
{#header_open|String Literals#}
@ -451,6 +467,7 @@ test "string literals" {
{#code_end#}
{#see_also|Arrays|Zig Test#}
{#header_open|Escape Sequences#}
<div class="table-wrapper">
<table>
<tr>
<th>
@ -497,6 +514,7 @@ test "string literals" {
<td>hexadecimal 24-bit Unicode character code UTF-8 encoded (6 digits)</td>
</tr>
</table>
</div>
<p>Note that the maximum valid Unicode point is <code>0x10ffff</code>.</p>
{#header_close#}
{#header_open|Multiline String Literals#}
@ -674,6 +692,7 @@ pub fn main() %void {
{#header_close#}
{#header_open|Operators#}
{#header_open|Table of Operators#}
<div class="table-wrapper">
<table>
<tr>
<th>
@ -1246,6 +1265,7 @@ const ptr = &amp;x;
</td>
</tr>
</table>
</div>
{#header_close#}
{#header_open|Precedence#}
<pre><code>x() x[] x.y
@ -2755,6 +2775,16 @@ test "implicitly cast to const pointer" {
use the C calling convention may pass structs and unions by value.
</p>
{#header_close#}
{#header_open|Function Reflection#}
{#code_begin|test#}
const assert = @import("std").debug.assert;
test "fn reflection" {
assert(@typeOf(assert).ReturnType == void);
assert(@typeOf(assert).is_var_args == false);
}
{#code_end#}
{#header_close#}
{#header_close#}
{#header_open|Errors#}
<p>
@ -2968,6 +2998,31 @@ fn createFoo(param: i32) %Foo {
</li>
</ul>
{#see_also|defer|if|switch#}
{#header_open|Error Union Type#}
<p>An error union is created by putting a <code>%</code> in front of a type.
You can use compile-time reflection to access the child type of an error union:</p>
{#code_begin|test#}
const assert = @import("std").debug.assert;
error SomeError;
test "error union" {
var foo: %i32 = undefined;
// Implicitly cast from child type of an error union:
foo = 1234;
// Implicitly cast from an error set:
foo = error.SomeError;
// Use compile-time reflection to access the child type of an error union:
comptime assert(@typeOf(foo).Child == i32);
}
{#code_end#}
{#header_close#}
{#header_open|Error Set Type#}
<p>TODO</p>
{#header_close#}
{#header_close#}
{#header_open|Nullables#}
<p>
@ -3069,6 +3124,24 @@ fn doAThing(nullable_foo: ?&Foo) void {
The optimizer can sometimes make better decisions knowing that pointer arguments
cannot be null.
</p>
{#header_open|Nullable Type#}
<p>A nullable is created by putting <code>?</code> in front of a type. You can use compile-time
reflection to access the child type of a nullable:</p>
{#code_begin|test#}
const assert = @import("std").debug.assert;
test "nullable type" {
// Declare a nullable and implicitly cast from null:
var foo: ?i32 = null;
// Implicitly cast from child type of a nullable
foo = 1234;
// Use compile-time reflection to access the child type of the nullable:
comptime assert(@typeOf(foo).Child == i32);
}
{#code_end#}
{#header_close#}
{#header_close#}
{#header_open|Casting#}
<p>TODO: explain implicit vs explicit casting</p>
@ -3804,6 +3877,17 @@ comptime {
<code>@cInclude</code>, <code>@cDefine</code>, and <code>@cUndef</code> work
within this expression, appending to a temporary buffer which is then parsed as C code.
</p>
<p>
Usually you should only have one <code>@cImport</code> in your entire application, because it saves the compiler
from invoking clang multiple times, and prevents inline functions from being duplicated.
</p>
<p>
Reasons for having multiple <code>@cImport</code> expressions would be:
</p>
<ul>
<li>To avoid a symbol collision, for example if foo.h and bar.h both <code>#define CONNECTION_COUNT</code></li>
<li>To analyze the C code with different preprocessor defines</li>
</ul>
{#see_also|Import from C Header File|@cInclude|@cDefine|@cUndef#}
{#header_close#}
{#header_open|@cInclude#}
@ -4133,17 +4217,28 @@ fn add(a: i32, b: i32) i32 { return a + b; }
{#header_open|@memberCount#}
<pre><code class="zig">@memberCount(comptime T: type) -&gt; (number literal)</code></pre>
<p>
This function returns the number of enum values in an enum type.
This function returns the number of members in a struct, enum, or union type.
</p>
<p>
The result is a compile time constant.
</p>
<p>
It does not include functions, variables, or constants.
</p>
{#header_close#}
{#header_open|@memberName#}
<p>TODO</p>
<pre><code class="zig">@memberName(comptime T: type, comptime index: usize) -&gt; [N]u8</code></pre>
<p>Returns the field name of a struct, union, or enum.</p>
<p>
The result is a compile time constant.
</p>
<p>
It does not include functions, variables, or constants.
</p>
{#header_close#}
{#header_open|@memberType#}
<p>TODO</p>
<pre><code class="zig">@memberType(comptime T: type, comptime index: usize) -&gt; type</code></pre>
<p>Returns the field type of a struct or union.</p>
{#header_close#}
{#header_open|@memcpy#}
<pre><code class="zig">@memcpy(noalias dest: &u8, noalias source: &const u8, byte_count: usize)</code></pre>
@ -5533,6 +5628,16 @@ fn readU32Be() u32 {}
</p>
{#header_close#}
{#header_close#}
{#header_open|Source Encoding#}
<p>Zig source code is encoded in UTF-8. An invalid UTF-8 byte sequence results in a compile error.</p>
<p>Throughout all zig source code (including in comments), some codepoints are never allowed:</p>
<ul>
<li>Ascii control characters, except for U+000a (LF): U+0000 - U+0009, U+000b - U+0001f, U+007f. (Note that Windows line endings (CRLF) are not allowed, and hard tabs are not allowed.)</li>
<li>Non-Ascii Unicode line endings: U+0085 (NEL), U+2028 (LS), U+2029 (PS).</li>
</ul>
<p>The codepoint U+000a (LF) (which is encoded as the single-byte value 0x0a) is the line terminator character. This character always terminates a line of zig source code (except possbly the last line of the file).</p>
<p>For some discussion on the rationale behind these design decisions, see <a href="https://github.com/zig-lang/zig/issues/663">issue #663</a></p>
{#header_close#}
{#header_open|Grammar#}
<pre><code class="nohighlight">Root = many(TopLevelItem) EOF
@ -5701,9 +5806,6 @@ ContainerDecl = option("extern" | "packed")
<li>Together we serve end users.</li>
</ul>
{#header_close#}
{#header_open|TODO#}
<p>TODO: document changes from a31b23c46ba2a8c28df01adc1aa0b4d878b9a5cf (compile time reflection additions)</p>
{#header_close#}
</div>
<script>
/*! highlight.js v9.12.0 | BSD3 License | git.io/hljslicense */
@ -5765,7 +5867,7 @@ hljs.registerLanguage("zig", function(t) {
a = t.IR + "\\s*\\(",
c = {
keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong",
built_in: "breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchg fence divExact truncate",
built_in: "breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchg fence divExact truncate",
literal: "true false null undefined"
},
n = [e, t.CLCM, t.CBCM, s, r];

View File

@ -331,12 +331,14 @@ struct TypeEnumField {
Buf *name;
BigInt value;
uint32_t decl_index;
AstNode *decl_node;
};
struct TypeUnionField {
Buf *name;
TypeEnumField *enum_field;
TypeTableEntry *type_entry;
AstNode *decl_node;
uint32_t gen_index;
};
@ -961,6 +963,7 @@ struct TypeStructField {
size_t packed_bits_offset;
size_t packed_bits_size;
size_t unaligned_bit_count;
AstNode *decl_node;
};
struct TypeTableEntryStruct {
AstNode *decl_node;
@ -982,6 +985,8 @@ struct TypeTableEntryStruct {
bool zero_bits_loop_flag;
bool zero_bits_known;
uint32_t abi_alignment; // also figured out with zero_bits pass
HashMap<Buf *, TypeStructField *, buf_hash, buf_eql_buf> fields_by_name;
};
struct TypeTableEntryMaybe {
@ -1013,6 +1018,8 @@ struct TypeTableEntryEnum {
bool generate_name_table;
LLVMValueRef name_table;
HashMap<Buf *, TypeEnumField *, buf_hash, buf_eql_buf> fields_by_name;
};
uint32_t type_ptr_hash(const TypeTableEntry *ptr);
@ -1045,6 +1052,8 @@ struct TypeTableEntryUnion {
uint32_t union_size_bytes;
TypeTableEntry *most_aligned_union_member;
HashMap<Buf *, TypeUnionField *, buf_hash, buf_eql_buf> fields_by_name;
};
struct FnGenParamInfo {

View File

@ -633,20 +633,27 @@ TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t
static void slice_type_common_init(CodeGen *g, TypeTableEntry *pointer_type, TypeTableEntry *entry) {
unsigned element_count = 2;
Buf *ptr_field_name = buf_create_from_str("ptr");
Buf *len_field_name = buf_create_from_str("len");
entry->data.structure.layout = ContainerLayoutAuto;
entry->data.structure.is_slice = true;
entry->data.structure.src_field_count = element_count;
entry->data.structure.gen_field_count = element_count;
entry->data.structure.fields = allocate<TypeStructField>(element_count);
entry->data.structure.fields[slice_ptr_index].name = buf_create_from_str("ptr");
entry->data.structure.fields_by_name.init(element_count);
entry->data.structure.fields[slice_ptr_index].name = ptr_field_name;
entry->data.structure.fields[slice_ptr_index].type_entry = pointer_type;
entry->data.structure.fields[slice_ptr_index].src_index = slice_ptr_index;
entry->data.structure.fields[slice_ptr_index].gen_index = 0;
entry->data.structure.fields[slice_len_index].name = buf_create_from_str("len");
entry->data.structure.fields[slice_len_index].name = len_field_name;
entry->data.structure.fields[slice_len_index].type_entry = g->builtin_types.entry_usize;
entry->data.structure.fields[slice_len_index].src_index = slice_len_index;
entry->data.structure.fields[slice_len_index].gen_index = 1;
entry->data.structure.fields_by_name.put(ptr_field_name, &entry->data.structure.fields[slice_ptr_index]);
entry->data.structure.fields_by_name.put(len_field_name, &entry->data.structure.fields[slice_len_index]);
assert(type_has_zero_bits_known(pointer_type->data.pointer.child_type));
if (pointer_type->data.pointer.child_type->zero_bits) {
entry->data.structure.gen_field_count = 1;
@ -1555,6 +1562,7 @@ TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *f
struct_type->data.structure.zero_bits_known = true;
struct_type->data.structure.complete = true;
struct_type->data.structure.fields = allocate<TypeStructField>(field_count);
struct_type->data.structure.fields_by_name.init(field_count);
ZigLLVMDIType **di_element_types = allocate<ZigLLVMDIType*>(field_count);
LLVMTypeRef *element_types = allocate<LLVMTypeRef>(field_count);
@ -1566,6 +1574,9 @@ TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *f
field->type_entry = field_types[i];
field->src_index = i;
field->gen_index = i;
auto prev_entry = struct_type->data.structure.fields_by_name.put_unique(field->name, field);
assert(prev_entry == nullptr);
}
struct_type->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), type_name);
@ -2102,6 +2113,7 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
enum_type->data.enumeration.src_field_count = field_count;
enum_type->data.enumeration.fields = allocate<TypeEnumField>(field_count);
enum_type->data.enumeration.fields_by_name.init(field_count);
Scope *scope = &enum_type->data.enumeration.decls_scope->base;
@ -2139,6 +2151,7 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i];
type_enum_field->name = field_node->data.struct_field.name;
type_enum_field->decl_index = field_i;
type_enum_field->decl_node = field_node;
if (field_node->data.struct_field.type != nullptr) {
ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.type,
@ -2147,6 +2160,15 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
buf_sprintf("consider 'union(enum)' here"));
}
auto field_entry = enum_type->data.enumeration.fields_by_name.put_unique(type_enum_field->name, type_enum_field);
if (field_entry != nullptr) {
ErrorMsg *msg = add_node_error(g, field_node,
buf_sprintf("duplicate enum field: '%s'", buf_ptr(type_enum_field->name)));
add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here"));
enum_type->data.enumeration.is_invalid = true;
continue;
}
AstNode *tag_value = field_node->data.struct_field.value;
// In this first pass we resolve explicit tag values.
@ -2242,6 +2264,7 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
size_t field_count = decl_node->data.container_decl.fields.length;
struct_type->data.structure.src_field_count = (uint32_t)field_count;
struct_type->data.structure.fields = allocate<TypeStructField>(field_count);
struct_type->data.structure.fields_by_name.init(field_count);
Scope *scope = &struct_type->data.structure.decls_scope->base;
@ -2250,6 +2273,7 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
AstNode *field_node = decl_node->data.container_decl.fields.at(i);
TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
type_struct_field->name = field_node->data.struct_field.name;
type_struct_field->decl_node = field_node;
if (field_node->data.struct_field.type == nullptr) {
add_node_error(g, field_node, buf_sprintf("struct field missing type"));
@ -2257,6 +2281,15 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
continue;
}
auto field_entry = struct_type->data.structure.fields_by_name.put_unique(type_struct_field->name, type_struct_field);
if (field_entry != nullptr) {
ErrorMsg *msg = add_node_error(g, field_node,
buf_sprintf("duplicate struct field: '%s'", buf_ptr(type_struct_field->name)));
add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here"));
struct_type->data.structure.is_invalid = true;
continue;
}
TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
type_struct_field->type_entry = field_type;
type_struct_field->src_index = i;
@ -2344,6 +2377,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
}
union_type->data.unionation.src_field_count = field_count;
union_type->data.unionation.fields = allocate<TypeUnionField>(field_count);
union_type->data.unionation.fields_by_name.init(field_count);
uint32_t biggest_align_bytes = 0;
@ -2395,6 +2429,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
tag_type->data.enumeration.layout = ContainerLayoutAuto;
tag_type->data.enumeration.src_field_count = field_count;
tag_type->data.enumeration.fields = allocate<TypeEnumField>(field_count);
tag_type->data.enumeration.fields_by_name.init(field_count);
tag_type->data.enumeration.decls_scope = union_type->data.unionation.decls_scope;
tag_type->data.enumeration.complete = true;
} else if (enum_type_node != nullptr) {
@ -2424,6 +2459,16 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
Buf *field_name = field_node->data.struct_field.name;
TypeUnionField *union_field = &union_type->data.unionation.fields[i];
union_field->name = field_node->data.struct_field.name;
union_field->decl_node = field_node;
auto field_entry = union_type->data.unionation.fields_by_name.put_unique(union_field->name, union_field);
if (field_entry != nullptr) {
ErrorMsg *msg = add_node_error(g, field_node,
buf_sprintf("duplicate union field: '%s'", buf_ptr(union_field->name)));
add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here"));
union_type->data.unionation.is_invalid = true;
continue;
}
TypeTableEntry *field_type;
if (field_node->data.struct_field.type == nullptr) {
@ -2456,6 +2501,10 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
union_field->enum_field = &tag_type->data.enumeration.fields[i];
union_field->enum_field->name = field_name;
union_field->enum_field->decl_index = i;
union_field->enum_field->decl_node = field_node;
auto prev_entry = tag_type->data.enumeration.fields_by_name.put_unique(union_field->enum_field->name, union_field->enum_field);
assert(prev_entry == nullptr); // caught by union de-duplicator above
AstNode *tag_value = field_node->data.struct_field.value;
// In this first pass we resolve explicit tag values.
@ -3246,6 +3295,10 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
is_const, init_val, &tld_var->base);
tld_var->var->linkage = linkage;
if (implicit_type != nullptr && type_is_invalid(implicit_type)) {
tld_var->var->value->type = g->builtin_types.entry_invalid;
}
if (var_decl->align_expr != nullptr) {
if (!analyze_const_align(g, tld_var->base.parent_scope, var_decl->align_expr, &tld_var->var->align_bytes)) {
tld_var->var->value->type = g->builtin_types.entry_invalid;
@ -3327,11 +3380,7 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *
}
// slice const
if (expected_type->id == TypeTableEntryIdStruct &&
actual_type->id == TypeTableEntryIdStruct &&
expected_type->data.structure.is_slice &&
actual_type->data.structure.is_slice)
{
if (is_slice(expected_type) && is_slice(actual_type)) {
TypeTableEntry *actual_ptr_type = actual_type->data.structure.fields[slice_ptr_index].type_entry;
TypeTableEntry *expected_ptr_type = expected_type->data.structure.fields[slice_ptr_index].type_entry;
if ((!actual_ptr_type->data.pointer.is_const || expected_ptr_type->data.pointer.is_const) &&
@ -3499,37 +3548,35 @@ FnTableEntry *scope_get_fn_if_root(Scope *scope) {
}
TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name) {
for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) {
TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];
if (buf_eql_buf(type_enum_field->name, name)) {
return type_enum_field;
}
}
return nullptr;
assert(enum_type->id == TypeTableEntryIdEnum);
if (enum_type->data.enumeration.src_field_count == 0)
return nullptr;
auto entry = enum_type->data.enumeration.fields_by_name.maybe_get(name);
if (entry == nullptr)
return nullptr;
return entry->value;
}
TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name) {
assert(type_entry->id == TypeTableEntryIdStruct);
assert(type_entry->data.structure.complete);
for (uint32_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
TypeStructField *field = &type_entry->data.structure.fields[i];
if (buf_eql_buf(field->name, name)) {
return field;
}
}
return nullptr;
if (type_entry->data.structure.src_field_count == 0)
return nullptr;
auto entry = type_entry->data.structure.fields_by_name.maybe_get(name);
if (entry == nullptr)
return nullptr;
return entry->value;
}
TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) {
assert(type_entry->id == TypeTableEntryIdUnion);
assert(type_entry->data.unionation.zero_bits_known);
for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) {
TypeUnionField *field = &type_entry->data.unionation.fields[i];
if (buf_eql_buf(field->enum_field->name, name)) {
return field;
}
}
return nullptr;
if (type_entry->data.unionation.src_field_count == 0)
return nullptr;
auto entry = type_entry->data.unionation.fields_by_name.maybe_get(name);
if (entry == nullptr)
return nullptr;
return entry->value;
}
TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag) {

View File

@ -60,8 +60,8 @@ bool type_is_complete(TypeTableEntry *type_entry);
bool type_is_invalid(TypeTableEntry *type_entry);
bool type_has_zero_bits_known(TypeTableEntry *type_entry);
void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry);
TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name);
ScopeDecls *get_container_scope(TypeTableEntry *type_entry);
TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name);
TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name);
TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name);
TypeEnumField *find_enum_field_by_tag(TypeTableEntry *enum_type, const BigInt *tag);

View File

@ -6193,6 +6193,15 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc
if (other_type->id == TypeTableEntryIdFloat) {
return true;
} else if (other_type->id == TypeTableEntryIdInt && const_val_is_int) {
if (!other_type->data.integral.is_signed && const_val->data.x_bigint.is_negative) {
Buf *val_buf = buf_alloc();
bigint_append_buf(val_buf, &const_val->data.x_bigint, 10);
ir_add_error(ira, instruction,
buf_sprintf("cannot cast negative value %s to unsigned integer type '%s'",
buf_ptr(val_buf),
buf_ptr(&other_type->name)));
return false;
}
if (bigint_fits_in_bits(&const_val->data.x_bigint, other_type->data.integral.bit_count,
other_type->data.integral.is_signed))
{
@ -6205,6 +6214,15 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc
if (const_val_fits_in_num_lit(const_val, child_type)) {
return true;
} else if (child_type->id == TypeTableEntryIdInt && const_val_is_int) {
if (!child_type->data.integral.is_signed && const_val->data.x_bigint.is_negative) {
Buf *val_buf = buf_alloc();
bigint_append_buf(val_buf, &const_val->data.x_bigint, 10);
ir_add_error(ira, instruction,
buf_sprintf("cannot cast negative value %s to unsigned integer type '%s'",
buf_ptr(val_buf),
buf_ptr(&child_type->name)));
return false;
}
if (bigint_fits_in_bits(&const_val->data.x_bigint,
child_type->data.integral.bit_count,
child_type->data.integral.is_signed))
@ -6351,10 +6369,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
}
// implicit [N]T to []const T
if (expected_type->id == TypeTableEntryIdStruct &&
expected_type->data.structure.is_slice &&
actual_type->id == TypeTableEntryIdArray)
{
if (is_slice(expected_type) && actual_type->id == TypeTableEntryIdArray) {
TypeTableEntry *ptr_type = expected_type->data.structure.fields[slice_ptr_index].type_entry;
assert(ptr_type->id == TypeTableEntryIdPointer);
@ -6366,8 +6381,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
}
// implicit &const [N]T to []const T
if (expected_type->id == TypeTableEntryIdStruct &&
expected_type->data.structure.is_slice &&
if (is_slice(expected_type) &&
actual_type->id == TypeTableEntryIdPointer &&
actual_type->data.pointer.is_const &&
actual_type->data.pointer.child_type->id == TypeTableEntryIdArray)
@ -7009,7 +7023,7 @@ static IrInstruction *ir_get_const_ptr(IrAnalyze *ira, IrInstruction *instructio
if (pointee_type->id == TypeTableEntryIdMetaType) {
TypeTableEntry *type_entry = pointee->data.x_type;
if (type_entry->id == TypeTableEntryIdUnreachable) {
ir_add_error(ira, instruction, buf_sprintf("pointer to unreachable not allowed"));
ir_add_error(ira, instruction, buf_sprintf("pointer to noreturn not allowed"));
return ira->codegen->invalid_instruction;
}
@ -9837,6 +9851,15 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
AstNode *fn_proto_node = fn_entry ? fn_entry->proto_node : nullptr;;
if (fn_type_id->cc == CallingConventionNaked) {
ErrorMsg *msg = ir_add_error(ira, fn_ref, buf_sprintf("unable to call function with naked calling convention"));
if (fn_proto_node) {
add_error_note(ira->codegen, msg, fn_proto_node, buf_sprintf("declared here"));
}
return ira->codegen->builtin_types.entry_invalid;
}
if (fn_type_id->is_var_args) {
if (call_param_count < src_param_count) {
ErrorMsg *msg = ir_add_error_node(ira, source_node,

View File

@ -1,4 +1,4 @@
pub use @import("../os/linux_errno.zig");
pub use @import("../os/linux/errno.zig");
pub extern "c" fn getrandom(buf_ptr: &u8, buf_len: usize, flags: c_uint) c_int;
extern "c" fn __errno_location() &c_int;

View File

@ -228,7 +228,7 @@ pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []cons
if (@typeId(T.Child) == builtin.TypeId.Array and T.Child.Child == u8) {
return output(context, (*value)[0..]);
} else {
@compileError("Unable to format type '" ++ @typeName(T) ++ "'");
return format(context, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
}
},
else => if (@canImplicitCast([]const u8, value)) {
@ -546,6 +546,12 @@ test "parse unsigned comptime" {
}
}
// Dummy field because of https://github.com/zig-lang/zig/issues/557.
// At top level because of https://github.com/zig-lang/zig/issues/675.
const Struct = struct {
unused: u8,
};
test "fmt.format" {
{
var buf1: [32]u8 = undefined;
@ -577,6 +583,14 @@ test "fmt.format" {
const result = try bufPrint(buf1[0..], "u3: {}\n", value);
assert(mem.eql(u8, result, "u3: 5\n"));
}
{
var buf1: [32]u8 = undefined;
const value = Struct {
.unused = 42,
};
const result = try bufPrint(buf1[0..], "pointer: {}\n", &value);
assert(mem.startsWith(u8, result, "pointer: Struct@"));
}
// TODO get these tests passing in release modes
// https://github.com/zig-lang/zig/issues/564

View File

@ -6,6 +6,7 @@ pub const Buffer = @import("buffer.zig").Buffer;
pub const BufferOutStream = @import("buffer.zig").BufferOutStream;
pub const HashMap = @import("hash_map.zig").HashMap;
pub const LinkedList = @import("linked_list.zig").LinkedList;
pub const IntrusiveLinkedList = @import("linked_list.zig").IntrusiveLinkedList;
pub const base64 = @import("base64.zig");
pub const build = @import("build.zig");

View File

@ -2,7 +2,7 @@ const std = @import("index.zig");
const builtin = @import("builtin");
const Os = builtin.Os;
const system = switch(builtin.os) {
Os.linux => @import("os/linux.zig"),
Os.linux => @import("os/linux/index.zig"),
Os.macosx, Os.ios => @import("os/darwin.zig"),
Os.windows => @import("os/windows/index.zig"),
else => @compileError("Unsupported OS"),

View File

@ -6,7 +6,7 @@ const os = this;
pub const windows = @import("windows/index.zig");
pub const darwin = @import("darwin.zig");
pub const linux = @import("linux.zig");
pub const linux = @import("linux/index.zig");
pub const zen = @import("zen.zig");
pub const posix = switch(builtin.os) {
Os.linux => linux,
@ -82,18 +82,24 @@ pub fn getRandomBytes(buf: []u8) %void {
// See #397
const err = posix.getErrno(posix.getrandom(buf.ptr, buf.len, 0));
if (err > 0) {
return switch (err) {
switch (err) {
posix.EINVAL => unreachable,
posix.EFAULT => unreachable,
posix.EINTR => continue,
else => unexpectedErrorPosix(err),
};
posix.ENOSYS => {
const fd = try posixOpenC(c"/dev/urandom", posix.O_RDONLY|posix.O_CLOEXEC, 0);
defer close(fd);
try posixRead(fd, buf);
return;
},
else => return unexpectedErrorPosix(err),
}
}
return;
},
Os.macosx, Os.ios => {
const fd = try posixOpen("/dev/urandom", posix.O_RDONLY|posix.O_CLOEXEC,
0, null);
const fd = try posixOpenC(c"/dev/urandom", posix.O_RDONLY|posix.O_CLOEXEC, 0);
defer close(fd);
try posixRead(fd, buf);
@ -183,10 +189,15 @@ pub fn close(handle: FileHandle) void {
/// Calls POSIX read, and keeps trying if it gets interrupted.
pub fn posixRead(fd: i32, buf: []u8) %void {
// Linux can return EINVAL when read amount is > 0x7ffff000
// See https://github.com/zig-lang/zig/pull/743#issuecomment-363158274
const max_buf_len = 0x7ffff000;
var index: usize = 0;
while (index < buf.len) {
const amt_written = posix.read(fd, &buf[index], buf.len - index);
const err = posix.getErrno(amt_written);
const want_to_read = math.min(buf.len - index, usize(max_buf_len));
const rc = posix.read(fd, &buf[index], want_to_read);
const err = posix.getErrno(rc);
if (err > 0) {
return switch (err) {
posix.EINTR => continue,
@ -199,7 +210,7 @@ pub fn posixRead(fd: i32, buf: []u8) %void {
else => unexpectedErrorPosix(err),
};
}
index += amt_written;
index += rc;
}
}
@ -214,9 +225,15 @@ error BrokenPipe;
/// Calls POSIX write, and keeps trying if it gets interrupted.
pub fn posixWrite(fd: i32, bytes: []const u8) %void {
while (true) {
const write_ret = posix.write(fd, bytes.ptr, bytes.len);
const write_err = posix.getErrno(write_ret);
// Linux can return EINVAL when write amount is > 0x7ffff000
// See https://github.com/zig-lang/zig/pull/743#issuecomment-363165856
const max_bytes_len = 0x7ffff000;
var index: usize = 0;
while (index < bytes.len) {
const amt_to_write = math.min(bytes.len - index, usize(max_bytes_len));
const rc = posix.write(fd, &bytes[index], amt_to_write);
const write_err = posix.getErrno(rc);
if (write_err > 0) {
return switch (write_err) {
posix.EINTR => continue,
@ -233,7 +250,7 @@ pub fn posixWrite(fd: i32, bytes: []const u8) %void {
else => unexpectedErrorPosix(write_err),
};
}
return;
index += rc;
}
}
@ -262,8 +279,12 @@ pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Al
mem.copy(u8, path0, file_path);
path0[file_path.len] = 0;
return posixOpenC(path0.ptr, flags, perm);
}
pub fn posixOpenC(file_path: &const u8, flags: u32, perm: usize) %i32 {
while (true) {
const result = posix.open(path0.ptr, flags, perm);
const result = posix.open(file_path, flags, perm);
const err = posix.getErrno(result);
if (err > 0) {
return switch (err) {
@ -1495,10 +1516,10 @@ test "std.os" {
_ = @import("darwin_errno.zig");
_ = @import("darwin.zig");
_ = @import("get_user_id.zig");
_ = @import("linux_errno.zig");
_ = @import("linux/errno.zig");
//_ = @import("linux_i386.zig");
_ = @import("linux_x86_64.zig");
_ = @import("linux.zig");
_ = @import("linux/x86_64.zig");
_ = @import("linux/index.zig");
_ = @import("path.zig");
_ = @import("windows/index.zig");
}

View File

@ -1,4 +1,5 @@
const linux = @import("linux.zig");
const std = @import("../../index.zig");
const linux = std.os.linux;
const socklen_t = linux.socklen_t;
const iovec = linux.iovec;

View File

@ -1,12 +1,12 @@
const std = @import("../index.zig");
const std = @import("../../index.zig");
const assert = std.debug.assert;
const builtin = @import("builtin");
const arch = switch (builtin.arch) {
builtin.Arch.x86_64 => @import("linux_x86_64.zig"),
builtin.Arch.i386 => @import("linux_i386.zig"),
builtin.Arch.x86_64 => @import("x86_64.zig"),
builtin.Arch.i386 => @import("i386.zig"),
else => @compileError("unsupported arch"),
};
pub use @import("linux_errno.zig");
pub use @import("errno.zig");
pub const PATH_MAX = 4096;
@ -787,10 +787,10 @@ pub fn timerfd_settime(fd: i32, flags: u32, new_value: &const itimerspec, old_va
return arch.syscall4(arch.SYS_timerfd_settime, usize(fd), usize(flags), @ptrToInt(new_value), @ptrToInt(old_value));
}
test "import linux_test" {
test "import linux test" {
// TODO lazy analysis should prevent this test from being compiled on windows, but
// it is still compiled on windows
if (builtin.os == builtin.Os.linux) {
_ = @import("linux_test.zig");
_ = @import("test.zig");
}
}

View File

@ -1,4 +1,4 @@
const std = @import("std");
const std = @import("../../index.zig");
const linux = std.os.linux;
const assert = std.debug.assert;

View File

@ -1,4 +1,5 @@
const linux = @import("linux.zig");
const std = @import("../../index.zig");
const linux = std.os.linux;
const socklen_t = linux.socklen_t;
const iovec = linux.iovec;

View File

@ -1,6 +1,65 @@
const tests = @import("tests.zig");
pub fn addCases(cases: &tests.CompileErrorContext) void {
cases.add("cast negative integer literal to usize",
\\export fn entry() void {
\\ const x = usize(-10);
\\}
, ".tmp_source.zig:2:21: error: cannot cast negative value -10 to unsigned integer type 'usize'");
cases.add("use invalid number literal as array index",
\\var v = 25;
\\export fn entry() void {
\\ var arr: [v]u8 = undefined;
\\}
, ".tmp_source.zig:1:1: error: unable to infer variable type");
cases.add("duplicate struct field",
\\const Foo = struct {
\\ Bar: i32,
\\ Bar: usize,
\\};
\\export fn entry() void {
\\ const a: Foo = undefined;
\\}
,
".tmp_source.zig:3:5: error: duplicate struct field: 'Bar'",
".tmp_source.zig:2:5: note: other field here");
cases.add("duplicate union field",
\\const Foo = union {
\\ Bar: i32,
\\ Bar: usize,
\\};
\\export fn entry() void {
\\ const a: Foo = undefined;
\\}
,
".tmp_source.zig:3:5: error: duplicate union field: 'Bar'",
".tmp_source.zig:2:5: note: other field here");
cases.add("duplicate enum field",
\\const Foo = enum {
\\ Bar,
\\ Bar,
\\};
\\
\\export fn entry() void {
\\ const a: Foo = undefined;
\\}
,
".tmp_source.zig:3:5: error: duplicate enum field: 'Bar'",
".tmp_source.zig:2:5: note: other field here");
cases.add("calling function with naked calling convention",
\\export fn entry() void {
\\ foo();
\\}
\\nakedcc fn foo() void { }
,
".tmp_source.zig:2:5: error: unable to call function with naked calling convention",
".tmp_source.zig:4:9: note: declared here");
cases.add("function with invalid return type",
\\export fn foo() boid {}
, ".tmp_source.zig:1:17: error: use of undeclared identifier 'boid'");
@ -326,10 +385,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
\\export fn entry() void { _ = a(); }
, ".tmp_source.zig:1:8: error: use of undeclared identifier 'bogus'");
cases.add("pointer to unreachable",
cases.add("pointer to noreturn",
\\fn a() &noreturn {}
\\export fn entry() void { _ = a(); }
, ".tmp_source.zig:1:9: error: pointer to unreachable not allowed");
, ".tmp_source.zig:1:9: error: pointer to noreturn not allowed");
cases.add("unreachable code",
\\export fn a() void {