Browse Source

Merge branch 'master' into llvm-17

gingerBill 1 year ago
parent
commit
acc29fbceb

+ 0 - 0
core/crypto/_blake2/_blake2.odin → core/crypto/_blake2/blake2.odin


+ 0 - 0
core/crypto/_sha3/_sha3.odin → core/crypto/_sha3/sha3.odin


+ 0 - 0
core/crypto/_tiger/_tiger.odin → core/crypto/_tiger/tiger.odin


+ 1 - 1
core/encoding/json/parser.odin

@@ -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
 		}

+ 2 - 2
core/io/util.odin

@@ -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)
 }

+ 42 - 0
core/runtime/internal.odin

@@ -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) }
 

+ 1 - 1
src/check_builtin.cpp

@@ -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;
 		}

+ 13 - 3
src/check_expr.cpp

@@ -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;

+ 1 - 1
src/check_stmt.cpp

@@ -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");
 		}
 
 

+ 3 - 0
src/check_type.cpp

@@ -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");

+ 3 - 0
src/checker.cpp

@@ -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;

+ 16 - 21
src/error.cpp

@@ -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);
 }
-
-
-
-

+ 22 - 1
src/llvm_backend_expr.cpp

@@ -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);
 		}

+ 59 - 1
src/parser.cpp

@@ -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);

+ 31 - 11
src/types.cpp

@@ -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);

+ 8 - 0
tests/core/encoding/json/test_core_json.odin

@@ -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)
+}