Browse Source

Merge branch 'master' into windows-llvm-13.0.0

gingerBill 2 năm trước cách đây
mục cha
commit
85ddff01f1

+ 2 - 1
.gitignore

@@ -270,6 +270,7 @@ bin/
 
 # - Linux/MacOS
 odin
+!odin/
 odin.dSYM
 *.bin
 demo.bin
@@ -286,4 +287,4 @@ shared/
 *.sublime-workspace
 examples/bug/
 build.sh
-!core/debug/
+!core/debug/

+ 4 - 4
core/mem/virtual/arena.odin

@@ -242,7 +242,7 @@ arena_growing_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, min
 	return arena_growing_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), minimum_block_size)
 }
 
-// Ability to bootstrap allocate a struct with an arena within the struct itself using the growing variant strategy.
+// Ability to bootstrap allocate a struct with an arena within the struct itself using the static variant strategy.
 @(require_results)
 arena_static_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, reserved: uint) -> (ptr: ^T, err: Allocator_Error) {
 	bootstrap: Arena
@@ -258,7 +258,7 @@ arena_static_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintpt
 	return
 }
 
-// Ability to bootstrap allocate a struct with an arena within the struct itself using the growing variant strategy.
+// Ability to bootstrap allocate a struct with an arena within the struct itself using the static variant strategy.
 @(require_results)
 arena_static_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, reserved: uint) -> (ptr: ^T, err: Allocator_Error) {
 	return arena_static_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), reserved)
@@ -271,7 +271,7 @@ arena_allocator :: proc(arena: ^Arena) -> mem.Allocator {
 	return mem.Allocator{arena_allocator_proc, arena}
 }
 
-// The allocator procedured by an `Allocator` produced by `arena_allocator`
+// The allocator procedure used by an `Allocator` produced by `arena_allocator`
 arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
                              size, alignment: int,
                              old_memory: rawptr, old_size: int,
@@ -328,7 +328,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
 
 
 
-// An `Arena_Temp` is a way to produce temporary watermarks to reset a arena to a previous state.
+// An `Arena_Temp` is a way to produce temporary watermarks to reset an arena to a previous state.
 // All uses of an `Arena_Temp` must be handled by ending them with `arena_temp_end` or ignoring them with `arena_temp_ignore`.
 Arena_Temp :: struct {
 	arena: ^Arena,

+ 14 - 3
core/sync/primitives.odin

@@ -7,10 +7,21 @@ current_thread_id :: proc "contextless" () -> int {
 	return _current_thread_id()
 }
 
-// A Mutex is a mutual exclusion lock
-// The zero value for a Mutex is an unlocked mutex
+// A Mutex is a [[mutual exclusion lock; https://en.wikipedia.org/wiki/Mutual_exclusion]]
+// It can be used to prevent more than one thread from executing the same piece of code,
+// and thus prevent access to same piece of memory by multiple threads, at the same time.
 //
-// A Mutex must not be copied after first use
+// A Mutex's zero value represents an initial, *unlocked* state.
+//
+// If another thread tries to take the lock while another thread holds it, it will pause
+// until the lock is released. Code or memory that is "surrounded" by a mutex lock is said
+// to be "guarded by a mutex".
+//
+// A Mutex must not be copied after first use (e.g., after locking it the first time).
+// This is because, in order to coordinate with other threads, all threads must watch
+// the same memory address to know when the lock has been released. Trying to use a
+// copy of the lock at a different memory address will result in broken and unsafe
+// behavior. For this reason, Mutexes are marked as `#no_copy`.
 Mutex :: struct #no_copy {
 	impl: _Mutex,
 }

+ 5 - 0
core/sys/windows/kernel32.odin

