Explorar o código

Merge remote-tracking branch 'live/master' into macharena

Colin Davidson hai 1 mes
pai
achega
b88f9194d0
Modificáronse 100 ficheiros con 569 adicións e 297 borrados
  1. 1 1
      .github/workflows/ci.yml
  2. 5 0
      .gitignore
  3. 1 1
      base/builtin/builtin.odin
  4. 5 0
      base/intrinsics/intrinsics.odin
  5. 4 1
      base/runtime/core.odin
  6. 1 1
      base/runtime/heap_allocator_unix.odin
  7. 1 0
      base/runtime/procs_darwin.odin
  8. 1 1
      core/c/libc/complex.odin
  9. 1 1
      core/c/libc/ctype.odin
  10. 1 1
      core/c/libc/errno.odin
  11. 1 1
      core/c/libc/locale.odin
  12. 1 1
      core/c/libc/math.odin
  13. 1 1
      core/c/libc/setjmp.odin
  14. 1 1
      core/c/libc/signal.odin
  15. 1 1
      core/c/libc/stdio.odin
  16. 1 1
      core/c/libc/stdlib.odin
  17. 1 1
      core/c/libc/string.odin
  18. 1 1
      core/c/libc/time.odin
  19. 1 1
      core/c/libc/uchar.odin
  20. 1 1
      core/c/libc/wchar.odin
  21. 1 1
      core/c/libc/wctype.odin
  22. 2 3
      core/crypto/hash/hash.odin
  23. 1 1
      core/hash/hash.odin
  24. 4 1
      core/mem/allocators.odin
  25. 2 2
      core/mem/virtual/virtual.odin
  26. 1 1
      core/net/interface_darwin.odin
  27. 20 17
      core/odin/parser/parser.odin
  28. 1 1
      core/os/os2/process_posix_darwin.odin
  29. 2 2
      core/os/os_darwin.odin
  30. 2 2
      core/os/os_freebsd.odin
  31. 2 2
      core/os/os_linux.odin
  32. 2 2
      core/os/os_netbsd.odin
  33. 2 2
      core/os/os_openbsd.odin
  34. 1 0
      core/path/filepath/match.odin
  35. 1 0
      core/path/filepath/walk.odin
  36. 51 0
      core/simd/simd.odin
  37. 1 1
      core/sync/futex_darwin.odin
  38. 1 1
      core/sync/primitives_darwin.odin
  39. 1 1
      core/sys/darwin/Foundation/NSBlock.odin
  40. 1 1
      core/sys/darwin/darwin.odin
  41. 1 1
      core/sys/darwin/mach_darwin.odin
  42. 1 1
      core/sys/darwin/proc.odin
  43. 5 15
      core/sys/darwin/sync.odin
  44. 1 1
      core/sys/info/platform_darwin.odin
  45. 1 1
      core/sys/kqueue/kqueue.odin
  46. 1 1
      core/sys/posix/arpa_inet.odin
  47. 1 1
      core/sys/posix/dirent.odin
  48. 1 1
      core/sys/posix/dlfcn.odin
  49. 1 1
      core/sys/posix/fcntl.odin
  50. 1 1
      core/sys/posix/fnmatch.odin
  51. 1 1
      core/sys/posix/glob.odin
  52. 1 1
      core/sys/posix/grp.odin
  53. 1 1
      core/sys/posix/langinfo.odin
  54. 1 1
      core/sys/posix/libgen.odin
  55. 1 1
      core/sys/posix/monetary.odin
  56. 1 1
      core/sys/posix/net_if.odin
  57. 1 1
      core/sys/posix/netdb.odin
  58. 1 1
      core/sys/posix/netinet_in.odin
  59. 1 1
      core/sys/posix/poll.odin
  60. 1 1
      core/sys/posix/pthread.odin
  61. 1 1
      core/sys/posix/pwd.odin
  62. 1 1
      core/sys/posix/sched.odin
  63. 1 1
      core/sys/posix/setjmp.odin
  64. 1 1
      core/sys/posix/signal.odin
  65. 1 1
      core/sys/posix/signal_libc.odin
  66. 1 1
      core/sys/posix/stdio.odin
  67. 1 1
      core/sys/posix/stdio_libc.odin
  68. 1 1
      core/sys/posix/stdlib.odin
  69. 1 1
      core/sys/posix/stdlib_libc.odin
  70. 1 1
      core/sys/posix/string.odin
  71. 1 1
      core/sys/posix/string_libc.odin
  72. 1 1
      core/sys/posix/sys_ipc.odin
  73. 1 1
      core/sys/posix/sys_mman.odin
  74. 1 1
      core/sys/posix/sys_msg.odin
  75. 1 1
      core/sys/posix/sys_resource.odin
  76. 1 1
      core/sys/posix/sys_select.odin
  77. 1 1
      core/sys/posix/sys_sem.odin
  78. 1 1
      core/sys/posix/sys_shm.odin
  79. 1 1
      core/sys/posix/sys_socket.odin
  80. 1 1
      core/sys/posix/sys_stat.odin
  81. 1 1
      core/sys/posix/sys_statvfs.odin
  82. 1 1
      core/sys/posix/sys_time.odin
  83. 1 1
      core/sys/posix/sys_times.odin
  84. 1 1
      core/sys/posix/sys_uio.odin
  85. 1 1
      core/sys/posix/sys_utsname.odin
  86. 1 1
      core/sys/posix/sys_wait.odin
  87. 1 1
      core/sys/posix/termios.odin
  88. 1 1
      core/sys/posix/time.odin
  89. 1 1
      core/sys/posix/ulimit.odin
  90. 1 1
      core/sys/posix/unistd.odin
  91. 1 1
      core/sys/posix/unistd_libc.odin
  92. 1 1
      core/sys/posix/utime.odin
  93. 1 1
      core/sys/posix/wordexp.odin
  94. 3 2
      core/sys/windows/ole32.odin
  95. 33 4
      core/sys/windows/util.odin
  96. 65 25
      src/build_settings.cpp
  97. 110 1
      src/check_builtin.cpp
  98. 102 94
      src/check_decl.cpp
  99. 65 46
      src/check_expr.cpp
  100. 4 0
      src/check_stmt.cpp

+ 1 - 1
.github/workflows/ci.yml

@@ -6,7 +6,7 @@ jobs:
     name: NetBSD Build, Check, and Test
     runs-on: ubuntu-latest
     env:
-      PKGSRC_BRANCH: 2024Q3
+      PKGSRC_BRANCH: 2025Q2
     steps:
     - uses: actions/checkout@v4
     - name: Build, Check, and Test

+ 5 - 0
.gitignore

@@ -297,3 +297,8 @@ build.sh
 *.rdi
 tests/issues/build/*
 misc/featuregen/featuregen
+
+# Clangd stuff
+.cache/
+.clangd
+compile_commands.json

+ 1 - 1
base/builtin/builtin.odin

@@ -145,7 +145,7 @@ ODIN_OS_STRING                  :: ODIN_OS_STRING
 
 /*
 	An `enum` value indicating the platform subtarget, chosen using the `-subtarget` switch.
-	Possible values are: `.Default` `.iOS`, and `.Android`.
+	Possible values are: `.Default` `.iPhone`, .iPhoneSimulator, and `.Android`.
 */
 ODIN_PLATFORM_SUBTARGET         :: ODIN_PLATFORM_SUBTARGET
 

+ 5 - 0
base/intrinsics/intrinsics.odin

@@ -213,6 +213,10 @@ type_is_subtype_of :: proc($T, $U: typeid) -> bool ---
 
 type_field_index_of :: proc($T: typeid, $name: string) -> uintptr ---
 
+// "Contiguous" means that the set of enum constants, when sorted, have a difference of either 0 or 1 between consecutive values.
+// This is the exact opposite of "sparse".
+type_enum_is_contiguous :: proc($T: typeid) -> bool where type_is_enum(T) ---
+
 type_equal_proc  :: proc($T: typeid) -> (equal:  proc "contextless" (rawptr, rawptr) -> bool)                 where type_is_comparable(T) ---
 type_hasher_proc :: proc($T: typeid) -> (hasher: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr) where type_is_comparable(T) ---
 
