Merge branch 'master' into llvm-17

This commit is contained in:
gingerBill
2023-09-27 11:38:11 +01:00
16 changed files with 202 additions and 42 deletions

View File

@@ -343,7 +343,7 @@ unquote_string :: proc(token: Token, spec: Specification, allocator := context.a
i += 1
continue
}
r, w := utf8.decode_rune_in_string(s)
r, w := utf8.decode_rune_in_string(s[i:])
if r == utf8.RUNE_ERROR && w == 1 {
break
}

View File

@@ -39,12 +39,12 @@ write_int :: proc(w: Writer, i: int, base: int = 10, n_written: ^int = nil) -> (
}
write_u128 :: proc(w: Writer, i: u128, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) {
buf: [32]byte
buf: [39]byte
s := strconv.append_bits_128(buf[:], i, base, false, 128, strconv.digits, nil)
return write_string(w, s, n_written)
}
write_i128 :: proc(w: Writer, i: i128, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) {
buf: [32]byte
buf: [40]byte
s := strconv.append_bits_128(buf[:], u128(i), base, true, 128, strconv.digits, nil)
return write_string(w, s, n_written)
}

View File

@@ -413,6 +413,48 @@ cstring_to_string :: proc "contextless" (s: cstring) -> string {
}
cstring_eq :: proc "contextless" (lhs, rhs: cstring) -> bool {
x := ([^]byte)(lhs)
y := ([^]byte)(rhs)
if x == y {
return true
}
if (x == nil) ~ (y == nil) {
return false
}
xn := cstring_len(lhs)
yn := cstring_len(rhs)
if xn != yn {
return false
}
return #force_inline memory_equal(x, y, xn)
}
cstring_cmp :: proc "contextless" (lhs, rhs: cstring) -> int {
x := ([^]byte)(lhs)
y := ([^]byte)(rhs)
if x == y {
return 0
}
if (x == nil) ~ (y == nil) {
return -1 if x == nil else +1
}
xn := cstring_len(lhs)
yn := cstring_len(rhs)
ret := memory_compare(x, y, min(xn, yn))
if ret == 0 && xn != yn {
return -1 if xn < yn else +1
}
return ret
}
cstring_ne :: #force_inline proc "contextless" (a, b: cstring) -> bool { return !cstring_eq(a, b) }
cstring_lt :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) < 0 }
cstring_gt :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) > 0 }
cstring_le :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) <= 0 }
cstring_ge :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) >= 0 }
complex32_eq :: #force_inline proc "contextless" (a, b: complex32) -> bool { return real(a) == real(b) && imag(a) == imag(b) }
complex32_ne :: #force_inline proc "contextless" (a, b: complex32) -> bool { return real(a) != real(b) || imag(a) != imag(b) }

View File

@@ -2120,7 +2120,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
return false;
}
Type *t = o.type;
if (t == nullptr || t == t_invalid || is_type_asm_proc(o.type) || is_type_polymorphic(operand->type)) {
if (t == nullptr || t == t_invalid || is_type_asm_proc(t) || is_type_polymorphic(t)) {
error(ce->args[0], "Invalid argument for '%.*s'", LIT(builtin_name));
return false;
}

View File

@@ -2462,8 +2462,9 @@ gb_internal void add_comparison_procedures_for_fields(CheckerContext *c, Type *t
add_package_dependency(c, "runtime", "quaternion256_ne");
break;
case Basic_cstring:
add_package_dependency(c, "runtime", "cstring_to_string");
/*fallthrough*/
add_package_dependency(c, "runtime", "cstring_eq");
add_package_dependency(c, "runtime", "cstring_ne");
break;
case Basic_string:
add_package_dependency(c, "runtime", "string_eq");
add_package_dependency(c, "runtime", "string_ne");
@@ -2621,7 +2622,16 @@ gb_internal void check_comparison(CheckerContext *c, Ast *node, Operand *x, Oper
if (!is_type_untyped(x->type)) size = gb_max(size, type_size_of(x->type));
if (!is_type_untyped(y->type)) size = gb_max(size, type_size_of(y->type));
if (is_type_string(x->type) || is_type_string(y->type)) {
if (is_type_cstring(x->type) && is_type_cstring(y->type)) {
switch (op) {
case Token_CmpEq: add_package_dependency(c, "runtime", "cstring_eq"); break;
case Token_NotEq: add_package_dependency(c, "runtime", "cstring_ne"); break;
case Token_Lt: add_package_dependency(c, "runtime", "cstring_lt"); break;
case Token_Gt: add_package_dependency(c, "runtime", "cstring_gt"); break;
case Token_LtEq: add_package_dependency(c, "runtime", "cstring_le"); break;
case Token_GtEq: add_package_dependency(c, "runtime", "cstring_gt"); break;
}
} else if (is_type_string(x->type) || is_type_string(y->type)) {
switch (op) {
case Token_CmpEq: add_package_dependency(c, "runtime", "string_eq"); break;
case Token_NotEq: add_package_dependency(c, "runtime", "string_ne"); break;

View File

@@ -1893,7 +1893,7 @@ gb_internal void check_value_decl_stmt(CheckerContext *ctx, Ast *node, u32 mod_f
}
if (is_arch_wasm() && e->Variable.thread_local_model.len != 0) {
error(e->token, "@(thread_local) is not supported for this target platform");
// error(e->token, "@(thread_local) is not supported for this target platform");
}

View File

@@ -613,6 +613,9 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *
scope_reserve(ctx->scope, min_field_count);
rw_mutex_lock(&struct_type->Struct.fields_mutex);
defer (rw_mutex_unlock(&struct_type->Struct.fields_mutex));
if (st->is_raw_union && min_field_count > 1) {
struct_type->Struct.is_raw_union = true;
context = str_lit("struct #raw_union");

View File

@@ -2029,6 +2029,9 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) {
break;
case Type_Generic:
break;
default:
GB_PANIC("Unhandled type: %*.s %d", LIT(type_strings[bt->kind]), bt->kind);
break;

View File

@@ -356,7 +356,9 @@ gb_internal void error_out_coloured(char const *str, TerminalStyle style, Termin
gb_internal void error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
global_error_collector.count.fetch_add(1);
if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT()) {
gb_exit(1);
}
mutex_lock(&global_error_collector.mutex);
// NOTE(bill): Duplicate error, skip it
if (pos.line == 0) {
@@ -372,11 +374,10 @@ gb_internal void error_va(TokenPos const &pos, TokenPos end, char const *fmt, va
error_out_va(fmt, va);
error_out("\n");
show_error_on_line(pos, end);
} else {
global_error_collector.count.fetch_sub(1);
}
mutex_unlock(&global_error_collector.mutex);
if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT()) {
gb_exit(1);
}
}
gb_internal void warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
@@ -410,8 +411,11 @@ gb_internal void error_line_va(char const *fmt, va_list va) {
}
gb_internal void error_no_newline_va(TokenPos const &pos, char const *fmt, va_list va) {
mutex_lock(&global_error_collector.mutex);
global_error_collector.count.fetch_add(1);
if (global_error_collector.count.load() > MAX_ERROR_COLLECTOR_COUNT()) {
gb_exit(1);
}
mutex_lock(&global_error_collector.mutex);
// NOTE(bill): Duplicate error, skip it
if (pos.line == 0) {
error_out_coloured("Error: ", TerminalStyle_Normal, TerminalColour_Red);
@@ -425,15 +429,15 @@ gb_internal void error_no_newline_va(TokenPos const &pos, char const *fmt, va_li
error_out_va(fmt, va);
}
mutex_unlock(&global_error_collector.mutex);
if (global_error_collector.count.load() > MAX_ERROR_COLLECTOR_COUNT()) {
gb_exit(1);
}
}
gb_internal void syntax_error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
global_error_collector.count.fetch_add(1);
if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT()) {
gb_exit(1);
}
mutex_lock(&global_error_collector.mutex);
global_error_collector.count++;
// NOTE(bill): Duplicate error, skip it
if (global_error_collector.prev != pos) {
global_error_collector.prev = pos;
@@ -447,16 +451,14 @@ gb_internal void syntax_error_va(TokenPos const &pos, TokenPos end, char const *
error_out_va(fmt, va);
error_out("\n");
}
mutex_unlock(&global_error_collector.mutex);
if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT()) {
gb_exit(1);
}
}
gb_internal void syntax_error_with_verbose_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
global_error_collector.count.fetch_add(1);
if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT()) {
gb_exit(1);
}
mutex_lock(&global_error_collector.mutex);
// NOTE(bill): Duplicate error, skip it
if (pos.line == 0) {
@@ -474,9 +476,6 @@ gb_internal void syntax_error_with_verbose_va(TokenPos const &pos, TokenPos end,
show_error_on_line(pos, end);
}
mutex_unlock(&global_error_collector.mutex);
if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT()) {
gb_exit(1);
}
}
@@ -578,7 +577,3 @@ gb_internal void compiler_error(char const *fmt, ...) {
GB_DEBUG_TRAP();
gb_exit(1);
}

View File

@@ -2414,7 +2414,28 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left
}
if (is_type_string(a)) {
if (is_type_cstring(a)) {
if (is_type_cstring(a) && is_type_cstring(b)) {
left = lb_emit_conv(p, left, t_cstring);
right = lb_emit_conv(p, right, t_cstring);
char const *runtime_procedure = nullptr;
switch (op_kind) {
case Token_CmpEq: runtime_procedure = "cstring_eq"; break;
case Token_NotEq: runtime_procedure = "cstring_ne"; break;
case Token_Lt: runtime_procedure = "cstring_lt"; break;
case Token_Gt: runtime_procedure = "cstring_gt"; break;
case Token_LtEq: runtime_procedure = "cstring_le"; break;
case Token_GtEq: runtime_procedure = "cstring_gt"; break;
}
GB_ASSERT(runtime_procedure != nullptr);
auto args = array_make<lbValue>(permanent_allocator(), 2);
args[0] = left;
args[1] = right;
return lb_emit_runtime_call(p, runtime_procedure, args);
}
if (is_type_cstring(a) ^ is_type_cstring(b)) {
left = lb_emit_conv(p, left, t_string);
right = lb_emit_conv(p, right, t_string);
}

View File

@@ -1361,6 +1361,22 @@ gb_internal Token peek_token(AstFile *f) {
return {};
}
gb_internal Token peek_token_n(AstFile *f, isize n) {
Token found = {};
for (isize i = f->curr_token_index+1; i < f->tokens.count; i++) {
Token tok = f->tokens[i];
if (tok.kind == Token_Comment) {
continue;
}
found = tok;
if (n-- == 0) {
return found;
}
}
return {};
}
gb_internal bool skip_possible_newline(AstFile *f) {
if (token_is_newline(f->curr_token)) {
advance_token(f);
@@ -2206,6 +2222,10 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
Ast *tag = ast_basic_directive(f, token, name);
Ast *original_expr = parse_expr(f, lhs);
Ast *expr = unparen_expr(original_expr);
if (expr == nullptr) {
syntax_error(name, "Expected a compound literal after #%.*s", LIT(name.string));
return ast_bad_expr(f, token, name);
}
switch (expr->kind) {
case Ast_ArrayType:
syntax_error(expr, "#partial has been replaced with #sparse for non-contiguous enumerated array types");
@@ -3419,6 +3439,18 @@ gb_internal Ast *parse_simple_stmt(AstFile *f, u32 flags) {
case Token_Colon:
expect_token_after(f, Token_Colon, "identifier list");
if ((flags&StmtAllowFlag_Label) && lhs.count == 1) {
bool is_partial = false;
Token partial_token = {};
if (f->curr_token.kind == Token_Hash) {
// NOTE(bill): This is purely for error messages
Token name = peek_token_n(f, 0);
if (name.kind == Token_Ident && name.string == "partial" &&
peek_token_n(f, 1).kind == Token_switch) {
partial_token = expect_token(f, Token_Hash);
expect_token(f, Token_Ident);
is_partial = true;
}
}
switch (f->curr_token.kind) {
case Token_OpenBrace: // block statement
case Token_if:
@@ -3440,6 +3472,19 @@ gb_internal Ast *parse_simple_stmt(AstFile *f, u32 flags) {
break;
}
#undef _SET_LABEL
if (is_partial) {
switch (stmt->kind) {
case Ast_SwitchStmt:
stmt->SwitchStmt.partial = true;
break;
case Ast_TypeSwitchStmt:
stmt->TypeSwitchStmt.partial = true;
break;
}
syntax_error(partial_token, "Incorrect use of directive, use '#partial %.*s: switch'", LIT(ast_token(name).string));
}
return stmt;
} break;
}
@@ -3984,7 +4029,9 @@ gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_fl
if (f->curr_token.kind != Token_Eq) {
type = parse_var_type(f, allow_ellipsis, allow_typeid_token);
Ast *tt = unparen_expr(type);
if (is_signature && !any_polymorphic_names && tt->kind == Ast_TypeidType && tt->TypeidType.specialization != nullptr) {
if (is_signature && !any_polymorphic_names &&
tt != nullptr &&
tt->kind == Ast_TypeidType && tt->TypeidType.specialization != nullptr) {
syntax_error(type, "Specialization of typeid is not allowed without polymorphic names");
}
}
@@ -5941,6 +5988,16 @@ gb_internal ParseFileError process_imported_file(Parser *p, ImportedFile importe
}
}
{
String name = file->fullpath;
name = remove_directory_from_path(name);
name = remove_extension_from_path(name);
if (string_starts_with(name, str_lit("_"))) {
syntax_error(pos, "Files cannot start with '_', got '%.*s'", LIT(file->fullpath));
}
}
if (build_context.command_kind == Command_test) {
String name = file->fullpath;
name = remove_extension_from_path(name);
@@ -5951,6 +6008,7 @@ gb_internal ParseFileError process_imported_file(Parser *p, ImportedFile importe
}
}
if (parse_file(p, file)) {
MUTEX_GUARD_BLOCK(&pkg->files_mutex) {
array_add(&pkg->files, file);

View File

@@ -143,7 +143,8 @@ struct TypeStruct {
Type * soa_elem;
i32 soa_count;
StructSoaKind soa_kind;
BlockingMutex mutex; // for settings offsets
RwMutex fields_mutex;
BlockingMutex offset_mutex; // for settings offsets
bool is_polymorphic;
bool are_offsets_set : 1;
@@ -2645,10 +2646,14 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple
return are_types_identical(x->Slice.elem, y->Slice.elem);
case Type_BitSet:
return are_types_identical(x->BitSet.elem, y->BitSet.elem) &&
are_types_identical(x->BitSet.underlying, y->BitSet.underlying) &&
x->BitSet.lower == y->BitSet.lower &&
x->BitSet.upper == y->BitSet.upper;
if (are_types_identical(x->BitSet.elem, y->BitSet.elem) &&
are_types_identical(x->BitSet.underlying, y->BitSet.underlying)) {
if (is_type_enum(x->BitSet.elem)) {
return true;
}
return x->BitSet.lower == y->BitSet.lower && x->BitSet.upper == y->BitSet.upper;
}
return false;
case Type_Enum:
@@ -2951,7 +2956,11 @@ gb_internal Selection lookup_field_from_index(Type *type, i64 index) {
gbAllocator a = permanent_allocator();
isize max_count = 0;
switch (type->kind) {
case Type_Struct: max_count = type->Struct.fields.count; break;
case Type_Struct:
rw_mutex_shared_lock(&type->Struct.fields_mutex);
max_count = type->Struct.fields.count;
rw_mutex_shared_unlock(&type->Struct.fields_mutex);
break;
case Type_Tuple: max_count = type->Tuple.variables.count; break;
}
@@ -2960,7 +2969,9 @@ gb_internal Selection lookup_field_from_index(Type *type, i64 index) {
}
switch (type->kind) {
case Type_Struct:
case Type_Struct: {
rw_mutex_shared_lock(&type->Struct.fields_mutex);
defer (rw_mutex_shared_unlock(&type->Struct.fields_mutex));
for (isize i = 0; i < max_count; i++) {
Entity *f = type->Struct.fields[i];
if (f->kind == Entity_Variable) {
@@ -2971,7 +2982,8 @@ gb_internal Selection lookup_field_from_index(Type *type, i64 index) {
}
}
}
break;
} break;
case Type_Tuple:
for (isize i = 0; i < max_count; i++) {
Entity *f = type->Tuple.variables[i];
@@ -3024,7 +3036,10 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name
}
}
if (type->kind == Type_Struct) {
for_array(i, type->Struct.fields) {
rw_mutex_shared_lock(&type->Struct.fields_mutex);
isize field_count = type->Struct.fields.count;
rw_mutex_shared_unlock(&type->Struct.fields_mutex);
if (field_count != 0) for_array(i, type->Struct.fields) {
Entity *f = type->Struct.fields[i];
if (f->flags&EntityFlag_Using) {
sel = lookup_field_with_selection(f->type, field_name, is_type, sel, allow_blank_ident);
@@ -3052,7 +3067,9 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name
}
if (type->kind == Type_Struct) {
rw_mutex_shared_lock(&type->Struct.fields_mutex);
Scope *s = type->Struct.scope;
rw_mutex_shared_unlock(&type->Struct.fields_mutex);
if (s != nullptr) {
Entity *found = scope_lookup_current(s, field_name);
if (found != nullptr && found->kind != Entity_Variable) {
@@ -3100,7 +3117,10 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name
}
}
for_array(i, type->Struct.fields) {
rw_mutex_shared_lock(&type->Struct.fields_mutex);
isize field_count = type->Struct.fields.count;
rw_mutex_shared_unlock(&type->Struct.fields_mutex);
if (field_count != 0) for_array(i, type->Struct.fields) {
Entity *f = type->Struct.fields[i];
if (f->kind != Entity_Variable || (f->flags & EntityFlag_Field) == 0) {
continue;
@@ -3680,7 +3700,7 @@ gb_internal i64 *type_set_offsets_of(Slice<Entity *> const &fields, bool is_pack
gb_internal bool type_set_offsets(Type *t) {
t = base_type(t);
if (t->kind == Type_Struct) {
MUTEX_GUARD(&t->Struct.mutex);
MUTEX_GUARD(&t->Struct.offset_mutex);
if (!t->Struct.are_offsets_set) {
t->Struct.are_offsets_being_processed = true;
t->Struct.offsets = type_set_offsets_of(t->Struct.fields, t->Struct.is_packed, t->Struct.is_raw_union);

View File

@@ -33,6 +33,7 @@ main :: proc() {
marshal_json(&t)
unmarshal_json(&t)
surrogate(&t)
utf8_string_of_multibyte_characters(&t)
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
if TEST_fail > 0 {
@@ -359,3 +360,10 @@ surrogate :: proc(t: ^testing.T) {
expect(t, uerr == nil, fmt.tprintf("Expected `json.unmarshal(%q)` to return a nil error, got %v", string(out), uerr))
expect(t, back == input, fmt.tprintf("Expected `json.unmarshal(%q)` to return %q, got %v", string(out), input, uerr))
}
@test
utf8_string_of_multibyte_characters :: proc(t: ^testing.T) {
_, err := json.parse_string(`"🐛✅"`)
msg := fmt.tprintf("Expected `json.parse` to return nil, got %v", err)
expect(t, err == nil, msg)
}