@@ -159,6 +159,11 @@ foreign kernel32 {
 	WaitForSingleObject :: proc(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD ---
 	Sleep :: proc(dwMilliseconds: DWORD) ---
 	GetProcessId :: proc(handle: HANDLE) -> DWORD ---
+	CopyFileW :: proc(
+		lpExistingFileName: LPCWSTR,
+		lpNewFileName: LPCWSTR,
+		bFailIfExists: BOOL,
+	) -> BOOL ---
 	CopyFileExW :: proc(
 		lpExistingFileName: LPCWSTR,
 		lpNewFileName: LPCWSTR,

+ 10 - 0
core/sys/windows/ws2_32.odin

@@ -206,4 +206,14 @@ foreign ws2_32 {
 		optval: ^c_char,
 		optlen: ^c_int,
 	) -> c_int ---
+	// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-ntohl)
+	ntohl :: proc(netlong: c_ulong) -> c_ulong ---
+	// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-ntohs)
+	ntohs :: proc(netshort: c_ushort) -> c_ushort ---
+	// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-htonl)
+	@(deprecated="Use endian specific integers instead, https://odin-lang.org/docs/overview/#basic-types")
+	htonl :: proc(hostlong: c_ulong) -> c_ulong ---
+	// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-htons)
+	@(deprecated="Use endian specific integers instead, https://odin-lang.org/docs/overview/#basic-types")
+	htons :: proc(hostshort: c_ushort) -> c_ushort ---
 }

+ 5 - 2
core/testing/testing.odin

@@ -4,6 +4,9 @@ import "core:fmt"
 import "core:io"
 import "core:time"
 import "core:intrinsics"
+import "core:reflect"
+
+_ :: reflect // alias reflect to nothing to force visibility for -vet
 
 // IMPORTANT NOTE: Compiler requires this layout
 Test_Signature :: proc(^T)
@@ -89,7 +92,7 @@ expect :: proc(t: ^T, ok: bool, msg: string = "", loc := #caller_location) -> bo
 	return ok
 }
 expect_value :: proc(t: ^T, value, expected: $T, loc := #caller_location) -> bool where intrinsics.type_is_comparable(T) {
-	ok := value == expected
+	ok := value == expected || reflect.is_nil(value) && reflect.is_nil(expected)
 	if !ok {
 		errorf(t, "expected %v, got %v", expected, value, loc=loc)
 	}
@@ -100,4 +103,4 @@ expect_value :: proc(t: ^T, value, expected: $T, loc := #caller_location) -> boo
 
 set_fail_timeout :: proc(t: ^T, duration: time.Duration, loc := #caller_location) {
 	_fail_timeout(t, duration, loc)
-}
+}

+ 15 - 12
src/llvm_backend.cpp

@@ -1825,25 +1825,28 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star
 		TEMPORARY_ALLOCATOR_GUARD();
 		auto args = array_make<lbValue>(temporary_allocator(), 1);
 		args[0] = lb_addr_load(p, all_tests_slice);
-		lb_emit_call(p, runner, args);
+		lbValue result = lb_emit_call(p, runner, args);
+
+		lbValue exit_runner = lb_find_package_value(m, str_lit("os"), str_lit("exit"));
+		auto exit_args = array_make<lbValue>(temporary_allocator(), 1);
+		exit_args[0] = lb_emit_select(p, result, lb_const_int(m, t_int, 0), lb_const_int(m, t_int, 1));
+		lb_emit_call(p, exit_runner, exit_args, ProcInlining_none);
 	} else {
 		if (m->info->entry_point != nullptr) {
 			lbValue entry_point = lb_find_procedure_value_from_entity(m, m->info->entry_point);
 			lb_emit_call(p, entry_point, {}, ProcInlining_no_inline);
 		}
-	}
-
-
-	if (call_cleanup) {
-		lbValue cleanup_runtime_value = {cleanup_runtime->value, cleanup_runtime->type};
-		lb_emit_call(p, cleanup_runtime_value, {}, ProcInlining_none);
-	}
 
+		if (call_cleanup) {
+			lbValue cleanup_runtime_value = {cleanup_runtime->value, cleanup_runtime->type};
+			lb_emit_call(p, cleanup_runtime_value, {}, ProcInlining_none);
+		}
 
-	if (is_dll_main) {
-		LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_i32), 1, false));
-	} else {
-		LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_i32), 0, false));
+		if (is_dll_main) {
+			LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_i32), 1, false));
+		} else {
+			LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_i32), 0, false));
+		}
 	}
 
 	lb_end_procedure_body(p);

+ 1 - 0
tests/issues/run.bat

@@ -14,6 +14,7 @@ set COMMON=-collection:tests=..\..
 ..\..\..\odin build ..\test_issue_2113.odin %COMMON% -file -debug || exit /b
 ..\..\..\odin test ..\test_issue_2466.odin %COMMON% -file || exit /b
 ..\..\..\odin test ..\test_issue_2615.odin %COMMON% -file || exit /b
+..\..\..\odin test ..\test_issue_2637.odin %COMMON% -file || exit /b
 
 @echo off
 

+ 1 - 0
tests/issues/run.sh

@@ -17,6 +17,7 @@ $ODIN test ../test_issue_2087.odin $COMMON -file
 $ODIN build ../test_issue_2113.odin $COMMON -file -debug
 $ODIN test ../test_issue_2466.odin $COMMON -file
 $ODIN test ../test_issue_2615.odin $COMMON -file
+$ODIN test ../test_issue_2637.odin $COMMON -file
 if [[ $($ODIN build ../test_issue_2395.odin $COMMON -file 2>&1 >/dev/null | grep -c "$NO_NIL_ERR") -eq 2 ]] ; then
 	echo "SUCCESSFUL 1/1"
 else

+ 13 - 0
tests/issues/test_issue_2637.odin

@@ -0,0 +1,13 @@
+// Tests issue #2637 https://github.com/odin-lang/Odin/issues/2637
+package test_issues
+
+import "core:testing"
+
+Foo :: Maybe(string)
+
+@(test)
+test_expect_value_succeeds_with_nil :: proc(t: ^testing.T) {
+  x: Foo
+  testing.expect(t, x == nil) // Succeeds
+  testing.expect_value(t, x, nil) // Fails, "expected nil, got nil"
+}

+ 1 - 1
vendor/ggpo/ggpo.odin

@@ -50,7 +50,7 @@ Player :: struct {
 	player_num: c.int,
 	using u: struct #raw_union {
 		local: struct {},
-		remove: struct {
+		remote: struct {
 			ip_address: [32]byte,
 			port: u16,
 		},

+ 1 - 1
vendor/raylib/raylib.odin

@@ -1133,7 +1133,7 @@ foreign lib {
 
 	SetGesturesEnabled     :: proc(flags: Gestures) ---          // Enable a set of gestures using flags
 	IsGestureDetected      :: proc(gesture: Gesture) -> bool --- // Check if a gesture have been detected
-	GetGestureDetected     :: proc() -> Gesture ---              // Get latest detected gesture
+	GetGestureDetected     :: proc() -> Gestures ---             // Get latest detected gesture
 	GetGestureHoldDuration :: proc() -> f32 ---                  // Get gesture hold time in milliseconds
 	GetGestureDragVector   :: proc() -> Vector2 ---              // Get gesture drag vector
 	GetGestureDragAngle    :: proc() -> f32 ---                  // Get gesture drag angle