@@ -310,6 +314,7 @@ simd_indices :: proc($T: typeid/#simd[$N]$E) -> T where type_is_numeric(T) ---
 
 simd_shuffle :: proc(a, b: #simd[N]T, indices: ..int) -> #simd[len(indices)]T ---
 simd_select  :: proc(cond: #simd[N]boolean_or_integer, true, false: #simd[N]T) -> #simd[N]T ---
+simd_runtime_swizzle :: proc(table: #simd[N]T, indices: #simd[N]T) -> #simd[N]T where type_is_integer(T) ---
 
 // Lane-wise operations
 simd_ceil    :: proc(a: #simd[N]any_float) -> #simd[N]any_float ---

+ 4 - 1
base/runtime/core.odin

@@ -557,7 +557,8 @@ ALL_ODIN_OS_TYPES :: Odin_OS_Types{
 	// Defined internally by the compiler
 	Odin_Platform_Subtarget_Type :: enum int {
 		Default,
-		iOS,
+		iPhone,
+		iPhoneSimulator
 		Android,
 	}
 */
@@ -565,6 +566,8 @@ Odin_Platform_Subtarget_Type :: type_of(ODIN_PLATFORM_SUBTARGET)
 
 Odin_Platform_Subtarget_Types :: bit_set[Odin_Platform_Subtarget_Type]
 
+@(builtin)
+ODIN_PLATFORM_SUBTARGET_IOS :: ODIN_PLATFORM_SUBTARGET == .iPhone || ODIN_PLATFORM_SUBTARGET == .iPhoneSimulator
 
 /*
 	// Defined internally by the compiler

+ 1 - 1
base/runtime/heap_allocator_unix.odin

@@ -3,7 +3,7 @@
 package runtime
 
 when ODIN_OS == .Darwin {
-	foreign import libc "system:System.framework"
+	foreign import libc "system:System"
 } else {
 	foreign import libc "system:c"
 }

+ 1 - 0
base/runtime/procs_darwin.odin

@@ -31,5 +31,6 @@ foreign ObjC {
 	class_getInstanceVariable :: proc "c" (cls : objc_Class, name: cstring) -> objc_Ivar ---
 	class_getInstanceSize     :: proc "c" (cls : objc_Class) -> uint ---
 	ivar_getOffset            :: proc "c" (v: objc_Ivar) -> uintptr ---
+	object_getClass           :: proc "c" (obj: objc_id) -> objc_Class ---
 }
 

+ 1 - 1
core/c/libc/complex.odin

@@ -5,7 +5,7 @@ package libc
 when ODIN_OS == .Windows {
 	foreign import libc "system:libucrt.lib"
 } else when ODIN_OS == .Darwin {
-	foreign import libc "system:System.framework"
+	foreign import libc "system:System"
 } else {
 	foreign import libc "system:c"
 }

+ 1 - 1
core/c/libc/ctype.odin

@@ -3,7 +3,7 @@ package libc
 when ODIN_OS == .Windows {
 	foreign import libc "system:libucrt.lib"
 } else when ODIN_OS == .Darwin {
-	foreign import libc "system:System.framework"
+	foreign import libc "system:System"
 } else {
 	foreign import libc "system:c"
 }

+ 1 - 1
core/c/libc/errno.odin

@@ -5,7 +5,7 @@ package libc
 when ODIN_OS == .Windows {
 	foreign import libc "system:libucrt.lib"
 } else when ODIN_OS == .Darwin {
-	foreign import libc "system:System.framework"
+	foreign import libc "system:System"
 } else {
 	foreign import libc "system:c"
 }

+ 1 - 1
core/c/libc/locale.odin

@@ -5,7 +5,7 @@ import "core:c"
 when ODIN_OS == .Windows {
 	foreign import libc "system:libucrt.lib"
 } else when ODIN_OS == .Darwin {
-	foreign import libc "system:System.framework"
+	foreign import libc "system:System"
 } else {
 	foreign import libc "system:c"
 }

+ 1 - 1
core/c/libc/math.odin

@@ -7,7 +7,7 @@ import "base:intrinsics"
 when ODIN_OS == .Windows {
 	foreign import libc "system:libucrt.lib"
 } else when ODIN_OS == .Darwin {
-	foreign import libc "system:System.framework"
+	foreign import libc "system:System"
 } else {
 	foreign import libc "system:c"
 }

+ 1 - 1
core/c/libc/setjmp.odin

@@ -5,7 +5,7 @@ package libc
 when ODIN_OS == .Windows {
 	foreign import libc "system:libucrt.lib"
 } else when ODIN_OS == .Darwin {
-	foreign import libc "system:System.framework"
+	foreign import libc "system:System"
 } else {
 	foreign import libc "system:c"
 }

+ 1 - 1
core/c/libc/signal.odin

@@ -5,7 +5,7 @@ package libc
 when ODIN_OS == .Windows {
 	foreign import libc "system:libucrt.lib"
 } else when ODIN_OS == .Darwin {
-	foreign import libc "system:System.framework"
+	foreign import libc "system:System"
 } else {
 	foreign import libc "system:c"
 }

+ 1 - 1
core/c/libc/stdio.odin

@@ -9,7 +9,7 @@ when ODIN_OS == .Windows {
 		"system:legacy_stdio_definitions.lib",
 	}
 } else when ODIN_OS == .Darwin {
-	foreign import libc "system:System.framework"
+	foreign import libc "system:System"
 } else {
 	foreign import libc "system:c"
 }

+ 1 - 1
core/c/libc/stdlib.odin

@@ -5,7 +5,7 @@ package libc
 when ODIN_OS == .Windows {
 	foreign import libc "system:libucrt.lib"
 } else when ODIN_OS == .Darwin {
-	foreign import libc "system:System.framework"
+	foreign import libc "system:System"
 } else {
 	foreign import libc "system:c"
 }

+ 1 - 1
core/c/libc/string.odin

@@ -7,7 +7,7 @@ import "base:runtime"
 when ODIN_OS == .Windows {
 	foreign import libc "system:libucrt.lib"
 } else when ODIN_OS == .Darwin {
-	foreign import libc "system:System.framework"
+	foreign import libc "system:System"
 } else {
 	foreign import libc "system:c"
 }

+ 1 - 1
core/c/libc/time.odin

@@ -5,7 +5,7 @@ package libc
 when ODIN_OS == .Windows {
 	foreign import libc "system:libucrt.lib"
 } else when ODIN_OS == .Darwin {
-	foreign import libc "system:System.framework"
+	foreign import libc "system:System"
 } else {
 	foreign import libc "system:c"
 }

+ 1 - 1
core/c/libc/uchar.odin

@@ -5,7 +5,7 @@ package libc
 when ODIN_OS == .Windows {
 	foreign import libc "system:libucrt.lib"
 } else when ODIN_OS == .Darwin {
-	foreign import libc "system:System.framework"
+	foreign import libc "system:System"
 } else {
 	foreign import libc "system:c"
 }

+ 1 - 1
core/c/libc/wchar.odin

@@ -5,7 +5,7 @@ package libc
 when ODIN_OS == .Windows {
 	foreign import libc "system:libucrt.lib"
 } else when ODIN_OS == .Darwin {
-	foreign import libc "system:System.framework"
+	foreign import libc "system:System"
 } else {
 	foreign import libc "system:c"
 }

+ 1 - 1
core/c/libc/wctype.odin

@@ -5,7 +5,7 @@ package libc
 when ODIN_OS == .Windows {
 	foreign import libc "system:libucrt.lib"
 } else when ODIN_OS == .Darwin {
-	foreign import libc "system:System.framework"
+	foreign import libc "system:System"
 } else {
 	foreign import libc "system:c"
 }

+ 2 - 3
core/crypto/hash/hash.odin

@@ -21,8 +21,7 @@ hash_string :: proc(algorithm: Algorithm, data: string, allocator := context.all
 // in a newly allocated slice.
 hash_bytes :: proc(algorithm: Algorithm, data: []byte, allocator := context.allocator) -> []byte {
 	dst := make([]byte, DIGEST_SIZES[algorithm], allocator)
-	hash_bytes_to_buffer(algorithm, data, dst)
-	return dst
+	return hash_bytes_to_buffer(algorithm, data, dst)
 }
 
 // hash_string_to_buffer will hash the given input and assign the
@@ -46,7 +45,7 @@ hash_bytes_to_buffer :: proc(algorithm: Algorithm, data, hash: []byte) -> []byte
 	update(&ctx, data)
 	final(&ctx, hash)
 
-	return hash
+	return hash[:DIGEST_SIZES[algorithm]]
 }
 
 // hash_stream will incrementally fully consume a stream, and return the

+ 1 - 1
core/hash/hash.odin

@@ -127,7 +127,7 @@ jenkins :: proc "contextless" (data: []byte, seed := u32(0)) -> u32 {
 }
 
 @(optimization_mode="favor_size")
-murmur32 :: proc "contextless" (data: []byte, seed := u32(0)) -> u32 {
+murmur32 :: proc "contextless" (data: []byte, seed := u32(0x9747b28c)) -> u32 {
 	c1_32: u32 : 0xcc9e2d51
 	c2_32: u32 : 0x1b873593
 

+ 4 - 1
core/mem/allocators.odin

@@ -2223,6 +2223,9 @@ Initialize a buddy allocator.
 
 This procedure initializes the buddy allocator `b` with a backing buffer `data`
 and block alignment specified by `alignment`.
+
+`alignment` may be any power of two, but the backing buffer must be aligned to
+at least `size_of(Buddy_Block)`.
 */
 buddy_allocator_init :: proc(b: ^Buddy_Allocator, data: []byte, alignment: uint, loc := #caller_location) {
 	assert(data != nil)
@@ -2233,7 +2236,7 @@ buddy_allocator_init :: proc(b: ^Buddy_Allocator, data: []byte, alignment: uint,
 		alignment = size_of(Buddy_Block)
 	}
 	ptr := raw_data(data)
-	assert(uintptr(ptr) % uintptr(alignment) == 0, "data is not aligned to minimum alignment", loc)
+	assert(uintptr(ptr) % uintptr(alignment) == 0, "The data is not aligned to the minimum alignment, which must be at least `size_of(Buddy_Block)`.", loc)
 	b.head = (^Buddy_Block)(ptr)
 	b.head.size = len(data)
 	b.head.is_free = true

+ 2 - 2
core/mem/virtual/virtual.odin

@@ -89,8 +89,8 @@ memory_block_alloc :: proc(committed, reserved: uint, alignment: uint = 0, flags
 	reserved  = align_formula(reserved, page_size)
 	committed = clamp(committed, 0, reserved)
 	
-	total_size     := uint(reserved + max(alignment, size_of(Platform_Memory_Block)))
-	base_offset    := uintptr(max(alignment, size_of(Platform_Memory_Block)))
+	total_size     := reserved + alignment + size_of(Platform_Memory_Block)
+	base_offset    := mem.align_forward_uintptr(size_of(Platform_Memory_Block), max(uintptr(alignment), align_of(Platform_Memory_Block)))
 	protect_offset := uintptr(0)
 	
 	do_protection := false

+ 1 - 1
core/net/interface_darwin.odin

@@ -23,7 +23,7 @@ package net
 import "core:strings"
 import "core:sys/posix"
 
-foreign import lib "system:System.framework"
+foreign import lib "system:System"
 
 @(private)
 _enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Interfaces_Error) {

+ 20 - 17
core/odin/parser/parser.odin

@@ -348,27 +348,30 @@ consume_comment_group :: proc(p: ^Parser, n: int) -> (comments: ^ast.Comment_Gro
 }
 
 consume_comment_groups :: proc(p: ^Parser, prev: tokenizer.Token) {
-	if p.curr_tok.kind == .Comment {
-		comment: ^ast.Comment_Group
-		end_line := 0
-
-		if p.curr_tok.pos.line == prev.pos.line {
-			comment, end_line = consume_comment_group(p, 0)
-			if p.curr_tok.pos.line != end_line || p.curr_tok.kind == .EOF {
-				p.line_comment = comment
-			}
-		}
+	if p.curr_tok.kind != .Comment {
+		return
+	}
+	comment: ^ast.Comment_Group
+	end_line := 0
 
-		end_line = -1
-		for p.curr_tok.kind == .Comment {
-			comment, end_line = consume_comment_group(p, 1)
-		}
-		if end_line+1 >= p.curr_tok.pos.line || end_line < 0 {
-			p.lead_comment = comment
+	if p.curr_tok.pos.line == prev.pos.line {
+		comment, end_line = consume_comment_group(p, 0)
+		if p.curr_tok.pos.line != end_line ||
+		   p.curr_tok.pos.line == prev.pos.line+1 ||
+		   p.curr_tok.kind == .EOF {
+			p.line_comment = comment
 		}
+	}
 
-		assert(p.curr_tok.kind != .Comment)
+	end_line = -1
+	for p.curr_tok.kind == .Comment {
+		comment, end_line = consume_comment_group(p, 1)
 	}
+	if end_line+1 >= p.curr_tok.pos.line || end_line < 0 {
+		p.lead_comment = comment
+	}
+
+	assert(p.curr_tok.kind != .Comment)
 }
 
 advance_token :: proc(p: ^Parser) -> tokenizer.Token {

+ 1 - 1
core/os/os2/process_posix_darwin.odin

@@ -10,7 +10,7 @@ import "core:sys/posix"
 import "core:sys/unix"
 import "core:time"
 
-foreign import lib "system:System.framework"
+foreign import lib "system:System"
 
 foreign lib {
 	sysctl :: proc(

+ 2 - 2
core/os/os_darwin.odin

@@ -1,8 +1,8 @@
 package os
 
 foreign import dl   "system:dl"
-foreign import libc "system:System.framework"
-foreign import pthread "system:System.framework"
+foreign import libc "system:System"
+foreign import pthread "system:System"
 
 import "base:runtime"
 import "core:strings"

+ 2 - 2
core/os/os_freebsd.odin

@@ -967,8 +967,8 @@ _processor_core_count :: proc() -> int {
 @(private, require_results)
 _alloc_command_line_arguments :: proc() -> []string {
 	res := make([]string, len(runtime.args__))
-	for arg, i in runtime.args__ {
-		res[i] = string(arg)
+	for _, i in res {
+		res[i] = string(runtime.args__[i])
 	}
 	return res
 }

+ 2 - 2
core/os/os_linux.odin

@@ -1100,8 +1100,8 @@ _processor_core_count :: proc() -> int {
 @(private, require_results)
 _alloc_command_line_arguments :: proc() -> []string {
 	res := make([]string, len(runtime.args__))
-	for arg, i in runtime.args__ {
-		res[i] = string(arg)
+	for _, i in  res {
+		res[i] = string(runtime.args__[i])
 	}
 	return res
 }

+ 2 - 2
core/os/os_netbsd.odin

@@ -1017,8 +1017,8 @@ _processor_core_count :: proc() -> int {
 @(private, require_results)
 _alloc_command_line_arguments :: proc() -> []string {
 	res := make([]string, len(runtime.args__))
-	for arg, i in runtime.args__ {
-		res[i] = string(arg)
+	for _, i in res {
+		res[i] = string(runtime.args__[i])
 	}
 	return res
 }

+ 2 - 2
core/os/os_openbsd.odin

@@ -917,8 +917,8 @@ _processor_core_count :: proc() -> int {
 @(private, require_results)
 _alloc_command_line_arguments :: proc() -> []string {
 	res := make([]string, len(runtime.args__))
-	for arg, i in runtime.args__ {
-		res[i] = string(arg)
+	for _, i in res {
+		res[i] = string(runtime.args__[i])
 	}
 	return res
 }

+ 1 - 0
core/path/filepath/match.odin

@@ -1,4 +1,5 @@
 #+build !wasi
+#+build !js
 package filepath
 
 import "core:os"

+ 1 - 0
core/path/filepath/walk.odin

@@ -1,4 +1,5 @@
 #+build !wasi
+#+build !js
 package filepath
 
 import "core:os"

+ 51 - 0
core/simd/simd.odin

@@ -2440,6 +2440,57 @@ Graphically, the operation looks as follows. The `t` and `f` represent the
 */
 select :: intrinsics.simd_select
 
+/*
+Runtime Equivalent to Shuffle.
+
+Performs element-wise table lookups using runtime indices.
+Each element in the indices vector selects an element from the table vector.
+The indices are automatically masked to prevent out-of-bounds access.
+
+This operation is hardware-accelerated on most platforms when using 8-bit
+integer vectors. For other element types or unsupported vector sizes, it
+falls back to software emulation.
+
+Inputs:
+- `table`: The lookup table vector (should be power-of-2 size for correct masking).
+- `indices`: The indices vector (automatically masked to valid range).
+
+Returns:
+- A vector where `result[i] = table[indices[i] & (table_size-1)]`.
+
+Operation:
+
+	for i in 0 ..< len(indices) {
+		masked_index := indices[i] & (len(table) - 1)
+		result[i] = table[masked_index]
+	}
+	return result
+
+Implementation:
+
+	| Platform    | Lane Size                                 | Implementation      |
+	|-------------|-------------------------------------------|---------------------|
+	| x86-64      | pshufb (16B), vpshufb (32B), AVX512 (64B) | Single vector       |
+	| ARM64       | tbl1 (16B), tbl2 (32B), tbl4 (64B)        | Automatic splitting |
+	| ARM32       | vtbl1 (8B), vtbl2 (16B), vtbl4 (32B)      | Automatic splitting |
+	| WebAssembly | i8x16.swizzle (16B), Emulation (>16B)     | Mixed               |
+	| Other       | Emulation                                 | Software            |
+
+Example:
+
+	import "core:simd"
+	import "core:fmt"
+
+	runtime_swizzle_example :: proc() {
+		table := simd.u8x16{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
+		indices := simd.u8x16{15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
+		result := simd.runtime_swizzle(table, indices)
+		fmt.println(result) // Expected: {15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
+	}
+
+*/
+runtime_swizzle :: intrinsics.simd_runtime_swizzle
+
 /*
 Compute the square root of each lane in a SIMD vector.
 */

+ 1 - 1
core/sync/futex_darwin.odin

@@ -6,7 +6,7 @@ import "core:c"
 import "core:sys/darwin"
 import "core:time"
 
-foreign import System "system:System.framework"
+foreign import System "system:System"
 
 foreign System {
 	// __ulock_wait is not available on 10.15

+ 1 - 1
core/sync/primitives_darwin.odin

@@ -5,7 +5,7 @@ package sync
 import "core:c"
 import "base:intrinsics"
 
-foreign import pthread "system:System.framework"
+foreign import pthread "system:System"
 
 _current_thread_id :: proc "contextless" () -> int {
 	tid: u64

+ 1 - 1
core/sys/darwin/Foundation/NSBlock.odin

@@ -62,7 +62,7 @@ global_block_descriptor := Block_Descriptor{
 	size     = size_of(Internal_Block_Literal),
 }
 
-foreign import libSystem "system:System.framework"
+foreign import libSystem "system:System"
 foreign libSystem {
 	_NSConcreteGlobalBlock: intrinsics.objc_class
 	_NSConcreteStackBlock: intrinsics.objc_class

+ 1 - 1
core/sys/darwin/darwin.odin

@@ -4,7 +4,7 @@ package darwin
 import "core:c"
 
 @(export)
-foreign import system "system:System.framework"
+foreign import system "system:System"
 
 Bool :: b8
 

+ 1 - 1
core/sys/darwin/mach_darwin.odin

@@ -1,6 +1,6 @@
 package darwin
 
-foreign import mach "system:System.framework"
+foreign import mach "system:System"
 
 import "core:c"
 import "base:intrinsics"

+ 1 - 1
core/sys/darwin/proc.odin

@@ -4,7 +4,7 @@ import "base:intrinsics"
 
 import "core:sys/posix"
 
-foreign import lib "system:System.framework"
+foreign import lib "system:System"
 
 // Incomplete bindings to the proc API on MacOS, add to when needed.
 

+ 5 - 15
core/sys/darwin/sync.odin

@@ -3,23 +3,13 @@ package darwin
 // #define OS_WAIT_ON_ADDR_AVAILABILITY \
 // 	__API_AVAILABLE(macos(14.4), ios(17.4), tvos(17.4), watchos(10.4))
 when ODIN_OS == .Darwin {
-
-	when ODIN_PLATFORM_SUBTARGET == .iOS && ODIN_MINIMUM_OS_VERSION >= 17_04_00 {
-		WAIT_ON_ADDRESS_AVAILABLE :: true
-	} else when ODIN_MINIMUM_OS_VERSION >= 14_04_00 {
-		WAIT_ON_ADDRESS_AVAILABLE :: true
+	when ODIN_PLATFORM_SUBTARGET_IOS {
+		WAIT_ON_ADDRESS_AVAILABLE :: ODIN_MINIMUM_OS_VERSION >= 17_04_00
+		ULOCK_WAIT_2_AVAILABLE    :: ODIN_MINIMUM_OS_VERSION >= 14_00_00
 	} else {
-		WAIT_ON_ADDRESS_AVAILABLE :: false
+		WAIT_ON_ADDRESS_AVAILABLE :: ODIN_MINIMUM_OS_VERSION >= 14_04_00
+		ULOCK_WAIT_2_AVAILABLE    :: ODIN_MINIMUM_OS_VERSION >= 11_00_00
 	}
-
-	when ODIN_PLATFORM_SUBTARGET == .iOS && ODIN_MINIMUM_OS_VERSION >= 14_00_00 {
-		ULOCK_WAIT_2_AVAILABLE :: true
-	} else when ODIN_MINIMUM_OS_VERSION >= 11_00_00 {
-		ULOCK_WAIT_2_AVAILABLE :: true
-	} else {
-		ULOCK_WAIT_2_AVAILABLE :: false
-	}
-
 } else {
 	WAIT_ON_ADDRESS_AVAILABLE :: false
 	ULOCK_WAIT_2_AVAILABLE    :: false

+ 1 - 1
core/sys/info/platform_darwin.odin

@@ -28,7 +28,7 @@ init_platform :: proc() {
 
 	macos_version = {int(version.majorVersion), int(version.minorVersion), int(version.patchVersion)}
 
-	when ODIN_PLATFORM_SUBTARGET == .iOS {
+	when ODIN_PLATFORM_SUBTARGET_IOS {
 		os_version.platform = .iOS
 		ws(&b, "iOS")
 	} else {

+ 1 - 1
core/sys/kqueue/kqueue.odin

@@ -2,7 +2,7 @@
 package kqueue
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/arpa_inet.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else when ODIN_OS == .Haiku {
 	foreign import lib "system:network"
 } else {

+ 1 - 1
core/sys/posix/dirent.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/dlfcn.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD {
 	foreign import lib "system:dl"
 } else {

+ 1 - 1
core/sys/posix/fcntl.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/fnmatch.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/glob.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/grp.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/langinfo.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/libgen.odin

@@ -2,7 +2,7 @@
 package posix
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/monetary.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/net_if.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/netdb.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/netinet_in.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/poll.odin

@@ -6,7 +6,7 @@ import "base:intrinsics"
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/pthread.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .Linux {
 	foreign import lib "system:pthread"
 } else {

+ 1 - 1
core/sys/posix/pwd.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/sched.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/setjmp.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/signal.odin

@@ -6,7 +6,7 @@ import "base:intrinsics"
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/signal_libc.odin

@@ -9,7 +9,7 @@ import "core:c/libc"
 when ODIN_OS == .Windows {
 	foreign import lib "system:libucrt.lib"
 } else when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/stdio.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/stdio_libc.odin

@@ -10,7 +10,7 @@ when ODIN_OS == .Windows {
 		"system:legacy_stdio_definitions.lib",
 	}
 } else when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/stdlib.odin

@@ -6,7 +6,7 @@ import "base:intrinsics"
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/stdlib_libc.odin

@@ -9,7 +9,7 @@ import "core:c/libc"
 when ODIN_OS == .Windows {
 	foreign import lib "system:libucrt.lib"
 } else when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/string.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/string_libc.odin

@@ -4,7 +4,7 @@ package posix
 when ODIN_OS == .Windows {
 	foreign import lib "system:libucrt.lib"
 } else when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/sys_ipc.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/sys_mman.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/sys_msg.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/sys_resource.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/sys_select.odin

@@ -6,7 +6,7 @@ import "base:intrinsics"
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/sys_sem.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/sys_shm.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/sys_socket.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import libc "system:System.framework"
+	foreign import libc "system:System"
 } else {
 	foreign import libc "system:c"
 }

+ 1 - 1
core/sys/posix/sys_stat.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/sys_statvfs.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/sys_time.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/sys_times.odin

@@ -2,7 +2,7 @@
 package posix
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/sys_uio.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import libc "system:System.framework"
+	foreign import libc "system:System"
 } else {
 	foreign import libc "system:c"
 }

+ 1 - 1
core/sys/posix/sys_utsname.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/sys_wait.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/termios.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/time.odin

@@ -5,7 +5,7 @@ import "core:c"
 import "core:c/libc"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/ulimit.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/unistd.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/unistd_libc.odin

@@ -6,7 +6,7 @@ import "core:c"
 when ODIN_OS == .Windows {
 	foreign import lib "system:libucrt.lib"
 } else when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/utime.odin

@@ -2,7 +2,7 @@
 package posix
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 1 - 1
core/sys/posix/wordexp.odin

@@ -4,7 +4,7 @@ package posix
 import "core:c"
 
 when ODIN_OS == .Darwin {
-	foreign import lib "system:System.framework"
+	foreign import lib "system:System"
 } else {
 	foreign import lib "system:c"
 }

+ 3 - 2
core/sys/windows/ole32.odin

@@ -25,11 +25,12 @@ COINIT :: enum DWORD {
 	SPEED_OVER_MEMORY = 0x8,
 }
 
+IUnknown_UUID_STRING :: "00000000-0000-0000-C000-000000000046"
+IUnknown_UUID := &IID{0x00000000, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}
+IUnknownVtbl :: IUnknown_VTable
 IUnknown :: struct {
 	using _iunknown_vtable: ^IUnknown_VTable,
 }
-
-IUnknownVtbl :: IUnknown_VTable
 IUnknown_VTable :: struct {
 	QueryInterface: proc "system" (This: ^IUnknown, riid: REFIID, ppvObject: ^rawptr) -> HRESULT,
 	AddRef:         proc "system" (This: ^IUnknown) -> ULONG,

+ 33 - 4
core/sys/windows/util.odin

@@ -170,15 +170,15 @@ wstring_to_utf8_alloc :: proc(s: wstring, N: int, allocator := context.temp_allo
 	return string(text[:n]), nil
 }
 
-wstring_to_utf8_buf :: proc(buf: []u8, s: wstring) -> (res: string) {
-	n := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, -1, nil, 0, nil, nil)
+wstring_to_utf8_buf :: proc(buf: []u8, s: wstring, N := -1) -> (res: string) {
+	n := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, i32(N), nil, 0, nil, nil)
 	if n == 0 {
 		return
 	} else if int(n) > len(buf) {
 		return
 	}
 
-	n2 := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, -1, raw_data(buf), n, nil, nil)
+	n2 := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, i32(N), raw_data(buf), n, nil, nil)
 	if n2 == 0 {
 		return
 	} else if int(n2) > len(buf) {
@@ -196,6 +196,21 @@ wstring_to_utf8_buf :: proc(buf: []u8, s: wstring) -> (res: string) {
 
 wstring_to_utf8 :: proc{wstring_to_utf8_alloc, wstring_to_utf8_buf}
 
+/*
+Converts a UTF-16 string into a regular UTF-8 `string` and allocates the result.
+If the input is null-terminated, only the part of the input string leading up
+to it will be converted.
+
+*Allocates Using Provided Allocator*
+
+Inputs:
+- s: The string to be converted
+- allocator: (default: context.allocator)
+
+Returns:
+- res: A cloned and converted string
+- err: An optional allocator error if one occured, `nil` otherwise
+*/
 utf16_to_utf8_alloc :: proc(s: []u16, allocator := context.temp_allocator) -> (res: string, err: runtime.Allocator_Error) {
 	if len(s) == 0 {
 		return "", nil
@@ -203,11 +218,25 @@ utf16_to_utf8_alloc :: proc(s: []u16, allocator := context.temp_allocator) -> (r
 	return wstring_to_utf8(raw_data(s), len(s), allocator)
 }
 
+/*
+Converts a UTF-16 string into a regular UTF-8 `string`, using `buf` as its backing.
+If the input is null-terminated, only the part of the input string leading up
+to it will be converted.
+
+*Uses `buf` for backing*
+
+Inputs:
+- s: The string to be converted
+- buf: Backing buffer for result string
+
+Returns:
+- res: A converted string, backed byu `buf`
+*/
 utf16_to_utf8_buf :: proc(buf: []u8, s: []u16) -> (res: string) {
 	if len(s) == 0 {
 		return
 	}
-	return wstring_to_utf8(buf, raw_data(s))
+	return wstring_to_utf8(buf, raw_data(s), len(s))
 }
 
 utf16_to_utf8 :: proc{utf16_to_utf8_alloc, utf16_to_utf8_buf}

+ 65 - 25
src/build_settings.cpp

@@ -171,15 +171,18 @@ struct TargetMetrics {
 
 enum Subtarget : u32 {
 	Subtarget_Default,
-	Subtarget_iOS,
+	Subtarget_iPhone,
+	Subtarget_iPhoneSimulator,
 	Subtarget_Android,
-
+	
 	Subtarget_COUNT,
+	Subtarget_Invalid,    // NOTE(harold): Must appear after _COUNT as this is not a real subtarget
 };
 
 gb_global String subtarget_strings[Subtarget_COUNT] = {
 	str_lit(""),
-	str_lit("ios"),
+	str_lit("iphone"),
+	str_lit("iphonesimulator"),
 	str_lit("android"),
 };
 
@@ -306,6 +309,7 @@ enum VetFlags : u64 {
 	VetFlag_Cast            = 1u<<8,
 	VetFlag_Tabs            = 1u<<9,
 	VetFlag_UnusedProcedures = 1u<<10,
+	VetFlag_ExplicitAllocators = 1u<<11,
 
 	VetFlag_Unused = VetFlag_UnusedVariables|VetFlag_UnusedImports,
 
@@ -339,6 +343,8 @@ u64 get_vet_flag_from_name(String const &name) {
 		return VetFlag_Tabs;
 	} else if (name == "unused-procedures") {
 		return VetFlag_UnusedProcedures;
+	} else if (name == "explicit-allocators") {
+		return VetFlag_ExplicitAllocators;
 	}
 	return VetFlag_NONE;
 }
@@ -857,7 +863,7 @@ gb_global NamedTargetMetrics *selected_target_metrics;
 gb_global Subtarget selected_subtarget;
 
 
-gb_internal TargetOsKind get_target_os_from_string(String str, Subtarget *subtarget_ = nullptr) {
+gb_internal TargetOsKind get_target_os_from_string(String str, Subtarget *subtarget_ = nullptr, String *subtarget_str = nullptr) {
 	String os_name = str;
 	String subtarget = {};
 	auto part = string_partition(str, str_lit(":"));
@@ -874,18 +880,26 @@ gb_internal TargetOsKind get_target_os_from_string(String str, Subtarget *subtar
 			break;
 		}
 	}
-	if (subtarget_) *subtarget_ = Subtarget_Default;
 
-	if (subtarget.len != 0) {
-		if (str_eq_ignore_case(subtarget, "generic") || str_eq_ignore_case(subtarget, "default")) {
-			if (subtarget_) *subtarget_ = Subtarget_Default;
-		} else {
-			for (isize i = 1; i < Subtarget_COUNT; i++) {
-				if (str_eq_ignore_case(subtarget_strings[i], subtarget)) {
-					if (subtarget_) *subtarget_ = cast(Subtarget)i;
-					break;
+	if (subtarget_str) *subtarget_str = subtarget;
+
+	if (subtarget_) {
+		if (subtarget.len != 0) {
+			*subtarget_ = Subtarget_Invalid;
+
+			if (str_eq_ignore_case(subtarget, "generic") || str_eq_ignore_case(subtarget, "default")) {
+				*subtarget_ = Subtarget_Default;
+				
+			} else {
+				for (isize i = 1; i < Subtarget_COUNT; i++) {
+					if (str_eq_ignore_case(subtarget_strings[i], subtarget)) {
+						*subtarget_ = cast(Subtarget)i;
+						break;
+					}
 				}
 			}
+		} else {
+			*subtarget_ = Subtarget_Default;
 		}
 	}
 
@@ -1824,16 +1838,29 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
 		}
 	}
 
-	if (metrics->os == TargetOs_darwin && subtarget == Subtarget_iOS) {
-		switch (metrics->arch) {
-		case TargetArch_arm64:
-			bc->metrics.target_triplet = str_lit("arm64-apple-ios");
-			break;
-		case TargetArch_amd64:
-			bc->metrics.target_triplet = str_lit("x86_64-apple-ios");
-			break;
-		default:
-			GB_PANIC("Unknown architecture for darwin");
+	if (metrics->os == TargetOs_darwin) {
+		switch (subtarget) {
+			case Subtarget_iPhone:
+				switch (metrics->arch) {
+				case TargetArch_arm64:
+					bc->metrics.target_triplet = str_lit("arm64-apple-ios");
+					break;
+				default:
+					GB_PANIC("Unknown architecture for -subtarget:iphone");
+				}
+				break;
+			case Subtarget_iPhoneSimulator:
+				switch (metrics->arch) {
+				case TargetArch_arm64:
+					bc->metrics.target_triplet = str_lit("arm64-apple-ios-simulator");
+					break;
+				case TargetArch_amd64:
+					bc->metrics.target_triplet = str_lit("x86_64-apple-ios-simulator");
+					break;
+				default:
+					GB_PANIC("Unknown architecture for -subtarget:iphonesimulator");
+				}
+				break;
 		}
 	} else if (metrics->os == TargetOs_linux && subtarget == Subtarget_Android) {
 		switch (metrics->arch) {
@@ -1892,10 +1919,23 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
 	// does not annoy the user with version warnings.
 	if (metrics->os == TargetOs_darwin) {
 		if (!bc->minimum_os_version_string_given) {
-			bc->minimum_os_version_string = str_lit("11.0.0");
+			if (subtarget == Subtarget_Default) {
+				bc->minimum_os_version_string = str_lit("11.0.0");
+			} else if (subtarget == Subtarget_iPhone || subtarget == Subtarget_iPhoneSimulator) {
+				// NOTE(harold): We default to 17.4 on iOS because that's when os_sync_wait_on_address was added and
+				//               we'd like to avoid any potential App Store issues by using the private ulock_* there.
+				bc->minimum_os_version_string = str_lit("17.4");
+			}
 		}
 
-		if (subtarget == Subtarget_Default) {
+		if (subtarget == Subtarget_iPhoneSimulator) {
+			// For the iPhoneSimulator subtarget, the version must be between 'ios' and '-simulator'.
+			String suffix = str_lit("-simulator");
+			GB_ASSERT(string_ends_with(bc->metrics.target_triplet, suffix));
+
+			String prefix = substring(bc->metrics.target_triplet, 0, bc->metrics.target_triplet.len - suffix.len);
+			bc->metrics.target_triplet = concatenate3_strings(permanent_allocator(), prefix, bc->minimum_os_version_string, suffix);
+		} else {
 			bc->metrics.target_triplet = concatenate_strings(permanent_allocator(), bc->metrics.target_triplet, bc->minimum_os_version_string);
 		}
 	} else if (selected_subtarget == Subtarget_Android) {

+ 110 - 1
src/check_builtin.cpp

@@ -1,5 +1,14 @@
 typedef bool (BuiltinTypeIsProc)(Type *t);
 
+gb_internal int enum_constant_entity_cmp(void const* a, void const* b) {
+	Entity const *ea = *(cast(Entity const **)a);
+	Entity const *eb = *(cast(Entity const **)b);
+	GB_ASSERT(ea->kind == Entity_Constant && eb->kind == Entity_Constant);
+	GB_ASSERT(ea->Constant.value.kind == ExactValue_Integer && eb->Constant.value.kind == ExactValue_Integer);
+	
+	return big_int_cmp(&ea->Constant.value.value_integer, &eb->Constant.value.value_integer);
+}
+
 gb_global BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_boolean_end - BuiltinProc__type_simple_boolean_begin] = {
 	nullptr, // BuiltinProc__type_simple_boolean_begin
 
@@ -1150,6 +1159,58 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan
 			return true;
 		}
 
+	case BuiltinProc_simd_runtime_swizzle:
+		{
+			if (ce->args.count != 2) {
+				error(call, "'%.*s' expected 2 arguments, got %td", LIT(builtin_name), ce->args.count);
+				return false;
+			}
+			
+			Operand src = {};
+			Operand indices = {};
+			check_expr(c, &src, ce->args[0]); if (src.mode == Addressing_Invalid) return false;
+			check_expr_with_type_hint(c, &indices, ce->args[1], src.type); if (indices.mode == Addressing_Invalid) return false;
+			
+			if (!is_type_simd_vector(src.type)) {
+				error(src.expr, "'%.*s' expected first argument to be a simd vector", LIT(builtin_name));
+				return false;
+			}
+			if (!is_type_simd_vector(indices.type)) {
+				error(indices.expr, "'%.*s' expected second argument (indices) to be a simd vector", LIT(builtin_name));
+				return false;
+			}
+			
+			Type *src_elem = base_array_type(src.type);
+			Type *indices_elem = base_array_type(indices.type);
+			
+			if (!is_type_integer(src_elem)) {
+				gbString src_str = type_to_string(src.type);
+				error(src.expr, "'%.*s' expected first argument to be a simd vector of integers, got '%s'", LIT(builtin_name), src_str);
+				gb_string_free(src_str);
+				return false;
+			}
+			
+			if (!is_type_integer(indices_elem)) {
+				gbString indices_str = type_to_string(indices.type);
+				error(indices.expr, "'%.*s' expected indices to be a simd vector of integers, got '%s'", LIT(builtin_name), indices_str);
+				gb_string_free(indices_str);
+				return false;
+			}
+			
+			if (!are_types_identical(src.type, indices.type)) {
+				gbString src_str = type_to_string(src.type);
+				gbString indices_str = type_to_string(indices.type);
+				error(indices.expr, "'%.*s' expected both arguments to have the same type, got '%s' vs '%s'", LIT(builtin_name), src_str, indices_str);
+				gb_string_free(indices_str);
+				gb_string_free(src_str);
+				return false;
+			}
+			
+			operand->mode = Addressing_Value;
+			operand->type = src.type;
+			return true;
+		}
+
 	case BuiltinProc_simd_ceil:
 	case BuiltinProc_simd_floor:
 	case BuiltinProc_simd_trunc:
@@ -2324,7 +2385,11 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
 
 		if (mode == Addressing_Invalid) {
 			gbString t = type_to_string(operand->type);
-			error(call, "'%.*s' is not supported for '%s'", LIT(builtin_name), t);
+			if (is_type_bit_set(op_type) && id == BuiltinProc_len) {
+				error(call, "'%.*s' is not supported for '%s', did you mean 'card'?", LIT(builtin_name), t);
+			} else {
+				error(call, "'%.*s' is not supported for '%s'", LIT(builtin_name), t);
+			}
 			return false;
 		}
 
@@ -6919,6 +6984,50 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
 			break;
 		}
 
+	case BuiltinProc_type_enum_is_contiguous:
+		{
+			Operand op = {};
+			Type *bt = check_type(c, ce->args[0]);
+			Type *type = base_type(bt);
+			if (type == nullptr || type == t_invalid) {
+				error(ce->args[0], "Expected a type for '%.*s'", LIT(builtin_name));
+				return false;
+			}
+			if (!is_type_enum(type)) {
+				gbString t = type_to_string(type);
+				error(ce->args[0], "Expected an enum type for '%.*s', got %s", LIT(builtin_name), t);
+				gb_string_free(t);
+				return false;
+			}
+			
+			auto enum_constants = array_make<Entity *>(temporary_allocator(), type->Enum.fields.count);
+			array_copy(&enum_constants, type->Enum.fields, 0);
+			array_sort(enum_constants, enum_constant_entity_cmp);
+			
+			BigInt minus_one = big_int_make_i64(-1);
+			defer (big_int_dealloc(&minus_one));
+			BigInt diff = {};
+			
+			bool contiguous = true;
+			operand->mode = Addressing_Constant;
+			operand->type = t_untyped_bool;
+			
+			for (isize i = 0; i < enum_constants.count - 1; i++) {
+				BigInt curr = enum_constants[i]->Constant.value.value_integer;
+				BigInt next = enum_constants[i + 1]->Constant.value.value_integer;
+				big_int_sub(&diff, &curr, &next);
+				defer (big_int_dealloc(&diff));
+				
+				if (!big_int_is_zero(&diff) && big_int_cmp(&diff, &minus_one) != 0) {
+					contiguous = false;
+					break;
+				}
+			}
+
+			operand->value = exact_value_bool(contiguous);
+			break;
+		}
+
 	case BuiltinProc_type_equal_proc:
 		{
 			Operand op = {};

+ 102 - 94
src/check_decl.cpp

@@ -1001,120 +1001,128 @@ gb_internal String handle_link_name(CheckerContext *ctx, Token token, String lin
 
 
 gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeContext &ac) {
-	if (!(ac.objc_name.len || ac.objc_is_class_method || ac.objc_type)) {
+	if (!ac.objc_type) {
 		return;
 	}
-	if (ac.objc_name.len == 0 && ac.objc_is_class_method) {
-		error(e->token, "@(objc_name) is required with @(objc_is_class_method)");
-	} else if (ac.objc_type == nullptr) {
-		error(e->token, "@(objc_name) requires that @(objc_type) to be set");
-	} else if (ac.objc_name.len == 0 && ac.objc_type) {
-		error(e->token, "@(objc_name) is required with @(objc_type)");
-	} else {
-		Type *t = ac.objc_type;
 
-		GB_ASSERT(t->kind == Type_Named);	// NOTE(harold): This is already checked for at the attribute resolution stage.
-		Entity *tn = t->Named.type_name;
+	Type *t = ac.objc_type;
+	GB_ASSERT(t->kind == Type_Named);	// NOTE(harold): This is already checked for at the attribute resolution stage.
 
-		GB_ASSERT(tn->kind == Entity_TypeName);
+	// Attempt to infer th objc_name automatically if the proc name contains
+	// the type name objc_type's name, followed by an underscore, as a prefix.
+	if (ac.objc_name.len == 0) {
+		String proc_name = e->token.string;
+		String type_name = t->Named.name;
 
-		if (tn->scope != e->scope) {
-			error(e->token, "@(objc_name) attribute may only be applied to procedures and types within the same scope");
+		if (proc_name.len > type_name.len + 1 &&
+			proc_name[type_name.len] == '_' &&
+			str_eq(type_name, substring(proc_name, 0, type_name.len))
+		) {
+			ac.objc_name = substring(proc_name, type_name.len+1, proc_name.len);
 		} else {
+			error(e->token, "@(objc_name) requires that @(objc_type) be set or inferred "
+							"by prefixing the proc name with the type and underscore: MyObjcType_myProcName :: proc().");
+		}
+	}
 
-			// Enable implementation by default if the class is an implementer too and
-			// @objc_implement was not set to false explicitly in this proc.
-			bool implement = tn->TypeName.objc_is_implementation;
-			if (ac.objc_is_disabled_implement) {
-				implement = false;
-			}
+	Entity *tn = t->Named.type_name;
+	GB_ASSERT(tn->kind == Entity_TypeName);
 
-			if (implement) {
-				GB_ASSERT(e->kind == Entity_Procedure);
-
-				auto &proc = e->type->Proc;
-				Type *first_param = proc.param_count > 0 ? proc.params->Tuple.variables[0]->type : t_untyped_nil;
-
-				if (!tn->TypeName.objc_is_implementation) {
-					error(e->token, "@(objc_is_implement) attribute may only be applied to procedures whose class also have @(objc_is_implement) applied");
-				} else if (!ac.objc_is_class_method && !(first_param->kind == Type_Pointer && internal_check_is_assignable_to(t, first_param->Pointer.elem))) {
-					error(e->token, "Objective-C instance methods implementations require the first parameter to be a pointer to the class type set by @(objc_type)");
-				} else if (proc.calling_convention == ProcCC_Odin && !tn->TypeName.objc_context_provider) {
-					error(e->token, "Objective-C methods with Odin calling convention can only be used with classes that have @(objc_context_provider) set");
-				} else if (ac.objc_is_class_method && proc.calling_convention != ProcCC_CDecl) {
-					error(e->token, "Objective-C class methods (objc_is_class_method=true) that have @objc_is_implementation can only use \"c\" calling convention");
-				} else if (proc.result_count > 1) {
-					error(e->token, "Objective-C method implementations may return at most 1 value");
-				} else {
-					// Always export unconditionally
-					// NOTE(harold): This means check_objc_methods() MUST be called before
-					//				 e->Procedure.is_export is set in check_proc_decl()!
-					if (ac.is_export) {
-						error(e->token, "Explicit export not allowed when @(objc_implement) is set. It set exported implicitly");
-					}
-					if (ac.link_name != "") {
-						error(e->token, "Explicit linkage not allowed when @(objc_implement) is set. It set to \"strong\" implicitly");
-					}
+	if (tn->scope != e->scope) {
+		error(e->token, "@(objc_name) attribute may only be applied to procedures and types within the same scope");
+	} else {
+		// Enable implementation by default if the class is an implementer too and
+		// @objc_implement was not set to false explicitly in this proc.
+		bool implement = tn->TypeName.objc_is_implementation;
+		if (ac.objc_is_disabled_implement) {
+			implement = false;
+		}
+
+		if (implement) {
+			GB_ASSERT(e->kind == Entity_Procedure);
+
+			auto &proc = e->type->Proc;
+			Type *first_param = proc.param_count > 0 ? proc.params->Tuple.variables[0]->type : t_untyped_nil;
+
+			if (!tn->TypeName.objc_is_implementation) {
+				error(e->token, "@(objc_is_implement) attribute may only be applied to procedures whose class also have @(objc_is_implement) applied");
+			} else if (!ac.objc_is_class_method && !(first_param->kind == Type_Pointer && internal_check_is_assignable_to(t, first_param->Pointer.elem))) {
+				error(e->token, "Objective-C instance methods implementations require the first parameter to be a pointer to the class type set by @(objc_type)");
+			} else if (proc.calling_convention == ProcCC_Odin && !tn->TypeName.objc_context_provider) {
+				error(e->token, "Objective-C methods with Odin calling convention can only be used with classes that have @(objc_context_provider) set");
+			} else if (ac.objc_is_class_method && proc.calling_convention != ProcCC_CDecl) {
+				error(e->token, "Objective-C class methods (objc_is_class_method=true) that have @objc_is_implementation can only use \"c\" calling convention");
+			} else if (proc.result_count > 1) {
+				error(e->token, "Objective-C method implementations may return at most 1 value");
+			} else {
+				// Always export unconditionally
+				// NOTE(harold): This means check_objc_methods() MUST be called before
+				//				 e->Procedure.is_export is set in check_proc_decl()!
+				if (ac.is_export) {
+					error(e->token, "Explicit export not allowed when @(objc_implement) is set. It set exported implicitly");
+				}
+				if (ac.link_name != "") {
+					error(e->token, "Explicit linkage not allowed when @(objc_implement) is set. It set to \"strong\" implicitly");
+				}
 
-					ac.is_export = true;
-					ac.linkage   = STR_LIT("strong");
+				ac.is_export = true;
+				ac.linkage   = STR_LIT("strong");
 
-					auto method = ObjcMethodData{ ac, e };
-					method.ac.objc_selector = ac.objc_selector != "" ? ac.objc_selector : ac.objc_name;
+				auto method = ObjcMethodData{ ac, e };
+				method.ac.objc_selector = ac.objc_selector != "" ? ac.objc_selector : ac.objc_name;
 
-					CheckerInfo *info = ctx->info;
-					mutex_lock(&info->objc_method_mutex);
-					defer (mutex_unlock(&info->objc_method_mutex));
+				CheckerInfo *info = ctx->info;
+				mutex_lock(&info->objc_method_mutex);
+				defer (mutex_unlock(&info->objc_method_mutex));
 
-					Array<ObjcMethodData>* method_list = map_get(&info->objc_method_implementations, t);
-					if (method_list) {
-						array_add(method_list, method);
-					} else {
-						auto list = array_make<ObjcMethodData>(permanent_allocator(), 1, 8);
-						list[0] = method;
+				Array<ObjcMethodData>* method_list = map_get(&info->objc_method_implementations, t);
+				if (method_list) {
+					array_add(method_list, method);
+				} else {
+					auto list = array_make<ObjcMethodData>(permanent_allocator(), 1, 8);
+					list[0] = method;
 
-						map_set(&info->objc_method_implementations, t, list);
-					}
+					map_set(&info->objc_method_implementations, t, list);
 				}
-			} else if (ac.objc_selector != "") {
-				error(e->token, "@(objc_selector) may only be applied to procedures that are Objective-C implementations.");
 			}
+		} else if (ac.objc_selector != "") {
+			error(e->token, "@(objc_selector) may only be applied to procedures that are Objective-C implementations.");
+		}
 
-			mutex_lock(&global_type_name_objc_metadata_mutex);
-			defer (mutex_unlock(&global_type_name_objc_metadata_mutex));
+		mutex_lock(&global_type_name_objc_metadata_mutex);
+		defer (mutex_unlock(&global_type_name_objc_metadata_mutex));
 
-			if (!tn->TypeName.objc_metadata) {
-				tn->TypeName.objc_metadata = create_type_name_obj_c_metadata();
-			}
-			auto *md = tn->TypeName.objc_metadata;
-			mutex_lock(md->mutex);
-			defer (mutex_unlock(md->mutex));
-
-			if (!ac.objc_is_class_method) {
-				bool ok = true;
-				for (TypeNameObjCMetadataEntry const &entry : md->value_entries) {
-					if (entry.name == ac.objc_name) {
-						error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name));
-						ok = false;
-						break;
-					}
-				}
-				if (ok) {
-					array_add(&md->value_entries, TypeNameObjCMetadataEntry{ac.objc_name, e});
-				}
-			} else {
-				bool ok = true;
-				for (TypeNameObjCMetadataEntry const &entry : md->type_entries) {
-					if (entry.name == ac.objc_name) {
-						error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name));
-						ok = false;
-						break;
-					}
+		if (!tn->TypeName.objc_metadata) {
+			tn->TypeName.objc_metadata = create_type_name_obj_c_metadata();
+		}
+		auto *md = tn->TypeName.objc_metadata;
+		mutex_lock(md->mutex);
+		defer (mutex_unlock(md->mutex));
+
+		if (!ac.objc_is_class_method) {
+			bool ok = true;
+			for (TypeNameObjCMetadataEntry const &entry : md->value_entries) {
+				if (entry.name == ac.objc_name) {
+					error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name));
+					ok = false;
+					break;
 				}
-				if (ok) {
-					array_add(&md->type_entries, TypeNameObjCMetadataEntry{ac.objc_name, e});
+			}
+			if (ok) {
+				array_add(&md->value_entries, TypeNameObjCMetadataEntry{ac.objc_name, e});
+			}
+		} else {
+			bool ok = true;
+			for (TypeNameObjCMetadataEntry const &entry : md->type_entries) {
+				if (entry.name == ac.objc_name) {
+					error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name));
+					ok = false;
+					break;
 				}
 			}
+			if (ok) {
+				array_add(&md->type_entries, TypeNameObjCMetadataEntry{ac.objc_name, e});
+			}
 		}
 	}
 }

+ 65 - 46
src/check_expr.cpp

@@ -6245,20 +6245,43 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
 	for (isize i = 0; i < pt->param_count; i++) {
 		if (!visited[i]) {
 			Entity *e = pt->params->Tuple.variables[i];
+			bool context_allocator_error = false;
 			if (e->kind == Entity_Variable) {
 				if (e->Variable.param_value.kind != ParameterValue_Invalid) {
-					ordered_operands[i].mode = Addressing_Value;
-					ordered_operands[i].type = e->type;
-					ordered_operands[i].expr = e->Variable.param_value.original_ast_expr;
+					if (ast_file_vet_explicit_allocators(c->file)) {
+						// NOTE(lucas): check if we are trying to default to context.allocator or context.temp_allocator
+						if (e->Variable.param_value.original_ast_expr->kind == Ast_SelectorExpr) {
+							auto& expr = e->Variable.param_value.original_ast_expr->SelectorExpr.expr;
+							auto& selector = e->Variable.param_value.original_ast_expr->SelectorExpr.selector;
+							if (expr->kind == Ast_Implicit &&
+								expr->Implicit.string == STR_LIT("context") &&
+								selector->kind == Ast_Ident &&
+								(selector->Ident.token.string == STR_LIT("allocator") ||
+      								selector->Ident.token.string == STR_LIT("temp_allocator"))) {
+								context_allocator_error = true;
+							}
+						}
+					}
 
-					dummy_argument_count += 1;
-					score += assign_score_function(1);
-					continue;
+					if (!context_allocator_error) {
+						ordered_operands[i].mode = Addressing_Value;
+						ordered_operands[i].type = e->type;
+						ordered_operands[i].expr = e->Variable.param_value.original_ast_expr;
+
+						dummy_argument_count += 1;
+						score += assign_score_function(1);
+						continue;
+					}
 				}
 			}
 
 			if (show_error) {
-				if (e->kind == Entity_TypeName) {
+				if (context_allocator_error) {
+					gbString str = type_to_string(e->type);
+					error(call, "Parameter '%.*s' of type '%s' must be explicitly provided in procedure call",
+					      LIT(e->token.string), str);
+					gb_string_free(str);
+				} else if (e->kind == Entity_TypeName) {
 					error(call, "Type parameter '%.*s' is missing in procedure call",
 					      LIT(e->token.string));
 				} else if (e->kind == Entity_Constant && e->Constant.value.kind != ExactValue_Invalid) {
@@ -10312,51 +10335,47 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
 			is_constant = false;
 		}
 
-		if (cl->elems[0]->kind == Ast_FieldValue) {
-			error(cl->elems[0], "'field = value' in a bit_set a literal is not allowed");
-			is_constant = false;
-		} else {
-			for (Ast *elem : cl->elems) {
-				if (elem->kind == Ast_FieldValue) {
-					error(elem, "'field = value' in a bit_set a literal is not allowed");
-					continue;
-				}
+		for (Ast *elem : cl->elems) {
+			if (elem->kind == Ast_FieldValue) {
+				error(elem, "'field = value' in a bit_set literal is not allowed");
+				is_constant = false;
+				continue;
+			}
 
-				check_expr_with_type_hint(c, o, elem, et);
+			check_expr_with_type_hint(c, o, elem, et);
 
-				if (is_constant) {
-					is_constant = o->mode == Addressing_Constant;
-				}
+			if (is_constant) {
+				is_constant = o->mode == Addressing_Constant;
+			}
 
-				if (elem->kind == Ast_BinaryExpr) {
-					switch (elem->BinaryExpr.op.kind) {
-					case Token_Or:
-						{
-							gbString x = expr_to_string(elem->BinaryExpr.left);
-							gbString y = expr_to_string(elem->BinaryExpr.right);
-							gbString e = expr_to_string(elem);
-							error(elem, "Was the following intended? '%s, %s'; if not, surround the expression with parentheses '(%s)'", x, y, e);
-							gb_string_free(e);
-							gb_string_free(y);
-							gb_string_free(x);
-						}
-						break;
+			if (elem->kind == Ast_BinaryExpr) {
+				switch (elem->BinaryExpr.op.kind) {
+				case Token_Or:
+					{
+						gbString x = expr_to_string(elem->BinaryExpr.left);
+						gbString y = expr_to_string(elem->BinaryExpr.right);
+						gbString e = expr_to_string(elem);
+						error(elem, "Was the following intended? '%s, %s'; if not, surround the expression with parentheses '(%s)'", x, y, e);
+						gb_string_free(e);
+						gb_string_free(y);
+						gb_string_free(x);
 					}
+					break;
 				}
+			}
 
-				check_assignment(c, o, t->BitSet.elem, str_lit("bit_set literal"));
-				if (o->mode == Addressing_Constant) {
-					i64 lower = t->BitSet.lower;
-					i64 upper = t->BitSet.upper;
-					i64 v = exact_value_to_i64(o->value);
-					if (lower <= v && v <= upper) {
-						// okay
-					} else {
-						gbString s = expr_to_string(o->expr);
-						error(elem, "Bit field value out of bounds, %s (%lld) not in the range %lld .. %lld", s, v, lower, upper);
-						gb_string_free(s);
-						continue;
-					}
+			check_assignment(c, o, t->BitSet.elem, str_lit("bit_set literal"));
+			if (o->mode == Addressing_Constant) {
+				i64 lower = t->BitSet.lower;
+				i64 upper = t->BitSet.upper;
+				i64 v = exact_value_to_i64(o->value);
+				if (lower <= v && v <= upper) {
+					// okay
+				} else {
+					gbString s = expr_to_string(o->expr);
+					error(elem, "Bit field value out of bounds, %s (%lld) not in the range %lld .. %lld", s, v, lower, upper);
+					gb_string_free(s);
+					continue;
 				}
 			}
 		}

+ 4 - 0
src/check_stmt.cpp

@@ -2778,6 +2778,10 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags)
 			Ast *stmt = ds->stmt;
 			Ast *original_stmt = stmt;
 
+			if (stmt->kind == Ast_BlockStmt && stmt->BlockStmt.stmts.count == 0) {
+				break; // empty defer statement
+			}
+
 			bool is_singular = true;
 			while (is_singular && stmt->kind == Ast_BlockStmt) {
 				Ast *inner_stmt = nullptr;

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio