aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorColin Davidson <colrdavidson@gmail.com>2024-11-20 15:51:08 -0800
committerColin Davidson <colrdavidson@gmail.com>2024-11-20 15:51:08 -0800
commitd60fb5a44e4d2e371562fd38947f8125b06bceb9 (patch)
tree4e924ee102c2af7b30d29017ab716ed00c51ab26 /src
parentf3ab14b8ccb45d0fef8a96937635bdf0943ce7d6 (diff)
parent3229f4668dfaa5f43a374bc549f42661b002699d (diff)
update to master
Diffstat (limited to 'src')
-rw-r--r--src/big_int.cpp17
-rw-r--r--src/bug_report.cpp37
-rw-r--r--src/build_cpuid.cpp35
-rw-r--r--src/build_settings.cpp48
-rw-r--r--src/cached.cpp109
-rw-r--r--src/check_builtin.cpp29
-rw-r--r--src/check_decl.cpp11
-rw-r--r--src/check_expr.cpp116
-rw-r--r--src/check_stmt.cpp17
-rw-r--r--src/check_type.cpp68
-rw-r--r--src/checker.cpp43
-rw-r--r--src/docs_format.cpp3
-rw-r--r--src/docs_writer.cpp18
-rw-r--r--src/exact_value.cpp1
-rw-r--r--src/gb/gb.h6
-rw-r--r--src/linker.cpp89
-rw-r--r--src/llvm_abi.cpp21
-rw-r--r--src/llvm_backend.hpp4
-rw-r--r--src/llvm_backend_debug.cpp11
-rw-r--r--src/llvm_backend_expr.cpp89
-rw-r--r--src/llvm_backend_general.cpp198
-rw-r--r--src/llvm_backend_proc.cpp5
-rw-r--r--src/llvm_backend_stmt.cpp21
-rw-r--r--src/llvm_backend_type.cpp28
-rw-r--r--src/llvm_backend_utility.cpp20
-rw-r--r--src/main.cpp956
-rw-r--r--src/parser.cpp59
-rw-r--r--src/parser.hpp3
-rw-r--r--src/string.cpp31
-rw-r--r--src/types.cpp118
-rw-r--r--src/unicode.cpp13
31 files changed, 1121 insertions, 1103 deletions
diff --git a/src/big_int.cpp b/src/big_int.cpp
index 83235483c..8e476f090 100644
--- a/src/big_int.cpp
+++ b/src/big_int.cpp
@@ -62,6 +62,7 @@ gb_internal void big_int_shl (BigInt *dst, BigInt const *x, BigInt const *y);
gb_internal void big_int_shr (BigInt *dst, BigInt const *x, BigInt const *y);
gb_internal void big_int_mul (BigInt *dst, BigInt const *x, BigInt const *y);
gb_internal void big_int_mul_u64(BigInt *dst, BigInt const *x, u64 y);
+gb_internal void big_int_exp_u64(BigInt *dst, BigInt const *x, u64 y, bool *success);
gb_internal void big_int_quo_rem(BigInt const *x, BigInt const *y, BigInt *q, BigInt *r);
gb_internal void big_int_quo (BigInt *z, BigInt const *x, BigInt const *y);
@@ -250,9 +251,7 @@ gb_internal void big_int_from_string(BigInt *dst, String const &s, bool *success
exp *= 10;
exp += v;
}
- for (u64 x = 0; x < exp; x++) {
- big_int_mul_eq(dst, &b);
- }
+ big_int_exp_u64(dst, &b, exp, success);
}
if (is_negative) {
@@ -328,6 +327,18 @@ gb_internal void big_int_mul_u64(BigInt *dst, BigInt const *x, u64 y) {
big_int_dealloc(&d);
}
+gb_internal void big_int_exp_u64(BigInt *dst, BigInt const *x, u64 y, bool *success) {
+ if (y > INT_MAX) {
+ *success = false;
+ return;
+ }
+
+ // Note: The cutoff for square-multiply being faster than the naive
+ // for loop is when exp > 4, but it probably isn't worth adding
+ // a fast path.
+ mp_err err = mp_expt_n(x, int(y), dst);
+ *success = err == MP_OKAY;
+}
gb_internal void big_int_mul(BigInt *dst, BigInt const *x, BigInt const *y) {
mp_mul(x, y, dst);
diff --git a/src/bug_report.cpp b/src/bug_report.cpp
index fa7e156ce..d4517f9e3 100644
--- a/src/bug_report.cpp
+++ b/src/bug_report.cpp
@@ -2,12 +2,6 @@
Gather and print platform and version info to help with reporting Odin bugs.
*/
-#if !defined(GB_COMPILER_MSVC)
- #if defined(GB_CPU_X86)
- #include <cpuid.h>
- #endif
-#endif
-
#if defined(GB_SYSTEM_LINUX)
#include <sys/utsname.h>
#include <sys/sysinfo.h>
@@ -154,21 +148,6 @@ gb_internal void report_windows_product_type(DWORD ProductType) {
}
#endif
-gb_internal void odin_cpuid(int leaf, int result[]) {
- #if defined(GB_CPU_ARM) || defined(GB_CPU_RISCV)
- return;
-
- #elif defined(GB_CPU_X86)
-
- #if defined(GB_COMPILER_MSVC)
- __cpuid(result, leaf);
- #else
- __get_cpuid(leaf, (unsigned int*)&result[0], (unsigned int*)&result[1], (unsigned int*)&result[2], (unsigned int*)&result[3]);
- #endif
-
- #endif
-}
-
gb_internal void report_cpu_info() {
gb_printf("\tCPU: ");
@@ -887,6 +866,10 @@ gb_internal void report_os_info() {
{"21G816", {21, 6, 0}, "macOS", {"Monterey", {12, 7, 0}}},
{"21G920", {21, 6, 0}, "macOS", {"Monterey", {12, 7, 1}}},
{"21G1974", {21, 6, 0}, "macOS", {"Monterey", {12, 7, 2}}},
+ {"21H1015", {21, 6, 0}, "macOS", {"Monterey", {12, 7, 3}}},
+ {"21H1123", {21, 6, 0}, "macOS", {"Monterey", {12, 7, 4}}},
+ {"21H1222", {21, 6, 0}, "macOS", {"Monterey", {12, 7, 5}}},
+ {"21H1320", {21, 6, 0}, "macOS", {"Monterey", {12, 7, 6}}},
{"22A380", {13, 0, 0}, "macOS", {"Ventura", {22, 1, 0}}},
{"22A400", {13, 0, 1}, "macOS", {"Ventura", {22, 1, 0}}},
{"22C65", {13, 1, 0}, "macOS", {"Ventura", {22, 2, 0}}},
@@ -904,6 +887,15 @@ gb_internal void report_os_info() {
{"22G120", {13, 6, 0}, "macOS", {"Ventura", {22, 6, 0}}},
{"22G313", {13, 6, 1}, "macOS", {"Ventura", {22, 6, 0}}},
{"22G320", {13, 6, 2}, "macOS", {"Ventura", {22, 6, 0}}},
+ {"22G436", {22, 6, 0}, "macOS", {"Ventura", {13, 6, 3}}},
+ {"22G513", {22, 6, 0}, "macOS", {"Ventura", {13, 6, 4}}},
+ {"22G621", {22, 6, 0}, "macOS", {"Ventura", {13, 6, 5}}},
+ {"22G630", {22, 6, 0}, "macOS", {"Ventura", {13, 6, 6}}},
+ {"22G720", {22, 6, 0}, "macOS", {"Ventura", {13, 6, 7}}},
+ {"22G820", {22, 6, 0}, "macOS", {"Ventura", {13, 6, 8}}},
+ {"22G830", {22, 6, 0}, "macOS", {"Ventura", {13, 6, 9}}},
+ {"22H123", {22, 6, 0}, "macOS", {"Ventura", {13, 7, 0}}},
+ {"22H221", {22, 6, 0}, "macOS", {"Ventura", {13, 7, 1}}},
{"23A344", {23, 0, 0}, "macOS", {"Sonoma", {14, 0, 0}}},
{"23B74", {23, 1, 0}, "macOS", {"Sonoma", {14, 1, 0}}},
{"23B81", {23, 1, 0}, "macOS", {"Sonoma", {14, 1, 1}}},
@@ -920,7 +912,10 @@ gb_internal void report_os_info() {
{"23G80", {23, 6, 0}, "macOS", {"Sonoma", {14, 6, 0}}},
{"23G93", {23, 6, 0}, "macOS", {"Sonoma", {14, 6, 1}}},
{"23H124", {23, 6, 0}, "macOS", {"Sonoma", {14, 7, 0}}},
+ {"23H222", {23, 6, 0}, "macOS", {"Sonoma", {14, 7, 1}}},
{"24A335", {24, 0, 0}, "macOS", {"Sequoia", {15, 0, 0}}},
+ {"24A348", {24, 0, 0}, "macOS", {"Sequoia", {15, 0, 1}}},
+ {"24B83", {24, 1, 0}, "macOS", {"Sequoia", {15, 1, 0}}},
};
diff --git a/src/build_cpuid.cpp b/src/build_cpuid.cpp
new file mode 100644
index 000000000..b7ba5dcdf
--- /dev/null
+++ b/src/build_cpuid.cpp
@@ -0,0 +1,35 @@
+#if !defined(GB_COMPILER_MSVC)
+ #if defined(GB_CPU_X86)
+ #include <cpuid.h>
+ #endif
+#endif
+
+gb_internal void odin_cpuid(int leaf, int result[]) {
+ #if defined(GB_CPU_ARM) || defined(GB_CPU_RISCV)
+ return;
+
+ #elif defined(GB_CPU_X86)
+
+ #if defined(GB_COMPILER_MSVC)
+ __cpuid(result, leaf);
+ #else
+ __get_cpuid(leaf, (unsigned int*)&result[0], (unsigned int*)&result[1], (unsigned int*)&result[2], (unsigned int*)&result[3]);
+ #endif
+
+ #endif
+}
+
+gb_internal bool should_use_march_native() {
+ #if !defined(GB_CPU_X86)
+ return false;
+
+ #else
+
+ int cpu[4];
+ odin_cpuid(0x1, &cpu[0]); // Get feature information in ECX + EDX
+
+ bool have_popcnt = cpu[2] & (1 << 23); // bit 23 in ECX = popcnt
+ return !have_popcnt;
+
+ #endif
+} \ No newline at end of file
diff --git a/src/build_settings.cpp b/src/build_settings.cpp
index 7aff8e650..50fae93b8 100644
--- a/src/build_settings.cpp
+++ b/src/build_settings.cpp
@@ -2,6 +2,7 @@
#include <sys/types.h>
#include <sys/sysctl.h>
#endif
+#include "build_cpuid.cpp"
// #if defined(GB_SYSTEM_WINDOWS)
// #define DEFAULT_TO_THREADED_CHECKER
@@ -343,6 +344,22 @@ struct BuildCacheData {
bool copy_already_done;
};
+
+enum LinkerChoice : i32 {
+ Linker_Invalid = -1,
+ Linker_Default = 0,
+ Linker_lld,
+ Linker_radlink,
+
+ Linker_COUNT,
+};
+
+String linker_choices[Linker_COUNT] = {
+ str_lit("default"),
+ str_lit("lld"),
+ str_lit("radlink"),
+};
+
// This stores the information for the specify architecture of this build
struct BuildContext {
// Constants
@@ -418,12 +435,13 @@ struct BuildContext {
bool no_rpath;
bool no_entry_point;
bool no_thread_local;
- bool use_lld;
bool cross_compiling;
bool different_os;
bool keep_object_files;
bool disallow_do;
+ LinkerChoice linker_choice;
+
StringSet custom_attributes;
bool strict_style;
@@ -453,7 +471,7 @@ struct BuildContext {
bool no_threaded_checker;
bool show_debug_messages;
-
+
bool copy_file_contents;
bool no_rtti;
@@ -1870,7 +1888,7 @@ gb_internal bool init_build_paths(String init_filename) {
return false;
}
- if (!build_context.use_lld && find_result.vs_exe_path.len == 0) {
+ if (build_context.linker_choice == Linker_Default && find_result.vs_exe_path.len == 0) {
gb_printf_err("link.exe not found.\n");
return false;
}
@@ -2049,19 +2067,19 @@ gb_internal bool init_build_paths(String init_filename) {
return false;
}
- gbFile output_file_test;
- const char* output_file_name = (const char*)output_file.text;
- gbFileError output_test_err = gb_file_open_mode(&output_file_test, gbFileMode_Append | gbFileMode_Rw, output_file_name);
+ // gbFile output_file_test;
+ // const char* output_file_name = (const char*)output_file.text;
+ // gbFileError output_test_err = gb_file_open_mode(&output_file_test, gbFileMode_Append | gbFileMode_Rw, output_file_name);
- if (output_test_err == 0) {
- gb_file_close(&output_file_test);
- gb_file_remove(output_file_name);
- } else {
- String output_file = path_to_string(ha, bc->build_paths[BuildPath_Output]);
- defer (gb_free(ha, output_file.text));
- gb_printf_err("No write permissions for output path: %.*s\n", LIT(output_file));
- return false;
- }
+ // if (output_test_err == 0) {
+ // gb_file_close(&output_file_test);
+ // gb_file_remove(output_file_name);
+ // } else {
+ // String output_file = path_to_string(ha, bc->build_paths[BuildPath_Output]);
+ // defer (gb_free(ha, output_file.text));
+ // gb_printf_err("No write permissions for output path: %.*s\n", LIT(output_file));
+ // return false;
+ // }
if (build_context.sanitizer_flags & SanitizerFlag_Address) {
switch (build_context.metrics.os) {
diff --git a/src/cached.cpp b/src/cached.cpp
index 4ad65ee9e..efdadce7b 100644
--- a/src/cached.cpp
+++ b/src/cached.cpp
@@ -187,10 +187,7 @@ gb_internal bool try_copy_executable_from_cache(void) {
extern char **environ;
#endif
-// returns false if different, true if it is the same
-gb_internal bool try_cached_build(Checker *c, Array<String> const &args) {
- TEMPORARY_ALLOCATOR_GUARD();
-
+Array<String> cache_gather_files(Checker *c) {
Parser *p = c->parser;
auto files = array_make<String>(heap_allocator());
@@ -222,29 +219,11 @@ gb_internal bool try_cached_build(Checker *c, Array<String> const &args) {
array_sort(files, string_cmp);
- u64 crc = 0;
- for (String const &path : files) {
- crc = crc64_with_seed(path.text, path.len, crc);
- }
-
- String base_cache_dir = build_context.build_paths[BuildPath_Output].basename;
- base_cache_dir = concatenate_strings(permanent_allocator(), base_cache_dir, str_lit("/.odin-cache"));
- (void)check_if_exists_directory_otherwise_create(base_cache_dir);
-
- gbString crc_str = gb_string_make_reserve(permanent_allocator(), 16);
- crc_str = gb_string_append_fmt(crc_str, "%016llx", crc);
- String cache_dir = concatenate3_strings(permanent_allocator(), base_cache_dir, str_lit("/"), make_string_c(crc_str));
- String files_path = concatenate3_strings(permanent_allocator(), cache_dir, str_lit("/"), str_lit("files.manifest"));
- String args_path = concatenate3_strings(permanent_allocator(), cache_dir, str_lit("/"), str_lit("args.manifest"));
- String env_path = concatenate3_strings(permanent_allocator(), cache_dir, str_lit("/"), str_lit("env.manifest"));
-
- build_context.build_cache_data.cache_dir = cache_dir;
- build_context.build_cache_data.files_path = files_path;
- build_context.build_cache_data.args_path = args_path;
- build_context.build_cache_data.env_path = env_path;
+ return files;
+}
+Array<String> cache_gather_envs() {
auto envs = array_make<String>(heap_allocator());
- defer (array_free(&envs));
{
#if defined(GB_SYSTEM_WINDOWS)
wchar_t *strings = GetEnvironmentStringsW();
@@ -275,19 +254,50 @@ gb_internal bool try_cached_build(Checker *c, Array<String> const &args) {
#endif
}
array_sort(envs, string_cmp);
+ return envs;
+}
+
+// returns false if different, true if it is the same
+gb_internal bool try_cached_build(Checker *c, Array<String> const &args) {
+ TEMPORARY_ALLOCATOR_GUARD();
+
+ auto files = cache_gather_files(c);
+ auto envs = cache_gather_envs();
+ defer (array_free(&envs));
+
+ u64 crc = 0;
+ for (String const &path : files) {
+ crc = crc64_with_seed(path.text, path.len, crc);
+ }
+
+ String base_cache_dir = build_context.build_paths[BuildPath_Output].basename;
+ base_cache_dir = concatenate_strings(permanent_allocator(), base_cache_dir, str_lit("/.odin-cache"));
+ (void)check_if_exists_directory_otherwise_create(base_cache_dir);
+
+ gbString crc_str = gb_string_make_reserve(permanent_allocator(), 16);
+ crc_str = gb_string_append_fmt(crc_str, "%016llx", crc);
+ String cache_dir = concatenate3_strings(permanent_allocator(), base_cache_dir, str_lit("/"), make_string_c(crc_str));
+ String files_path = concatenate3_strings(permanent_allocator(), cache_dir, str_lit("/"), str_lit("files.manifest"));
+ String args_path = concatenate3_strings(permanent_allocator(), cache_dir, str_lit("/"), str_lit("args.manifest"));
+ String env_path = concatenate3_strings(permanent_allocator(), cache_dir, str_lit("/"), str_lit("env.manifest"));
+
+ build_context.build_cache_data.cache_dir = cache_dir;
+ build_context.build_cache_data.files_path = files_path;
+ build_context.build_cache_data.args_path = args_path;
+ build_context.build_cache_data.env_path = env_path;
if (check_if_exists_directory_otherwise_create(cache_dir)) {
- goto write_cache;
+ return false;
}
if (check_if_exists_file_otherwise_create(files_path)) {
- goto write_cache;
+ return false;
}
if (check_if_exists_file_otherwise_create(args_path)) {
- goto write_cache;
+ return false;
}
if (check_if_exists_file_otherwise_create(env_path)) {
- goto write_cache;
+ return false;
}
{
@@ -297,7 +307,7 @@ gb_internal bool try_cached_build(Checker *c, Array<String> const &args) {
LoadedFileError file_err = load_file_32(
alloc_cstring(temporary_allocator(), files_path),
&loaded_file,
- false
+ true
);
if (file_err > LoadedFile_Empty) {
return false;
@@ -315,7 +325,7 @@ gb_internal bool try_cached_build(Checker *c, Array<String> const &args) {
}
isize sep = string_index_byte(line, ' ');
if (sep < 0) {
- goto write_cache;
+ return false;
}
String timestamp_str = substring(line, 0, sep);
@@ -325,21 +335,21 @@ gb_internal bool try_cached_build(Checker *c, Array<String> const &args) {
path_str = string_trim_whitespace(path_str);
if (file_count >= files.count) {
- goto write_cache;
+ return false;
}
if (files[file_count] != path_str) {
- goto write_cache;
+ return false;
}
u64 timestamp = exact_value_to_u64(exact_value_integer_from_string(timestamp_str));
gbFileTime last_write_time = gb_file_last_write_time(alloc_cstring(temporary_allocator(), path_str));
if (last_write_time != timestamp) {
- goto write_cache;
+ return false;
}
}
if (file_count != files.count) {
- goto write_cache;
+ return false;
}
}
{
@@ -348,7 +358,7 @@ gb_internal bool try_cached_build(Checker *c, Array<String> const &args) {
LoadedFileError file_err = load_file_32(
alloc_cstring(temporary_allocator(), args_path),
&loaded_file,
- false
+ true
);
if (file_err > LoadedFile_Empty) {
return false;
@@ -366,11 +376,11 @@ gb_internal bool try_cached_build(Checker *c, Array<String> const &args) {
break;
}
if (args_count >= args.count) {
- goto write_cache;
+ return false;
}
if (line != args[args_count]) {
- goto write_cache;
+ return false;
}
}
}
@@ -380,7 +390,7 @@ gb_internal bool try_cached_build(Checker *c, Array<String> const &args) {
LoadedFileError file_err = load_file_32(
alloc_cstring(temporary_allocator(), env_path),
&loaded_file,
- false
+ true
);
if (file_err > LoadedFile_Empty) {
return false;
@@ -398,20 +408,26 @@ gb_internal bool try_cached_build(Checker *c, Array<String> const &args) {
break;
}
if (env_count >= envs.count) {
- goto write_cache;
+ return false;
}
if (line != envs[env_count]) {
- goto write_cache;
+ return false;
}
}
}
return try_copy_executable_from_cache();
+}
+
+void write_cached_build(Checker *c, Array<String> const &args) {
+ auto files = cache_gather_files(c);
+ defer (array_free(&files));
+ auto envs = cache_gather_envs();
+ defer (array_free(&envs));
-write_cache:;
{
- char const *path_c = alloc_cstring(temporary_allocator(), files_path);
+ char const *path_c = alloc_cstring(temporary_allocator(), build_context.build_cache_data.files_path);
gb_file_remove(path_c);
debugf("Cache: updating %s\n", path_c);
@@ -426,7 +442,7 @@ write_cache:;
}
}
{
- char const *path_c = alloc_cstring(temporary_allocator(), args_path);
+ char const *path_c = alloc_cstring(temporary_allocator(), build_context.build_cache_data.args_path);
gb_file_remove(path_c);
debugf("Cache: updating %s\n", path_c);
@@ -441,7 +457,7 @@ write_cache:;
}
}
{
- char const *path_c = alloc_cstring(temporary_allocator(), env_path);
+ char const *path_c = alloc_cstring(temporary_allocator(), build_context.build_cache_data.env_path);
gb_file_remove(path_c);
debugf("Cache: updating %s\n", path_c);
@@ -454,8 +470,5 @@ write_cache:;
gb_fprintf(&f, "%.*s\n", LIT(env));
}
}
-
-
- return false;
}
diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp
index 8c051cca2..c86503093 100644
--- a/src/check_builtin.cpp
+++ b/src/check_builtin.cpp
@@ -1533,6 +1533,10 @@ gb_internal LoadDirectiveResult check_load_directory_directive(CheckerContext *c
for (FileInfo fi : list) {
LoadFileCache *cache = nullptr;
+ if (fi.is_dir) {
+ continue;
+ }
+
if (cache_load_file_directive(c, call, fi.fullpath, err_on_not_found, &cache, LoadFileTier_Contents, /*use_mutex*/false)) {
array_add(&file_caches, cache);
} else {
@@ -2060,8 +2064,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
bool ok = check_builtin_simd_operation(c, operand, call, id, type_hint);
if (!ok) {
operand->type = t_invalid;
+ operand->mode = Addressing_Value;
}
- operand->mode = Addressing_Value;
operand->value = {};
operand->expr = call;
return ok;
@@ -3098,7 +3102,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
// Okay
} else if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) {
gbString type_str = type_to_string(original_type);
- error(call, "Expected a ordered numeric type to 'min', got '%s'", type_str);
+ error(call, "Expected an ordered numeric type to 'min', got '%s'", type_str);
gb_string_free(type_str);
return false;
}
@@ -3166,6 +3170,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
return false;
}
+ if (ce->args.count <= 1) {
+ error(call, "Too few arguments for 'min', two or more are required");
+ return false;
+ }
bool all_constant = operand->mode == Addressing_Constant;
@@ -3184,7 +3192,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
if (!is_type_ordered(b.type) || !(is_type_numeric(b.type) || is_type_string(b.type))) {
gbString type_str = type_to_string(b.type);
error(call,
- "Expected a ordered numeric type to 'min', got '%s'",
+ "Expected an ordered numeric type to 'min', got '%s'",
type_str);
gb_string_free(type_str);
return false;
@@ -3267,7 +3275,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
// Okay
} else if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) {
gbString type_str = type_to_string(original_type);
- error(call, "Expected a ordered numeric type to 'max', got '%s'", type_str);
+ error(call, "Expected an ordered numeric type to 'max', got '%s'", type_str);
gb_string_free(type_str);
return false;
}
@@ -3339,6 +3347,11 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
gb_string_free(type_str);
return false;
}
+
+ if (ce->args.count <= 1) {
+ error(call, "Too few arguments for 'max', two or more are required");
+ return false;
+ }
bool all_constant = operand->mode == Addressing_Constant;
@@ -3358,7 +3371,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
if (!is_type_ordered(b.type) || !(is_type_numeric(b.type) || is_type_string(b.type))) {
gbString type_str = type_to_string(b.type);
error(arg,
- "Expected a ordered numeric type to 'max', got '%s'",
+ "Expected an ordered numeric type to 'max', got '%s'",
type_str);
gb_string_free(type_str);
return false;
@@ -3488,7 +3501,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
Type *type = operand->type;
if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) {
gbString type_str = type_to_string(operand->type);
- error(call, "Expected a ordered numeric or string type to 'clamp', got '%s'", type_str);
+ error(call, "Expected an ordered numeric or string type to 'clamp', got '%s'", type_str);
gb_string_free(type_str);
return false;
}
@@ -3505,7 +3518,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
}
if (!is_type_ordered(y.type) || !(is_type_numeric(y.type) || is_type_string(y.type))) {
gbString type_str = type_to_string(y.type);
- error(call, "Expected a ordered numeric or string type to 'clamp', got '%s'", type_str);
+ error(call, "Expected an ordered numeric or string type to 'clamp', got '%s'", type_str);
gb_string_free(type_str);
return false;
}
@@ -3516,7 +3529,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
}
if (!is_type_ordered(z.type) || !(is_type_numeric(z.type) || is_type_string(z.type))) {
gbString type_str = type_to_string(z.type);
- error(call, "Expected a ordered numeric or string type to 'clamp', got '%s'", type_str);
+ error(call, "Expected an ordered numeric or string type to 'clamp', got '%s'", type_str);
gb_string_free(type_str);
return false;
}
diff --git a/src/check_decl.cpp b/src/check_decl.cpp
index 3b532a727..60eb030ff 100644
--- a/src/check_decl.cpp
+++ b/src/check_decl.cpp
@@ -88,11 +88,12 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o
e->type = t_invalid;
return nullptr;
} else if (is_type_polymorphic(t)) {
- Entity *e = entity_of_node(operand->expr);
- if (e == nullptr) {
+ Entity *e2 = entity_of_node(operand->expr);
+ if (e2 == nullptr) {
+ e->type = t_invalid;
return nullptr;
}
- if (e->state.load() != EntityState_Resolved) {
+ if (e2->state.load() != EntityState_Resolved) {
gbString str = type_to_string(t);
defer (gb_string_free(str));
error(e->token, "Invalid use of a polymorphic type '%s' in %.*s", str, LIT(context_name));
@@ -232,6 +233,10 @@ gb_internal bool check_override_as_type_due_to_aliasing(CheckerContext *ctx, Ent
// until there is a proper delaying system to try declaration again if they
// have failed.
+ if (e->type != nullptr && is_type_typed(e->type)) {
+ return false;
+ }
+
e->kind = Entity_TypeName;
check_type_decl(ctx, e, init, named_type);
return true;
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index fc1aa62e6..cb4647f33 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -285,7 +285,7 @@ gb_internal void error_operand_no_value(Operand *o) {
if (o->mode == Addressing_NoValue) {
Ast *x = unparen_expr(o->expr);
- if (x->kind == Ast_CallExpr) {
+ if (x != nullptr && x->kind == Ast_CallExpr) {
Ast *p = unparen_expr(x->CallExpr.proc);
if (p->kind == Ast_BasicDirective) {
String tag = p->BasicDirective.name.string;
@@ -297,7 +297,7 @@ gb_internal void error_operand_no_value(Operand *o) {
}
gbString err = expr_to_string(o->expr);
- if (x->kind == Ast_CallExpr) {
+ if (x != nullptr && x->kind == Ast_CallExpr) {
error(o->expr, "'%s' call does not return a value and cannot be used as a value", err);
} else {
error(o->expr, "'%s' used as a value", err);
@@ -897,20 +897,6 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
}
}
- if (is_type_relative_pointer(dst)) {
- i64 score = check_distance_between_types(c, operand, dst->RelativePointer.pointer_type, allow_array_programming);
- if (score >= 0) {
- return score+2;
- }
- }
-
- if (is_type_relative_multi_pointer(dst)) {
- i64 score = check_distance_between_types(c, operand, dst->RelativeMultiPointer.pointer_type, allow_array_programming);
- if (score >= 0) {
- return score+2;
- }
- }
-
if (is_type_proc(dst)) {
if (are_types_identical(src, dst)) {
return 3;
@@ -1052,12 +1038,6 @@ gb_internal AstPackage *get_package_of_type(Type *type) {
case Type_DynamicArray:
type = type->DynamicArray.elem;
continue;
- case Type_RelativePointer:
- type = type->RelativePointer.pointer_type;
- continue;
- case Type_RelativeMultiPointer:
- type = type->RelativeMultiPointer.pointer_type;
- continue;
}
return nullptr;
}
@@ -3901,6 +3881,12 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ
// IMPORTANT NOTE(bill): This uses right-left evaluation in type checking only no in
check_expr(c, y, be->right);
Type *rhs_type = type_deref(y->type);
+ if (rhs_type == nullptr) {
+ error(y->expr, "Cannot use '%.*s' on an expression with no value", LIT(op.string));
+ x->mode = Addressing_Invalid;
+ x->expr = node;
+ return;
+ }
if (is_type_bit_set(rhs_type)) {
Type *elem = base_type(rhs_type)->BitSet.elem;
@@ -5388,22 +5374,25 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
Type *t = type_deref(operand->type);
if (t == nullptr) {
error(operand->expr, "Cannot use a selector expression on 0-value expression");
- } else if (is_type_dynamic_array(t)) {
- init_mem_allocator(c->checker);
- }
- sel = lookup_field(operand->type, field_name, operand->mode == Addressing_Type);
- entity = sel.entity;
+ } else {
+ if (is_type_dynamic_array(t)) {
+ init_mem_allocator(c->checker);
+ }
+ sel = lookup_field(operand->type, field_name, operand->mode == Addressing_Type);
+ entity = sel.entity;
- // NOTE(bill): Add type info needed for fields like 'names'
- if (entity != nullptr && (entity->flags&EntityFlag_TypeField)) {
- add_type_info_type(c, operand->type);
- }
- if (is_type_enum(operand->type)) {
- add_type_info_type(c, operand->type);
+ // NOTE(bill): Add type info needed for fields like 'names'
+ if (entity != nullptr && (entity->flags&EntityFlag_TypeField)) {
+ add_type_info_type(c, operand->type);
+ }
+ if (is_type_enum(operand->type)) {
+ add_type_info_type(c, operand->type);
+ }
}
}
- if (entity == nullptr && selector->kind == Ast_Ident && (is_type_array(type_deref(operand->type)) || is_type_simd_vector(type_deref(operand->type)))) {
+ if (entity == nullptr && selector->kind == Ast_Ident && operand->type != nullptr &&
+ (is_type_array(type_deref(operand->type)) || is_type_simd_vector(type_deref(operand->type)))) {
String field_name = selector->Ident.token.string;
if (1 < field_name.len && field_name.len <= 4) {
u8 swizzles_xyzw[4] = {'x', 'y', 'z', 'w'};
@@ -8002,6 +7991,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
pt = data.gen_entity->type;
}
}
+ pt = base_type(pt);
if (pt->kind == Type_Proc && pt->Proc.calling_convention == ProcCC_Odin) {
if ((c->scope->flags & ScopeFlag_ContextDefined) == 0) {
@@ -8220,17 +8210,6 @@ gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64
}
return true;
- case Type_RelativeMultiPointer:
- {
- Type *pointer_type = base_type(t->RelativeMultiPointer.pointer_type);
- GB_ASSERT(pointer_type->kind == Type_MultiPointer);
- o->type = pointer_type->MultiPointer.elem;
- if (o->mode != Addressing_Constant) {
- o->mode = Addressing_Variable;
- }
- }
- return true;
-
case Type_DynamicArray:
o->type = t->DynamicArray.elem;
if (o->mode != Addressing_Constant) {
@@ -8469,6 +8448,15 @@ gb_internal ExprKind check_implicit_selector_expr(CheckerContext *c, Operand *o,
error(node, "Undeclared name '%.*s' for type '%s'", LIT(name), typ);
check_did_you_mean_type(name, bt->Enum.fields);
+ } else if (is_type_bit_set(th) && is_type_enum(th->BitSet.elem)) {
+ ERROR_BLOCK();
+
+ gbString typ = type_to_string(th);
+ gbString str = expr_to_string(node);
+ error(node, "Cannot convert enum value to '%s'", typ);
+ error_line("\tSuggestion: Did you mean '{ %s }'?\n", str);
+ gb_string_free(typ);
+ gb_string_free(str);
} else {
gbString typ = type_to_string(th);
gbString str = expr_to_string(node);
@@ -8795,11 +8783,6 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n
return kind;
}
- if (x.type == nullptr || x.type == t_invalid ||
- y.type == nullptr || y.type == t_invalid) {
- return kind;
- }
-
bool use_type_hint = type_hint != nullptr && (is_operand_nil(x) || is_operand_nil(y));
convert_to_typed(c, &x, use_type_hint ? type_hint : y.type);
@@ -10609,8 +10592,6 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node,
// Okay
} else if (is_type_string(t)) {
// Okay
- } else if (is_type_relative_multi_pointer(t)) {
- // Okay
} else if (is_type_matrix(t)) {
// Okay
} else {
@@ -10765,11 +10746,6 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node,
}
break;
- case Type_RelativeMultiPointer:
- valid = true;
- o->type = type_deref(o->type);
- break;
-
case Type_EnumeratedArray:
{
gbString str = expr_to_string(o->expr);
@@ -10846,16 +10822,6 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node,
x[i:n] -> []T
*/
o->type = alloc_type_slice(t->MultiPointer.elem);
- } else if (t->kind == Type_RelativeMultiPointer && se->high != nullptr) {
- /*
- x[:] -> [^]T
- x[i:] -> [^]T
- x[:n] -> []T
- x[i:n] -> []T
- */
- Type *pointer_type = base_type(t->RelativeMultiPointer.pointer_type);
- GB_ASSERT(pointer_type->kind == Type_MultiPointer);
- o->type = alloc_type_slice(pointer_type->MultiPointer.elem);
}
@@ -11216,22 +11182,6 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
} else if (t->kind == Type_SoaPointer) {
o->mode = Addressing_SoaVariable;
o->type = type_deref(t);
- } else if (t->kind == Type_RelativePointer) {
- if (o->mode != Addressing_Variable) {
- gbString str = expr_to_string(o->expr);
- gbString typ = type_to_string(o->type);
- error(o->expr, "Cannot dereference relative pointer '%s' of type '%s' as it does not have a variable addressing mode", str, typ);
- gb_string_free(typ);
- gb_string_free(str);
- }
-
- // NOTE(bill): This is required because when dereferencing, the original type has been lost
- add_type_info_type(c, o->type);
-
- Type *ptr_type = base_type(t->RelativePointer.pointer_type);
- GB_ASSERT(ptr_type->kind == Type_Pointer);
- o->mode = Addressing_Variable;
- o->type = ptr_type->Pointer.elem;
} else {
gbString str = expr_to_string(o->expr);
gbString typ = type_to_string(o->type);
diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp
index 74a9e8825..2418fcc5c 100644
--- a/src/check_stmt.cpp
+++ b/src/check_stmt.cpp
@@ -2600,6 +2600,23 @@ gb_internal void check_for_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
check_expr(ctx, &o, fs->cond);
if (o.mode != Addressing_Invalid && !is_type_boolean(o.type)) {
error(fs->cond, "Non-boolean condition in 'for' statement");
+ } else {
+ Ast *cond = unparen_expr(o.expr);
+ if (cond && cond->kind == Ast_BinaryExpr &&
+ cond->BinaryExpr.left && cond->BinaryExpr.right &&
+ cond->BinaryExpr.op.kind == Token_GtEq &&
+ is_type_unsigned(type_of_expr(cond->BinaryExpr.left)) &&
+ cond->BinaryExpr.right->tav.value.kind == ExactValue_Integer &&
+ is_exact_value_zero(cond->BinaryExpr.right->tav.value)) {
+ warning(cond, "Expression is always true since unsigned numbers are always >= 0");
+ } else if (cond && cond->kind == Ast_BinaryExpr &&
+ cond->BinaryExpr.left && cond->BinaryExpr.right &&
+ cond->BinaryExpr.op.kind == Token_LtEq &&
+ is_type_unsigned(type_of_expr(cond->BinaryExpr.right)) &&
+ cond->BinaryExpr.left->tav.value.kind == ExactValue_Integer &&
+ is_exact_value_zero(cond->BinaryExpr.left->tav.value)) {
+ warning(cond, "Expression is always true since unsigned numbers are always >= 0");
+ }
}
}
if (fs->post != nullptr) {
diff --git a/src/check_type.cpp b/src/check_type.cpp
index f0e0acb9b..84e7fb249 100644
--- a/src/check_type.cpp
+++ b/src/check_type.cpp
@@ -673,7 +673,7 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *
#define ST_ALIGN(_name) if (st->_name != nullptr) { \
if (st->is_packed) { \
- syntax_error(st->_name, "'#%s' cannot be applied with '#packed'", #_name); \
+ error(st->_name, "'#%s' cannot be applied with '#packed'", #_name); \
return; \
} \
i64 align = 1; \
@@ -682,12 +682,31 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *
} \
}
- ST_ALIGN(field_align);
+ ST_ALIGN(min_field_align);
+ ST_ALIGN(max_field_align);
ST_ALIGN(align);
- if (struct_type->Struct.custom_align < struct_type->Struct.custom_field_align) {
- warning(st->align, "#align(%lld) is defined to be less than #field_name(%lld)",
- cast(long long)struct_type->Struct.custom_align,
- cast(long long)struct_type->Struct.custom_field_align);
+ if (struct_type->Struct.custom_align < struct_type->Struct.custom_min_field_align) {
+ error(st->align, "#align(%lld) is defined to be less than #min_field_align(%lld)",
+ cast(long long)struct_type->Struct.custom_align,
+ cast(long long)struct_type->Struct.custom_min_field_align);
+ }
+ if (struct_type->Struct.custom_max_field_align != 0 &&
+ struct_type->Struct.custom_align > struct_type->Struct.custom_max_field_align) {
+ error(st->align, "#align(%lld) is defined to be greater than #max_field_align(%lld)",
+ cast(long long)struct_type->Struct.custom_align,
+ cast(long long)struct_type->Struct.custom_max_field_align);
+ }
+ if (struct_type->Struct.custom_max_field_align != 0 &&
+ struct_type->Struct.custom_min_field_align > struct_type->Struct.custom_max_field_align) {
+ error(st->align, "#min_field_align(%lld) is defined to be greater than #max_field_align(%lld)",
+ cast(long long)struct_type->Struct.custom_min_field_align,
+ cast(long long)struct_type->Struct.custom_max_field_align);
+
+ i64 a = gb_min(struct_type->Struct.custom_min_field_align, struct_type->Struct.custom_max_field_align);
+ i64 b = gb_max(struct_type->Struct.custom_min_field_align, struct_type->Struct.custom_max_field_align);
+ // NOTE(bill): sort them to keep code consistent
+ struct_type->Struct.custom_min_field_align = a;
+ struct_type->Struct.custom_max_field_align = b;
}
#undef ST_ALIGN
@@ -3498,41 +3517,8 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
case_end;
case_ast_node(rt, RelativeType, e);
- GB_ASSERT(rt->tag->kind == Ast_CallExpr);
- ast_node(ce, CallExpr, rt->tag);
-
- Type *base_integer = nullptr;
-
- if (ce->args.count != 1) {
- error(rt->type, "#relative expected 1 type argument, got %td", ce->args.count);
- } else {
- base_integer = check_type(ctx, ce->args[0]);
- if (!is_type_integer(base_integer)) {
- error(rt->type, "#relative base types must be an integer");
- base_integer = nullptr;
- } else if (type_size_of(base_integer) > 64) {
- error(rt->type, "#relative base integer types be less than or equal to 64-bits");
- base_integer = nullptr;
- }
- }
-
- Type *relative_type = nullptr;
- Type *base_type = check_type(ctx, rt->type);
- if (!is_type_pointer(base_type) && !is_type_multi_pointer(base_type)) {
- error(rt->type, "#relative types can only be a pointer or multi-pointer");
- relative_type = base_type;
- } else if (base_integer == nullptr) {
- relative_type = base_type;
- } else {
- if (is_type_pointer(base_type)) {
- relative_type = alloc_type_relative_pointer(base_type, base_integer);
- } else if (is_type_multi_pointer(base_type)) {
- relative_type = alloc_type_relative_multi_pointer(base_type, base_integer);
- }
- }
- GB_ASSERT(relative_type != nullptr);
-
- *type = relative_type;
+ error(e, "#relative types have been removed from the compiler. Prefer \"core:relative\".");
+ *type = t_invalid;
set_base_type(named_type, *type);
return true;
case_end;
diff --git a/src/checker.cpp b/src/checker.cpp
index af1e0e675..b7cf343f8 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -695,6 +695,9 @@ gb_internal void check_scope_usage_internal(Checker *c, Scope *scope, u64 vet_fl
bool vet_unused = (vet_flags & VetFlag_Unused) != 0;
bool vet_shadowing = (vet_flags & (VetFlag_Shadowing|VetFlag_Using)) != 0;
bool vet_unused_procedures = (vet_flags & VetFlag_UnusedProcedures) != 0;
+ if (vet_unused_procedures && e->pkg && e->pkg->kind == Package_Runtime) {
+ vet_unused_procedures = false;
+ }
VettedEntity ve_unused = {};
VettedEntity ve_shadowed = {};
@@ -2183,16 +2186,6 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) {
add_type_info_type_internal(c, bt->SimdVector.elem);
break;
- case Type_RelativePointer:
- add_type_info_type_internal(c, bt->RelativePointer.pointer_type);
- add_type_info_type_internal(c, bt->RelativePointer.base_integer);
- break;
-
- case Type_RelativeMultiPointer:
- add_type_info_type_internal(c, bt->RelativeMultiPointer.pointer_type);
- add_type_info_type_internal(c, bt->RelativeMultiPointer.base_integer);
- break;
-
case Type_Matrix:
add_type_info_type_internal(c, bt->Matrix.elem);
break;
@@ -2438,16 +2431,6 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) {
add_min_dep_type_info(c, bt->SimdVector.elem);
break;
- case Type_RelativePointer:
- add_min_dep_type_info(c, bt->RelativePointer.pointer_type);
- add_min_dep_type_info(c, bt->RelativePointer.base_integer);
- break;
-
- case Type_RelativeMultiPointer:
- add_min_dep_type_info(c, bt->RelativeMultiPointer.pointer_type);
- add_min_dep_type_info(c, bt->RelativeMultiPointer.base_integer);
- break;
-
case Type_Matrix:
add_min_dep_type_info(c, bt->Matrix.elem);
break;
@@ -3072,8 +3055,6 @@ gb_internal void init_core_type_info(Checker *c) {
t_type_info_map = find_core_type(c, str_lit("Type_Info_Map"));
t_type_info_bit_set = find_core_type(c, str_lit("Type_Info_Bit_Set"));
t_type_info_simd_vector = find_core_type(c, str_lit("Type_Info_Simd_Vector"));
- t_type_info_relative_pointer = find_core_type(c, str_lit("Type_Info_Relative_Pointer"));
- t_type_info_relative_multi_pointer = find_core_type(c, str_lit("Type_Info_Relative_Multi_Pointer"));
t_type_info_matrix = find_core_type(c, str_lit("Type_Info_Matrix"));
t_type_info_soa_pointer = find_core_type(c, str_lit("Type_Info_Soa_Pointer"));
t_type_info_bit_field = find_core_type(c, str_lit("Type_Info_Bit_Field"));
@@ -3102,8 +3083,6 @@ gb_internal void init_core_type_info(Checker *c) {
t_type_info_map_ptr = alloc_type_pointer(t_type_info_map);
t_type_info_bit_set_ptr = alloc_type_pointer(t_type_info_bit_set);
t_type_info_simd_vector_ptr = alloc_type_pointer(t_type_info_simd_vector);
- t_type_info_relative_pointer_ptr = alloc_type_pointer(t_type_info_relative_pointer);
- t_type_info_relative_multi_pointer_ptr = alloc_type_pointer(t_type_info_relative_multi_pointer);
t_type_info_matrix_ptr = alloc_type_pointer(t_type_info_matrix);
t_type_info_soa_pointer_ptr = alloc_type_pointer(t_type_info_soa_pointer);
t_type_info_bit_field_ptr = alloc_type_pointer(t_type_info_bit_field);
@@ -6206,7 +6185,7 @@ gb_internal void check_deferred_procedures(Checker *c) {
}
if ((src_params == nullptr && dst_params != nullptr) ||
(src_params != nullptr && dst_params == nullptr)) {
- error(src->token, "Deferred procedure '%.*s' parameters do not match the inputs of initial procedure '%.*s'", LIT(src->token.string), LIT(dst->token.string));
+ error(src->token, "Deferred procedure '%.*s' parameters do not match the inputs of initial procedure '%.*s'", LIT(dst->token.string), LIT(src->token.string));
continue;
}
@@ -6219,8 +6198,8 @@ gb_internal void check_deferred_procedures(Checker *c) {
gbString s = type_to_string(src_params);
gbString d = type_to_string(dst_params);
error(src->token, "Deferred procedure '%.*s' parameters do not match the inputs of initial procedure '%.*s':\n\t(%s) =/= (%s)",
- LIT(src->token.string), LIT(dst->token.string),
- s, d
+ LIT(dst->token.string), LIT(src->token.string),
+ d, s
);
gb_string_free(d);
gb_string_free(s);
@@ -6236,7 +6215,7 @@ gb_internal void check_deferred_procedures(Checker *c) {
}
if ((src_results == nullptr && dst_params != nullptr) ||
(src_results != nullptr && dst_params == nullptr)) {
- error(src->token, "Deferred procedure '%.*s' parameters do not match the results of initial procedure '%.*s'", LIT(src->token.string), LIT(dst->token.string));
+ error(src->token, "Deferred procedure '%.*s' parameters do not match the results of initial procedure '%.*s'", LIT(dst->token.string), LIT(src->token.string));
continue;
}
@@ -6249,8 +6228,8 @@ gb_internal void check_deferred_procedures(Checker *c) {
gbString s = type_to_string(src_results);
gbString d = type_to_string(dst_params);
error(src->token, "Deferred procedure '%.*s' parameters do not match the results of initial procedure '%.*s':\n\t(%s) =/= (%s)",
- LIT(src->token.string), LIT(dst->token.string),
- s, d
+ LIT(dst->token.string), LIT(src->token.string),
+ d, s
);
gb_string_free(d);
gb_string_free(s);
@@ -6302,8 +6281,8 @@ gb_internal void check_deferred_procedures(Checker *c) {
gbString s = type_to_string(tsrc);
gbString d = type_to_string(dst_params);
error(src->token, "Deferred procedure '%.*s' parameters do not match the results of initial procedure '%.*s':\n\t(%s) =/= (%s)",
- LIT(src->token.string), LIT(dst->token.string),
- s, d
+ LIT(dst->token.string), LIT(src->token.string),
+ d, s
);
gb_string_free(d);
gb_string_free(s);
diff --git a/src/docs_format.cpp b/src/docs_format.cpp
index ca6ecb5c2..6378971d0 100644
--- a/src/docs_format.cpp
+++ b/src/docs_format.cpp
@@ -79,8 +79,7 @@ enum OdinDocTypeKind : u32 {
OdinDocType_SOAStructFixed = 17,
OdinDocType_SOAStructSlice = 18,
OdinDocType_SOAStructDynamic = 19,
- OdinDocType_RelativePointer = 20,
- OdinDocType_RelativeMultiPointer = 21,
+
OdinDocType_MultiPointer = 22,
OdinDocType_Matrix = 23,
OdinDocType_SoaPointer = 24,
diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp
index 835dfdff1..341b3fa6b 100644
--- a/src/docs_writer.cpp
+++ b/src/docs_writer.cpp
@@ -776,24 +776,6 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
doc_type.types = odin_doc_type_as_slice(w, type->SimdVector.elem);
// TODO(bill):
break;
- case Type_RelativePointer:
- doc_type.kind = OdinDocType_RelativePointer;
- {
- OdinDocTypeIndex types[2] = {};
- types[0] = odin_doc_type(w, type->RelativePointer.pointer_type);
- types[1] = odin_doc_type(w, type->RelativePointer.base_integer);
- doc_type.types = odin_write_slice(w, types, gb_count_of(types));
- }
- break;
- case Type_RelativeMultiPointer:
- doc_type.kind = OdinDocType_RelativeMultiPointer;
- {
- OdinDocTypeIndex types[2] = {};
- types[0] = odin_doc_type(w, type->RelativeMultiPointer.pointer_type);
- types[1] = odin_doc_type(w, type->RelativeMultiPointer.base_integer);
- doc_type.types = odin_write_slice(w, types, gb_count_of(types));
- }
- break;
case Type_Matrix:
doc_type.kind = OdinDocType_Matrix;
diff --git a/src/exact_value.cpp b/src/exact_value.cpp
index 1a42a82a9..5d6016ecc 100644
--- a/src/exact_value.cpp
+++ b/src/exact_value.cpp
@@ -687,6 +687,7 @@ gb_internal void match_exact_values(ExactValue *x, ExactValue *y) {
case ExactValue_String:
case ExactValue_Quaternion:
case ExactValue_Pointer:
+ case ExactValue_Compound:
case ExactValue_Procedure:
case ExactValue_Typeid:
return;
diff --git a/src/gb/gb.h b/src/gb/gb.h
index 1fef4b4f5..f74026c7d 100644
--- a/src/gb/gb.h
+++ b/src/gb/gb.h
@@ -2541,7 +2541,11 @@ gb_inline void const *gb_pointer_add_const(void const *ptr, isize bytes) {
gb_inline void const *gb_pointer_sub_const(void const *ptr, isize bytes) { return cast(void const *)(cast(u8 const *)ptr - bytes); }
gb_inline isize gb_pointer_diff (void const *begin, void const *end) { return cast(isize)(cast(u8 const *)end - cast(u8 const *)begin); }
-gb_inline void gb_zero_size(void *ptr, isize size) { memset(ptr, 0, size); }
+gb_inline void gb_zero_size(void *ptr, isize size) {
+ if (size != 0) {
+ memset(ptr, 0, size);
+ }
+}
#if defined(_MSC_VER) && !defined(__clang__)
diff --git a/src/linker.cpp b/src/linker.cpp
index 500fead69..261d6e7a4 100644
--- a/src/linker.cpp
+++ b/src/linker.cpp
@@ -167,8 +167,10 @@ gb_internal i32 linker_stage(LinkerData *gen) {
if (is_windows) {
String section_name = str_lit("msvc-link");
- if (build_context.use_lld) {
- section_name = str_lit("lld-link");
+ switch (build_context.linker_choice) {
+ case Linker_Default: break;
+ case Linker_lld: section_name = str_lit("lld-link"); break;
+ case Linker_radlink: section_name = str_lit("rad-link"); break;
}
timings_start_section(timings, section_name);
@@ -304,7 +306,48 @@ gb_internal i32 linker_stage(LinkerData *gen) {
String windows_sdk_bin_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Win_SDK_Bin_Path]);
defer (gb_free(heap_allocator(), windows_sdk_bin_path.text));
- if (!build_context.use_lld) { // msvc
+ switch (build_context.linker_choice) {
+ case Linker_lld:
+ result = system_exec_command_line_app("msvc-lld-link",
+ "\"%.*s\\bin\\lld-link\" %s -OUT:\"%.*s\" %s "
+ "/nologo /incremental:no /opt:ref /subsystem:%.*s "
+ "%.*s "
+ "%.*s "
+ "%s "
+ "",
+ LIT(build_context.ODIN_ROOT), object_files, LIT(output_filename),
+ link_settings,
+ LIT(build_context.ODIN_WINDOWS_SUBSYSTEM),
+ LIT(build_context.link_flags),
+ LIT(build_context.extra_linker_flags),
+ lib_str
+ );
+
+ if (result) {
+ return result;
+ }
+ break;
+ case Linker_radlink:
+ result = system_exec_command_line_app("msvc-rad-link",
+ "\"%.*s\\bin\\radlink\" %s -OUT:\"%.*s\" %s "
+ "/nologo /incremental:no /opt:ref /subsystem:%.*s "
+ "%.*s "
+ "%.*s "
+ "%s "
+ "",
+ LIT(build_context.ODIN_ROOT), object_files, LIT(output_filename),
+ link_settings,
+ LIT(build_context.ODIN_WINDOWS_SUBSYSTEM),
+ LIT(build_context.link_flags),
+ LIT(build_context.extra_linker_flags),
+ lib_str
+ );
+
+ if (result) {
+ return result;
+ }
+ break;
+ default: { // msvc
String res_path = quote_path(heap_allocator(), build_context.build_paths[BuildPath_RES]);
String rc_path = quote_path(heap_allocator(), build_context.build_paths[BuildPath_RC]);
defer (gb_free(heap_allocator(), res_path.text));
@@ -365,25 +408,8 @@ gb_internal i32 linker_stage(LinkerData *gen) {
if (result) {
return result;
}
- } else { // lld
- result = system_exec_command_line_app("msvc-lld-link",
- "\"%.*s\\bin\\lld-link\" %s -OUT:\"%.*s\" %s "
- "/nologo /incremental:no /opt:ref /subsystem:%.*s "
- "%.*s "
- "%.*s "
- "%s "
- "",
- LIT(build_context.ODIN_ROOT), object_files, LIT(output_filename),
- link_settings,
- LIT(build_context.ODIN_WINDOWS_SUBSYSTEM),
- LIT(build_context.link_flags),
- LIT(build_context.extra_linker_flags),
- lib_str
- );
-
- if (result) {
- return result;
- }
+ break;
+ }
}
} else {
timings_start_section(timings, str_lit("ld-link"));
@@ -605,9 +631,18 @@ gb_internal i32 linker_stage(LinkerData *gen) {
link_settings = gb_string_appendc(link_settings, "-Wl,-fini,'_odin_exit_point' ");
}
- } else if (build_context.metrics.os != TargetOs_openbsd && build_context.metrics.os != TargetOs_haiku && build_context.metrics.arch != TargetArch_riscv64) {
- // OpenBSD and Haiku default to PIE executable. do not pass -no-pie for it.
- link_settings = gb_string_appendc(link_settings, "-no-pie ");
+ }
+
+ if (build_context.build_mode == BuildMode_Executable && build_context.reloc_mode == RelocMode_PIC) {
+ // Do not disable PIE, let the linker choose. (most likely you want it enabled)
+ } else if (build_context.build_mode != BuildMode_DynamicLibrary) {
+ if (build_context.metrics.os != TargetOs_openbsd
+ && build_context.metrics.os != TargetOs_haiku
+ && build_context.metrics.arch != TargetArch_riscv64
+ ) {
+ // OpenBSD and Haiku default to PIE executable. do not pass -no-pie for it.
+ link_settings = gb_string_appendc(link_settings, "-no-pie ");
+ }
}
gbString platform_lib_str = gb_string_make(heap_allocator(), "");
@@ -670,7 +705,7 @@ gb_internal i32 linker_stage(LinkerData *gen) {
link_command_line = gb_string_append_fmt(link_command_line, " %.*s ", LIT(build_context.extra_linker_flags));
link_command_line = gb_string_append_fmt(link_command_line, " %s ", link_settings);
- if (build_context.use_lld) {
+ if (build_context.linker_choice == Linker_lld) {
link_command_line = gb_string_append_fmt(link_command_line, " -fuse-ld=lld");
result = system_exec_command_line_app("lld-link", link_command_line);
} else {
@@ -684,7 +719,7 @@ gb_internal i32 linker_stage(LinkerData *gen) {
if (is_osx && build_context.ODIN_DEBUG) {
// NOTE: macOS links DWARF symbols dynamically. Dsymutil will map the stubs in the exe
// to the symbols in the object file
- result = system_exec_command_line_app("dsymutil", "dsymutil %.*s", LIT(output_filename));
+ result = system_exec_command_line_app("dsymutil", "dsymutil \"%.*s\"", LIT(output_filename));
if (result) {
return result;
diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp
index 42086b09d..0b2bb7956 100644
--- a/src/llvm_abi.cpp
+++ b/src/llvm_abi.cpp
@@ -531,6 +531,7 @@ namespace lbAbiAmd64SysV {
RegClass_SSEInt16,
RegClass_SSEInt32,
RegClass_SSEInt64,
+ RegClass_SSEInt128,
RegClass_SSEUp,
RegClass_X87,
RegClass_X87Up,
@@ -572,6 +573,15 @@ namespace lbAbiAmd64SysV {
gb_internal Array<RegClass> classify(LLVMTypeRef t);
gb_internal LLVMTypeRef llreg(LLVMContextRef c, Array<RegClass> const &reg_classes, LLVMTypeRef type);
+ gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type) {
+ if (!return_is_defined) {
+ return lb_arg_type_direct(LLVMVoidTypeInContext(c));
+ }
+ LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
+
+ return amd64_type(c, return_type, Amd64TypeAttribute_StructRect, ft->calling_convention);
+ }
+
gb_internal LB_ABI_INFO(abi_info) {
LLVMContextRef c = m->ctx;
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
@@ -582,12 +592,7 @@ namespace lbAbiAmd64SysV {
for (unsigned i = 0; i < arg_count; i++) {
ft->args[i] = amd64_type(c, arg_types[i], Amd64TypeAttribute_ByVal, calling_convention);
}
-
- if (return_is_defined) {
- ft->ret = amd64_type(c, return_type, Amd64TypeAttribute_StructRect, calling_convention);
- } else {
- ft->ret = lb_arg_type_direct(LLVMVoidTypeInContext(c));
- }
+ ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple);
return ft;
}
@@ -616,6 +621,10 @@ namespace lbAbiAmd64SysV {
}
switch (kind) {
case LLVMIntegerTypeKind:
+ if (LLVM_VERSION_MAJOR >= 18 && sz >= 16) {
+ return true;
+ }
+ return false;
case LLVMHalfTypeKind:
case LLVMFloatTypeKind:
case LLVMDoubleTypeKind:
diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp
index 68f95cb03..464efa325 100644
--- a/src/llvm_backend.hpp
+++ b/src/llvm_backend.hpp
@@ -75,7 +75,6 @@ enum lbAddrKind {
lbAddr_Context,
lbAddr_SoaVariable,
- lbAddr_RelativePointer,
lbAddr_Swizzle,
lbAddr_SwizzleLarge,
@@ -104,9 +103,6 @@ struct lbAddr {
Ast *node;
} index_set;
struct {
- bool deref;
- } relative;
- struct {
Type *type;
u8 count; // 2, 3, or 4 components
u8 indices[4];
diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp
index 5cc79dcc8..464f7065c 100644
--- a/src/llvm_backend_debug.cpp
+++ b/src/llvm_backend_debug.cpp
@@ -920,17 +920,6 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
elem, subscripts, gb_count_of(subscripts));
}
- case Type_RelativePointer: {
- LLVMMetadataRef base_integer = lb_debug_type(m, type->RelativePointer.base_integer);
- gbString name = type_to_string(type, temporary_allocator());
- return LLVMDIBuilderCreateTypedef(m->debug_builder, base_integer, name, gb_string_length(name), nullptr, 0, nullptr, cast(u32)(8*type_align_of(type)));
- }
- case Type_RelativeMultiPointer: {
- LLVMMetadataRef base_integer = lb_debug_type(m, type->RelativeMultiPointer.base_integer);
- gbString name = type_to_string(type, temporary_allocator());
- return LLVMDIBuilderCreateTypedef(m->debug_builder, base_integer, name, gb_string_length(name), nullptr, 0, nullptr, cast(u32)(8*type_align_of(type)));
- }
-
case Type_Matrix: {
LLVMMetadataRef subscripts[1] = {};
subscripts[0] = LLVMDIBuilderGetOrCreateSubrange(m->debug_builder,
diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp
index 58467db2e..80c469ae6 100644
--- a/src/llvm_backend_expr.cpp
+++ b/src/llvm_backend_expr.cpp
@@ -130,7 +130,7 @@ gb_internal lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x,
LLVMTypeRef vector_type = nullptr;
if (op != Token_Not && lb_try_vector_cast(p->module, val, &vector_type)) {
LLVMValueRef vp = LLVMBuildPointerCast(p->builder, val.value, LLVMPointerType(vector_type, 0), "");
- LLVMValueRef v = LLVMBuildLoad2(p->builder, vector_type, vp, "");
+ LLVMValueRef v = OdinLLVMBuildLoad(p, vector_type, vp);
LLVMValueRef opv = nullptr;
switch (op) {
@@ -324,8 +324,8 @@ gb_internal bool lb_try_direct_vector_arith(lbProcedure *p, TokenKind op, lbValu
LLVMValueRef lhs_vp = LLVMBuildPointerCast(p->builder, lhs_ptr.value, LLVMPointerType(vector_type, 0), "");
LLVMValueRef rhs_vp = LLVMBuildPointerCast(p->builder, rhs_ptr.value, LLVMPointerType(vector_type, 0), "");
- LLVMValueRef x = LLVMBuildLoad2(p->builder, vector_type, lhs_vp, "");
- LLVMValueRef y = LLVMBuildLoad2(p->builder, vector_type, rhs_vp, "");
+ LLVMValueRef x = OdinLLVMBuildLoad(p, vector_type, lhs_vp);
+ LLVMValueRef y = OdinLLVMBuildLoad(p, vector_type, rhs_vp);
LLVMValueRef z = nullptr;
if (is_type_float(integral_type)) {
@@ -551,15 +551,14 @@ gb_internal LLVMValueRef lb_matrix_to_vector(lbProcedure *p, lbValue matrix) {
Type *mt = base_type(matrix.type);
GB_ASSERT(mt->kind == Type_Matrix);
LLVMTypeRef elem_type = lb_type(p->module, mt->Matrix.elem);
-
+
unsigned total_count = cast(unsigned)matrix_type_total_internal_elems(mt);
LLVMTypeRef total_matrix_type = LLVMVectorType(elem_type, total_count);
-
+
#if 1
LLVMValueRef ptr = lb_address_from_load_or_generate_local(p, matrix).value;
LLVMValueRef matrix_vector_ptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(total_matrix_type, 0), "");
- LLVMValueRef matrix_vector = LLVMBuildLoad2(p->builder, total_matrix_type, matrix_vector_ptr, "");
- LLVMSetAlignment(matrix_vector, cast(unsigned)type_align_of(mt));
+ LLVMValueRef matrix_vector = OdinLLVMBuildLoadAligned(p, total_matrix_type, matrix_vector_ptr, type_align_of(mt));
return matrix_vector;
#else
LLVMValueRef matrix_vector = LLVMBuildBitCast(p->builder, matrix.value, total_matrix_type, "");
@@ -1225,10 +1224,10 @@ gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbV
lbValue d3 = lb_emit_struct_ep(p, res.addr, 3);
if (immediate_type != ft) {
- d0 = lb_emit_conv(p, d0, ft);
- d1 = lb_emit_conv(p, d1, ft);
- d2 = lb_emit_conv(p, d2, ft);
- d3 = lb_emit_conv(p, d3, ft);
+ z0 = lb_emit_conv(p, z0, ft);
+ z1 = lb_emit_conv(p, z1, ft);
+ z2 = lb_emit_conv(p, z2, ft);
+ z3 = lb_emit_conv(p, z3, ft);
}
lb_emit_store(p, d0, z0);
@@ -1648,7 +1647,7 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
lb_emit_store(p, a1, id);
return lb_addr_load(p, res);
} else if (dst->kind == Type_Basic) {
- if (src->Basic.kind == Basic_string && dst->Basic.kind == Basic_cstring) {
+ if (src->kind == Type_Basic && src->Basic.kind == Basic_string && dst->Basic.kind == Basic_cstring) {
String str = lb_get_const_string(m, value);
lbValue res = {};
res.type = t;
@@ -2364,12 +2363,23 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
GB_ASSERT(src->kind == Type_Matrix);
lbAddr v = lb_add_local_generated(p, t, true);
- if (is_matrix_square(dst) && is_matrix_square(dst)) {
+ if (dst->Matrix.row_count == src->Matrix.row_count &&
+ dst->Matrix.column_count == src->Matrix.column_count) {
+ for (i64 j = 0; j < dst->Matrix.column_count; j++) {
+ for (i64 i = 0; i < dst->Matrix.row_count; i++) {
+ lbValue d = lb_emit_matrix_epi(p, v.addr, i, j);
+ lbValue s = lb_emit_matrix_ev(p, value, i, j);
+ s = lb_emit_conv(p, s, dst->Matrix.elem);
+ lb_emit_store(p, d, s);
+ }
+ }
+ } else if (is_matrix_square(dst) && is_matrix_square(dst)) {
for (i64 j = 0; j < dst->Matrix.column_count; j++) {
for (i64 i = 0; i < dst->Matrix.row_count; i++) {
if (i < src->Matrix.row_count && j < src->Matrix.column_count) {
lbValue d = lb_emit_matrix_epi(p, v.addr, i, j);
lbValue s = lb_emit_matrix_ev(p, value, i, j);
+ s = lb_emit_conv(p, s, dst->Matrix.elem);
lb_emit_store(p, d, s);
} else if (i == j) {
lbValue d = lb_emit_matrix_epi(p, v.addr, i, j);
@@ -2555,17 +2565,27 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left
if (are_types_identical(a, b)) {
// NOTE(bill): No need for a conversion
- } else if (lb_is_const(left) || lb_is_const_nil(left)) {
+ } else if ((lb_is_const(left) && !is_type_array(left.type)) || lb_is_const_nil(left)) {
+ // NOTE(karl): !is_type_array(left.type) is there to avoid lb_emit_conv
+ // trying to convert a constant array into a non-array. In that case we
+ // want the `else` branch to happen, so it can try to convert the
+ // non-array into an array instead.
+
if (lb_is_const_nil(left)) {
+ if (internal_check_is_assignable_to(right.type, left.type)) {
+ right = lb_emit_conv(p, right, left.type);
+ }
return lb_emit_comp_against_nil(p, op_kind, right);
}
left = lb_emit_conv(p, left, right.type);
- } else if (lb_is_const(right) || lb_is_const_nil(right)) {
+ } else if ((lb_is_const(right) && !is_type_array(right.type)) || lb_is_const_nil(right)) {
if (lb_is_const_nil(right)) {
+ if (internal_check_is_assignable_to(left.type, right.type)) {
+ left = lb_emit_conv(p, left, right.type);
+ }
return lb_emit_comp_against_nil(p, op_kind, left);
}
right = lb_emit_conv(p, right, left.type);
-
} else {
Type *lt = left.type;
Type *rt = right.type;
@@ -4180,30 +4200,6 @@ gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) {
return lb_addr(v);
}
- case Type_RelativeMultiPointer: {
- lbAddr rel_ptr_addr = {};
- if (deref) {
- lbValue rel_ptr_ptr = lb_build_expr(p, ie->expr);
- rel_ptr_addr = lb_addr(rel_ptr_ptr);
- } else {
- rel_ptr_addr = lb_build_addr(p, ie->expr);
- }
- lbValue rel_ptr = lb_relative_pointer_to_pointer(p, rel_ptr_addr);
-
- lbValue index = lb_build_expr(p, ie->index);
- index = lb_emit_conv(p, index, t_int);
- lbValue v = {};
-
- Type *pointer_type = base_type(t->RelativeMultiPointer.pointer_type);
- GB_ASSERT(pointer_type->kind == Type_MultiPointer);
- Type *elem = pointer_type->MultiPointer.elem;
-
- LLVMValueRef indices[1] = {index.value};
- v.value = LLVMBuildGEP2(p->builder, lb_type(p->module, elem), rel_ptr.value, indices, 1, "");
- v.type = alloc_type_pointer(elem);
- return lb_addr(v);
- }
-
case Type_DynamicArray: {
lbValue dynamic_array = {};
dynamic_array = lb_build_expr(p, ie->expr);
@@ -4313,13 +4309,6 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) {
return slice;
}
- case Type_RelativePointer:
- GB_PANIC("TODO(bill): Type_RelativePointer should be handled above already on the lb_addr_load");
- break;
- case Type_RelativeMultiPointer:
- GB_PANIC("TODO(bill): Type_RelativeMultiPointer should be handled above already on the lb_addr_load");
- break;
-
case Type_DynamicArray: {
Type *elem_type = type->DynamicArray.elem;
Type *slice_type = alloc_type_slice(elem_type);
@@ -5323,11 +5312,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
case_ast_node(de, DerefExpr, expr);
Type *t = type_of_expr(de->expr);
- if (is_type_relative_pointer(t)) {
- lbAddr addr = lb_build_addr(p, de->expr);
- addr.relative.deref = true;
- return addr;
- } else if (is_type_soa_pointer(t)) {
+ if (is_type_soa_pointer(t)) {
lbValue value = lb_build_expr(p, de->expr);
lbValue ptr = lb_emit_struct_ev(p, value, 0);
lbValue idx = lb_emit_struct_ev(p, value, 1);
diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp
index 842a1cbc8..9dc603993 100644
--- a/src/llvm_backend_general.cpp
+++ b/src/llvm_backend_general.cpp
@@ -409,14 +409,6 @@ gb_internal lbModule *lb_module_of_entity(lbGenerator *gen, Entity *e) {
gb_internal lbAddr lb_addr(lbValue addr) {
lbAddr v = {lbAddr_Default, addr};
- if (addr.type != nullptr && is_type_relative_pointer(type_deref(addr.type))) {
- GB_ASSERT(is_type_pointer(addr.type));
- v.kind = lbAddr_RelativePointer;
- } else if (addr.type != nullptr && is_type_relative_multi_pointer(type_deref(addr.type))) {
- GB_ASSERT(is_type_pointer(addr.type) ||
- is_type_multi_pointer(addr.type));
- v.kind = lbAddr_RelativePointer;
- }
return v;
}
@@ -501,42 +493,6 @@ gb_internal Type *lb_addr_type(lbAddr const &addr) {
return type_deref(addr.addr.type);
}
-
-gb_internal lbValue lb_relative_pointer_to_pointer(lbProcedure *p, lbAddr const &addr) {
- GB_ASSERT(addr.kind == lbAddr_RelativePointer);
-
- Type *t = base_type(lb_addr_type(addr));
- GB_ASSERT(is_type_relative_pointer(t) || is_type_relative_multi_pointer(t));
-
- Type *pointer_type = nullptr;
- Type *base_integer = nullptr;
- if (t->kind == Type_RelativePointer) {
- pointer_type = t->RelativePointer.pointer_type;
- base_integer = t->RelativePointer.base_integer;
- } else if (t->kind == Type_RelativeMultiPointer) {
- pointer_type = t->RelativeMultiPointer.pointer_type;
- base_integer = t->RelativeMultiPointer.base_integer;
- }
-
- lbValue ptr = lb_emit_conv(p, addr.addr, t_uintptr);
- lbValue offset = lb_emit_conv(p, ptr, alloc_type_pointer(base_integer));
- offset = lb_emit_load(p, offset);
-
- if (!is_type_unsigned(base_integer)) {
- offset = lb_emit_conv(p, offset, t_i64);
- }
- offset = lb_emit_conv(p, offset, t_uintptr);
- lbValue absolute_ptr = lb_emit_arith(p, Token_Add, ptr, offset, t_uintptr);
- absolute_ptr = lb_emit_conv(p, absolute_ptr, pointer_type);
-
- lbValue cond = lb_emit_comp(p, Token_CmpEq, offset, lb_const_nil(p->module, base_integer));
-
- // NOTE(bill): nil check
- lbValue nil_ptr = lb_const_nil(p->module, pointer_type);
- lbValue final_ptr = lb_emit_select(p, cond, nil_ptr, absolute_ptr);
- return final_ptr;
-}
-
gb_internal lbValue lb_make_soa_pointer(lbProcedure *p, Type *type, lbValue const &addr, lbValue const &index) {
lbAddr v = lb_add_local_generated(p, type, false);
lbValue ptr = lb_emit_struct_ep(p, v.addr, 0);
@@ -557,9 +513,6 @@ gb_internal lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) {
case lbAddr_Map:
return lb_internal_dynamic_map_get_ptr(p, addr.addr, addr.map.key);
- case lbAddr_RelativePointer:
- return lb_relative_pointer_to_pointer(p, addr);
-
case lbAddr_SoaVariable:
{
Type *soa_ptr_type = alloc_type_soa_pointer(lb_addr_type(addr));
@@ -584,9 +537,6 @@ gb_internal lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) {
gb_internal lbValue lb_build_addr_ptr(lbProcedure *p, Ast *expr) {
lbAddr addr = lb_build_addr(p, expr);
- if (addr.kind == lbAddr_RelativePointer) {
- return addr.addr;
- }
return lb_addr_get_ptr(p, addr);
}
@@ -722,7 +672,10 @@ gb_internal unsigned lb_try_get_alignment(LLVMValueRef addr_ptr, unsigned defaul
gb_internal bool lb_try_update_alignment(LLVMValueRef addr_ptr, unsigned alignment) {
if (LLVMIsAGlobalValue(addr_ptr) || LLVMIsAAllocaInst(addr_ptr) || LLVMIsALoadInst(addr_ptr)) {
if (LLVMGetAlignment(addr_ptr) < alignment) {
- if (LLVMIsAAllocaInst(addr_ptr) || LLVMIsAGlobalValue(addr_ptr)) {
+ if (LLVMIsAAllocaInst(addr_ptr)) {
+ LLVMSetAlignment(addr_ptr, alignment);
+ } else if (LLVMIsAGlobalValue(addr_ptr) && LLVMGetLinkage(addr_ptr) != LLVMExternalLinkage) {
+ // NOTE(laytan): setting alignment of an external global just changes the alignment we expect it to be.
LLVMSetAlignment(addr_ptr, alignment);
}
}
@@ -755,10 +708,7 @@ gb_internal bool lb_try_vector_cast(lbModule *m, lbValue ptr, LLVMTypeRef *vecto
LLVMValueRef addr_ptr = ptr.value;
if (LLVMIsAAllocaInst(addr_ptr) || LLVMIsAGlobalValue(addr_ptr)) {
- unsigned alignment = LLVMGetAlignment(addr_ptr);
- alignment = gb_max(alignment, vector_alignment);
- possible = true;
- LLVMSetAlignment(addr_ptr, alignment);
+ possible = lb_try_update_alignment(addr_ptr, vector_alignment);
} else if (LLVMIsALoadInst(addr_ptr)) {
unsigned alignment = LLVMGetAlignment(addr_ptr);
possible = alignment >= vector_alignment;
@@ -774,6 +724,36 @@ gb_internal bool lb_try_vector_cast(lbModule *m, lbValue ptr, LLVMTypeRef *vecto
return false;
}
+gb_internal LLVMValueRef OdinLLVMBuildLoad(lbProcedure *p, LLVMTypeRef type, LLVMValueRef value) {
+ LLVMValueRef result = LLVMBuildLoad2(p->builder, type, value, "");
+
+ // If it is not an instruction it isn't a GEP, so we don't need to track alignment in the metadata,
+ // which is not possible anyway (only LLVM instructions can have metadata).
+ if (LLVMIsAInstruction(value)) {
+ u64 is_packed = lb_get_metadata_custom_u64(p->module, value, ODIN_METADATA_IS_PACKED);
+ if (is_packed != 0) {
+ LLVMSetAlignment(result, 1);
+ }
+ }
+
+ return result;
+}
+
+gb_internal LLVMValueRef OdinLLVMBuildLoadAligned(lbProcedure *p, LLVMTypeRef type, LLVMValueRef value, i64 alignment) {
+ LLVMValueRef result = LLVMBuildLoad2(p->builder, type, value, "");
+
+ LLVMSetAlignment(result, cast(unsigned)alignment);
+
+ if (LLVMIsAInstruction(value)) {
+ u64 is_packed = lb_get_metadata_custom_u64(p->module, value, ODIN_METADATA_IS_PACKED);
+ if (is_packed != 0) {
+ LLVMSetAlignment(result, 1);
+ }
+ }
+
+ return result;
+}
+
gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
if (addr.addr.value == nullptr) {
return;
@@ -789,10 +769,6 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
value.value = LLVMConstNull(lb_type(p->module, t));
}
- if (addr.kind == lbAddr_RelativePointer && addr.relative.deref) {
- addr = lb_addr(lb_address_from_load(p, lb_addr_load(p, addr)));
- }
-
if (addr.kind == lbAddr_BitField) {
lbValue dst = addr.addr;
if (is_type_endian_big(addr.bitfield.type)) {
@@ -830,44 +806,6 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
lb_emit_runtime_call(p, "__write_bits", args);
}
return;
- } else if (addr.kind == lbAddr_RelativePointer) {
- Type *rel_ptr = base_type(lb_addr_type(addr));
- GB_ASSERT(rel_ptr->kind == Type_RelativePointer ||
- rel_ptr->kind == Type_RelativeMultiPointer);
- Type *pointer_type = nullptr;
- Type *base_integer = nullptr;
-
- if (rel_ptr->kind == Type_RelativePointer) {
- pointer_type = rel_ptr->RelativePointer.pointer_type;
- base_integer = rel_ptr->RelativePointer.base_integer;
- } else if (rel_ptr->kind == Type_RelativeMultiPointer) {
- pointer_type = rel_ptr->RelativeMultiPointer.pointer_type;
- base_integer = rel_ptr->RelativeMultiPointer.base_integer;
- }
-
- value = lb_emit_conv(p, value, pointer_type);
-
- GB_ASSERT(is_type_pointer(addr.addr.type));
- lbValue ptr = lb_emit_conv(p, addr.addr, t_uintptr);
- lbValue val_ptr = lb_emit_conv(p, value, t_uintptr);
- lbValue offset = {};
- offset.value = LLVMBuildSub(p->builder, val_ptr.value, ptr.value, "");
- offset.type = t_uintptr;
-
- if (!is_type_unsigned(base_integer)) {
- offset = lb_emit_conv(p, offset, t_i64);
- }
- offset = lb_emit_conv(p, offset, base_integer);
-
- lbValue offset_ptr = lb_emit_conv(p, addr.addr, alloc_type_pointer(base_integer));
- offset = lb_emit_select(p,
- lb_emit_comp(p, Token_CmpEq, val_ptr, lb_const_nil(p->module, t_uintptr)),
- lb_const_nil(p->module, base_integer),
- offset
- );
- LLVMBuildStore(p->builder, offset.value, offset_ptr.value);
- return;
-
} else if (addr.kind == lbAddr_Map) {
lb_internal_dynamic_map_set(p, addr.addr, addr.map.type, addr.map.key, value, p->curr_stmt);
return;
@@ -1119,7 +1057,7 @@ gb_internal lbValue lb_emit_load(lbProcedure *p, lbValue value) {
Type *vt = base_type(value.type);
GB_ASSERT(vt->kind == Type_MultiPointer);
Type *t = vt->MultiPointer.elem;
- LLVMValueRef v = LLVMBuildLoad2(p->builder, lb_type(p->module, t), value.value, "");
+ LLVMValueRef v = OdinLLVMBuildLoad(p, lb_type(p->module, t), value.value);
return lbValue{v, t};
} else if (is_type_soa_pointer(value.type)) {
lbValue ptr = lb_emit_struct_ev(p, value, 0);
@@ -1130,16 +1068,7 @@ gb_internal lbValue lb_emit_load(lbProcedure *p, lbValue value) {
GB_ASSERT_MSG(is_type_pointer(value.type), "%s", type_to_string(value.type));
Type *t = type_deref(value.type);
- LLVMValueRef v = LLVMBuildLoad2(p->builder, lb_type(p->module, t), value.value, "");
-
- // If it is not an instruction it isn't a GEP, so we don't need to track alignment in the metadata,
- // which is not possible anyway (only LLVM instructions can have metadata).
- if (LLVMIsAInstruction(value.value)) {
- u64 is_packed = lb_get_metadata_custom_u64(p->module, value.value, ODIN_METADATA_IS_PACKED);
- if (is_packed != 0) {
- LLVMSetAlignment(v, 1);
- }
- }
+ LLVMValueRef v = OdinLLVMBuildLoad(p, lb_type(p->module, t), value.value);
return lbValue{v, t};
}
@@ -1225,46 +1154,6 @@ gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) {
}
return r;
- } else if (addr.kind == lbAddr_RelativePointer) {
- Type *rel_ptr = base_type(lb_addr_type(addr));
- Type *base_integer = nullptr;
- Type *pointer_type = nullptr;
- GB_ASSERT(rel_ptr->kind == Type_RelativePointer ||
- rel_ptr->kind == Type_RelativeMultiPointer);
-
- if (rel_ptr->kind == Type_RelativePointer) {
- base_integer = rel_ptr->RelativePointer.base_integer;
- pointer_type = rel_ptr->RelativePointer.pointer_type;
- } else if (rel_ptr->kind == Type_RelativeMultiPointer) {
- base_integer = rel_ptr->RelativeMultiPointer.base_integer;
- pointer_type = rel_ptr->RelativeMultiPointer.pointer_type;
- }
-
- lbValue ptr = lb_emit_conv(p, addr.addr, t_uintptr);
- lbValue offset = lb_emit_conv(p, ptr, alloc_type_pointer(base_integer));
- offset = lb_emit_load(p, offset);
-
-
- if (!is_type_unsigned(base_integer)) {
- offset = lb_emit_conv(p, offset, t_i64);
- }
- offset = lb_emit_conv(p, offset, t_uintptr);
- lbValue absolute_ptr = lb_emit_arith(p, Token_Add, ptr, offset, t_uintptr);
- absolute_ptr = lb_emit_conv(p, absolute_ptr, pointer_type);
-
- lbValue cond = lb_emit_comp(p, Token_CmpEq, offset, lb_const_nil(p->module, base_integer));
-
- // NOTE(bill): nil check
- lbValue nil_ptr = lb_const_nil(p->module, pointer_type);
- lbValue final_ptr = {};
- final_ptr.type = absolute_ptr.type;
- final_ptr.value = LLVMBuildSelect(p->builder, cond.value, nil_ptr.value, absolute_ptr.value, "");
-
- if (rel_ptr->kind == Type_RelativeMultiPointer) {
- return final_ptr;
- }
- return lb_emit_load(p, final_ptr);
-
} else if (addr.kind == lbAddr_Map) {
Type *map_type = base_type(type_deref(addr.addr.type));
GB_ASSERT(map_type->kind == Type_Map);
@@ -1413,7 +1302,7 @@ gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) {
LLVMTypeRef vector_type = nullptr;
if (lb_try_vector_cast(p->module, addr.addr, &vector_type)) {
LLVMValueRef vp = LLVMBuildPointerCast(p->builder, addr.addr.value, LLVMPointerType(vector_type, 0), "");
- LLVMValueRef v = LLVMBuildLoad2(p->builder, vector_type, vp, "");
+ LLVMValueRef v = OdinLLVMBuildLoad(p, vector_type, vp);
LLVMValueRef scalars[4] = {};
for (u8 i = 0; i < addr.swizzle.count; i++) {
scalars[i] = LLVMConstInt(lb_type(p->module, t_u32), addr.swizzle.indices[i], false);
@@ -2357,13 +2246,6 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
case Type_SimdVector:
return LLVMVectorType(lb_type(m, type->SimdVector.elem), cast(unsigned)type->SimdVector.count);
-
- case Type_RelativePointer:
- return lb_type_internal(m, type->RelativePointer.base_integer);
- case Type_RelativeMultiPointer:
- return lb_type_internal(m, type->RelativeMultiPointer.base_integer);
-
-
case Type_Matrix:
{
@@ -2710,7 +2592,7 @@ general_end:;
if (LLVMIsALoadInst(val) && (src_size >= dst_size && src_align >= dst_align)) {
LLVMValueRef val_ptr = LLVMGetOperand(val, 0);
val_ptr = LLVMBuildPointerCast(p->builder, val_ptr, LLVMPointerType(dst_type, 0), "");
- LLVMValueRef loaded_val = LLVMBuildLoad2(p->builder, dst_type, val_ptr, "");
+ LLVMValueRef loaded_val = OdinLLVMBuildLoad(p, dst_type, val_ptr);
// LLVMSetAlignment(loaded_val, gb_min(src_align, dst_align));
@@ -2726,7 +2608,7 @@ general_end:;
LLVMValueRef nptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(src_type, 0), "");
LLVMBuildStore(p->builder, val, nptr);
- return LLVMBuildLoad2(p->builder, dst_type, ptr, "");
+ return OdinLLVMBuildLoad(p, dst_type, ptr);
}
}
diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp
index d84599eb0..5aee5b639 100644
--- a/src/llvm_backend_proc.cpp
+++ b/src/llvm_backend_proc.cpp
@@ -2568,7 +2568,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
case BuiltinProc_atomic_load_explicit: {
lbValue dst = lb_build_expr(p, ce->args[0]);
- LLVMValueRef instr = LLVMBuildLoad2(p->builder, lb_type(p->module, type_deref(dst.type)), dst.value, "");
+ LLVMValueRef instr = OdinLLVMBuildLoad(p, lb_type(p->module, type_deref(dst.type)), dst.value);
switch (id) {
case BuiltinProc_non_temporal_load:
{
@@ -2621,8 +2621,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
if (is_type_simd_vector(t)) {
lbValue res = {};
res.type = t;
- res.value = LLVMBuildLoad2(p->builder, lb_type(p->module, t), src.value, "");
- LLVMSetAlignment(res.value, 1);
+ res.value = OdinLLVMBuildLoadAligned(p, lb_type(p->module, t), src.value, 1);
return res;
} else {
lbAddr dst = lb_add_local_generated(p, t, false);
diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp
index df3d4bc03..06d66ac80 100644
--- a/src/llvm_backend_stmt.cpp
+++ b/src/llvm_backend_stmt.cpp
@@ -2001,7 +2001,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) {
LLVMValueRef ptr = p->temp_callee_return_struct_memory;
LLVMValueRef nptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(src_type, 0), "");
LLVMBuildStore(p->builder, ret_val, nptr);
- ret_val = LLVMBuildLoad2(p->builder, ret_type, ptr, "");
+ ret_val = OdinLLVMBuildLoad(p, ret_type, ptr);
} else {
ret_val = OdinLLVMBuildTransmute(p, ret_val, ret_type);
}
@@ -2018,14 +2018,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) {
gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
lb_ensure_abi_function_type(p->module, p);
- lbValue res = {};
-
- TypeTuple *tuple = &p->type->Proc.results->Tuple;
isize return_count = p->type->Proc.result_count;
- isize res_count = return_results.count;
-
- lbFunctionType *ft = lb_get_function_type(p->module, p->type);
- bool return_by_pointer = ft->ret.kind == lbArg_Indirect;
if (return_count == 0) {
// No return values
@@ -2038,7 +2031,17 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return
LLVMBuildRetVoid(p->builder);
}
return;
- } else if (return_count == 1) {
+ }
+
+ lbValue res = {};
+
+ TypeTuple *tuple = &p->type->Proc.results->Tuple;
+ isize res_count = return_results.count;
+
+ lbFunctionType *ft = lb_get_function_type(p->module, p->type);
+ bool return_by_pointer = ft->ret.kind == lbArg_Indirect;
+
+ if (return_count == 1) {
Entity *e = tuple->variables[0];
if (res_count == 0) {
rw_mutex_shared_lock(&p->module->values_mutex);
diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp
index 9d4505bb0..6c12b37be 100644
--- a/src/llvm_backend_type.cpp
+++ b/src/llvm_backend_type.cpp
@@ -43,6 +43,8 @@ gb_internal u64 lb_typeid_kind(lbModule *m, Type *type, u64 id=0) {
if (flags & BasicFlag_Pointer) kind = Typeid_Pointer;
if (flags & BasicFlag_String) kind = Typeid_String;
if (flags & BasicFlag_Rune) kind = Typeid_Rune;
+
+ if (bt->Basic.kind == Basic_typeid) kind = Typeid_Type_Id;
} break;
case Type_Pointer: kind = Typeid_Pointer; break;
case Type_MultiPointer: kind = Typeid_Multi_Pointer; break;
@@ -59,8 +61,6 @@ gb_internal u64 lb_typeid_kind(lbModule *m, Type *type, u64 id=0) {
case Type_Proc: kind = Typeid_Procedure; break;
case Type_BitSet: kind = Typeid_Bit_Set; break;
case Type_SimdVector: kind = Typeid_Simd_Vector; break;
- case Type_RelativePointer: kind = Typeid_Relative_Pointer; break;
- case Type_RelativeMultiPointer: kind = Typeid_Relative_Multi_Pointer; break;
case Type_SoaPointer: kind = Typeid_SoaPointer; break;
case Type_BitField: kind = Typeid_Bit_Field; break;
}
@@ -948,30 +948,6 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
}
break;
- case Type_RelativePointer:
- {
- tag_type = t_type_info_relative_pointer;
- LLVMValueRef vals[2] = {
- get_type_info_ptr(m, t->RelativePointer.pointer_type),
- get_type_info_ptr(m, t->RelativePointer.base_integer),
- };
-
- variant_value = llvm_const_named_struct(m, tag_type, vals, gb_count_of(vals));
- }
- break;
-
- case Type_RelativeMultiPointer:
- {
- tag_type = t_type_info_relative_multi_pointer;
- LLVMValueRef vals[2] = {
- get_type_info_ptr(m, t->RelativeMultiPointer.pointer_type),
- get_type_info_ptr(m, t->RelativeMultiPointer.base_integer),
- };
-
- variant_value = llvm_const_named_struct(m, tag_type, vals, gb_count_of(vals));
- }
- break;
-
case Type_Matrix:
{
tag_type = t_type_info_matrix;
diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp
index f63c42ab9..a2a0ba4cc 100644
--- a/src/llvm_backend_utility.cpp
+++ b/src/llvm_backend_utility.cpp
@@ -124,8 +124,16 @@ gb_internal void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, u
switch (kind) {
case LLVMStructTypeKind:
case LLVMArrayTypeKind:
- // NOTE(bill): Enforce zeroing through memset to make sure padding is zeroed too
- lb_mem_zero_ptr_internal(p, ptr, lb_const_int(p->module, t_int, sz).value, alignment, false);
+ if (is_type_tuple(type)) {
+ // NOTE(bill): even though this should be safe, to keep ASAN happy, do not zero the implicit padding at the end
+ GB_ASSERT(type->kind == Type_Tuple);
+ i64 n = type->Tuple.variables.count-1;
+ i64 end_offset = type->Tuple.offsets[n] + type_size_of(type->Tuple.variables[n]->type);
+ lb_mem_zero_ptr_internal(p, ptr, lb_const_int(p->module, t_int, end_offset).value, alignment, false);
+ } else {
+ // NOTE(bill): Enforce zeroing through memset to make sure padding is zeroed too
+ lb_mem_zero_ptr_internal(p, ptr, lb_const_int(p->module, t_int, sz).value, alignment, false);
+ }
break;
default:
LLVMBuildStore(p->builder, LLVMConstNull(lb_type(p->module, type)), ptr);
@@ -269,7 +277,7 @@ gb_internal lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) {
if (lb_try_update_alignment(ptr, align)) {
LLVMTypeRef result_type = lb_type(p->module, t);
res.value = LLVMBuildPointerCast(p->builder, ptr.value, LLVMPointerType(result_type, 0), "");
- res.value = LLVMBuildLoad2(p->builder, result_type, res.value, "");
+ res.value = OdinLLVMBuildLoad(p, result_type, res.value);
return res;
}
lbAddr addr = lb_add_local_generated(p, t, false);
@@ -1123,10 +1131,6 @@ gb_internal lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
Type *t = base_type(type_deref(s.type));
Type *result_type = nullptr;
- if (is_type_relative_pointer(t)) {
- s = lb_addr_get_ptr(p, lb_addr(s));
- }
-
if (is_type_struct(t)) {
result_type = get_struct_field_type(t, index);
} else if (is_type_union(t)) {
@@ -1432,8 +1436,6 @@ gb_internal lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection
e = lb_emit_array_epi(p, e, index);
} else if (type->kind == Type_Map) {
e = lb_emit_struct_ep(p, e, index);
- } else if (type->kind == Type_RelativePointer) {
- e = lb_emit_struct_ep(p, e, index);
} else {
GB_PANIC("un-gep-able type %s", type_to_string(type));
}
diff --git a/src/main.cpp b/src/main.cpp
index a969e32a9..8a5339000 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -328,6 +328,8 @@ enum BuildFlagKind {
BuildFlag_NoRPath,
BuildFlag_NoEntryPoint,
BuildFlag_UseLLD,
+ BuildFlag_UseRADLink,
+ BuildFlag_Linker,
BuildFlag_UseSeparateModules,
BuildFlag_NoThreadedChecker,
BuildFlag_ShowDebugMessages,
@@ -539,6 +541,8 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_NoRPath, str_lit("no-rpath"), BuildFlagParam_None, Command__does_build);
add_flag(&build_flags, BuildFlag_NoEntryPoint, str_lit("no-entry-point"), BuildFlagParam_None, Command__does_check &~ Command_test);
add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None, Command__does_build);
+ add_flag(&build_flags, BuildFlag_UseRADLink, str_lit("radlink"), BuildFlagParam_None, Command__does_build);
+ add_flag(&build_flags, BuildFlag_Linker, str_lit("linker"), BuildFlagParam_String, Command__does_build);
add_flag(&build_flags, BuildFlag_UseSeparateModules, str_lit("use-separate-modules"), BuildFlagParam_None, Command__does_build);
add_flag(&build_flags, BuildFlag_NoThreadedChecker, str_lit("no-threaded-checker"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_ShowDebugMessages, str_lit("show-debug-messages"), BuildFlagParam_None, Command_all);
@@ -1060,27 +1064,29 @@ gb_internal bool parse_build_flags(Array<String> args) {
}
if (!found) {
- struct DistanceAndTargetIndex {
- isize distance;
- isize target_index;
- };
+ if (str != "?") {
+ struct DistanceAndTargetIndex {
+ isize distance;
+ isize target_index;
+ };
- DistanceAndTargetIndex distances[gb_count_of(named_targets)] = {};
- for (isize i = 0; i < gb_count_of(named_targets); i++) {
- distances[i].target_index = i;
- distances[i].distance = levenstein_distance_case_insensitive(str, named_targets[i].name);
- }
- gb_sort_array(distances, gb_count_of(distances), gb_isize_cmp(gb_offset_of(DistanceAndTargetIndex, distance)));
+ DistanceAndTargetIndex distances[gb_count_of(named_targets)] = {};
+ for (isize i = 0; i < gb_count_of(named_targets); i++) {
+ distances[i].target_index = i;
+ distances[i].distance = levenstein_distance_case_insensitive(str, named_targets[i].name);
+ }
+ gb_sort_array(distances, gb_count_of(distances), gb_isize_cmp(gb_offset_of(DistanceAndTargetIndex, distance)));
- gb_printf_err("Unknown target '%.*s'\n", LIT(str));
+ gb_printf_err("Unknown target '%.*s'\n", LIT(str));
- if (distances[0].distance <= MAX_SMALLEST_DID_YOU_MEAN_DISTANCE) {
- gb_printf_err("Did you mean:\n");
- for (isize i = 0; i < gb_count_of(named_targets); i++) {
- if (distances[i].distance > MAX_SMALLEST_DID_YOU_MEAN_DISTANCE) {
- break;
+ if (distances[0].distance <= MAX_SMALLEST_DID_YOU_MEAN_DISTANCE) {
+ gb_printf_err("Did you mean:\n");
+ for (isize i = 0; i < gb_count_of(named_targets); i++) {
+ if (distances[i].distance > MAX_SMALLEST_DID_YOU_MEAN_DISTANCE) {
+ break;
+ }
+ gb_printf_err("\t%.*s\n", LIT(named_targets[distances[i].target_index].name));
}
- gb_printf_err("\t%.*s\n", LIT(named_targets[distances[i].target_index].name));
}
}
gb_printf_err("All supported targets:\n");
@@ -1199,8 +1205,38 @@ gb_internal bool parse_build_flags(Array<String> args) {
build_context.no_thread_local = true;
break;
case BuildFlag_UseLLD:
- build_context.use_lld = true;
+ gb_printf_err("Warning: Use of -lld has been deprecated in favour of -linker:lld\n");
+ build_context.linker_choice = Linker_lld;
+ break;
+ case BuildFlag_UseRADLink:
+ gb_printf_err("Warning: Use of -lld has been deprecated in favour of -linker:radlink\n");
+ build_context.linker_choice = Linker_radlink;
+ break;
+ case BuildFlag_Linker:
+ {
+ GB_ASSERT(value.kind == ExactValue_String);
+ LinkerChoice linker_choice = Linker_Invalid;
+
+ for (i32 i = 0; i < Linker_COUNT; i++) {
+ if (linker_choices[i] == value.value_string) {
+ linker_choice = cast(LinkerChoice)i;
+ break;
+ }
+ }
+
+ if (linker_choice == Linker_Invalid) {
+ gb_printf_err("Invalid option for -linker:<string>. Expected one of the following\n");
+ for (i32 i = 0; i < Linker_COUNT; i++) {
+ gb_printf_err("\t%.*s\n", LIT(linker_choices[i]));
+ }
+ bad_flags = true;
+ } else {
+ build_context.linker_choice = linker_choice;
+ }
+ }
break;
+
+
case BuildFlag_UseSeparateModules:
build_context.use_separate_modules = true;
break;
@@ -1408,7 +1444,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
build_context.terse_errors = true;
break;
case BuildFlag_VerboseErrors:
- gb_printf_err("-verbose-errors is not the default, -terse-errors can now disable it\n");
+ gb_printf_err("-verbose-errors is now the default, -terse-errors can disable it\n");
build_context.hide_error_line = false;
build_context.terse_errors = false;
break;
@@ -1747,7 +1783,7 @@ gb_internal void check_defines(BuildContext *bc, Checker *c) {
String name = make_string_c(entry.key);
ExactValue value = entry.value;
GB_ASSERT(value.kind != ExactValue_Invalid);
-
+
bool found = false;
for_array(i, c->info.defineables) {
Defineable *def = &c->info.defineables[i];
@@ -1776,9 +1812,9 @@ gb_internal void temp_alloc_defineable_strings(Checker *c) {
gb_internal GB_COMPARE_PROC(defineables_cmp) {
Defineable *x = (Defineable *)a;
Defineable *y = (Defineable *)b;
-
+
int cmp = 0;
-
+
String x_file = get_file_path_string(x->pos.file_id);
String y_file = get_file_path_string(y->pos.file_id);
cmp = string_compare(x_file, y_file);
@@ -1789,8 +1825,22 @@ gb_internal GB_COMPARE_PROC(defineables_cmp) {
return i32_cmp(x->pos.offset, y->pos.offset);
}
-gb_internal void sort_defineables(Checker *c) {
+gb_internal void sort_defineables_and_remove_duplicates(Checker *c) {
+ if (c->info.defineables.count == 0) {
+ return;
+ }
gb_sort_array(c->info.defineables.data, c->info.defineables.count, defineables_cmp);
+
+ Defineable prev = c->info.defineables[0];
+ for (isize i = 1; i < c->info.defineables.count; ) {
+ Defineable curr = c->info.defineables[i];
+ if (prev.pos == curr.pos) {
+ array_ordered_remove(&c->info.defineables, i);
+ continue;
+ }
+ prev = curr;
+ i++;
+ }
}
gb_internal void export_defineables(Checker *c, String path) {
@@ -2125,11 +2175,12 @@ gb_internal void remove_temp_files(lbGenerator *gen) {
}
-gb_internal void print_show_help(String const arg0, String const &command) {
+gb_internal void print_show_help(String const arg0, String const &command, String optional_flag = {}) {
print_usage_line(0, "%.*s is a tool for managing Odin source code.", LIT(arg0));
print_usage_line(0, "Usage:");
print_usage_line(1, "%.*s %.*s [arguments]", LIT(arg0), LIT(command));
print_usage_line(0, "");
+ defer (print_usage_line(0, ""));
if (command == "build") {
print_usage_line(1, "build Compiles directory of .odin files as an executable.");
@@ -2175,475 +2226,560 @@ gb_internal void print_show_help(String const arg0, String const &command) {
bool check_only = command == "check" || strip_semicolon;
bool check = run_or_build || check_only;
+ if (command == "help") {
+ doc = true;
+ build = true;
+ run_or_build = true;
+ test_only = true;
+ strip_semicolon = true;
+ check_only = true;
+ check = true;
+ }
+
print_usage_line(0, "");
print_usage_line(1, "Flags");
print_usage_line(0, "");
- if (check) {
- print_usage_line(1, "-file");
- print_usage_line(2, "Tells `%.*s %.*s` to treat the given file as a self-contained package.", LIT(arg0), LIT(command));
- print_usage_line(2, "This means that `<dir>/a.odin` won't have access to `<dir>/b.odin`'s contents.");
- print_usage_line(0, "");
- }
- if (doc) {
- print_usage_line(1, "-short");
- print_usage_line(2, "Shows shortened documentation for the packages.");
- print_usage_line(0, "");
- print_usage_line(1, "-all-packages");
- print_usage_line(2, "Generates documentation for all packages used in the current project.");
+ auto const print_flag = [&optional_flag](char const *flag) -> bool {
+ if (optional_flag.len != 0) {
+ String f = make_string_c(flag);
+ isize i = string_index_byte(f, ':');
+ if (i >= 0) {
+ f.len = i;
+ }
+ if (optional_flag != f) {
+ return false;
+ }
+ }
print_usage_line(0, "");
+ print_usage_line(1, flag);
+ return true;
+ };
- print_usage_line(1, "-doc-format");
- print_usage_line(2, "Generates documentation as the .odin-doc format (useful for external tooling).");
- print_usage_line(0, "");
- print_usage_line(1, "-out:<filepath>");
- print_usage_line(2, "Sets the base name of the resultig .odin-doc file.");
- print_usage_line(2, "The extension can be optionally included; the resulting file will always have an extension of '.odin-doc'.");
- print_usage_line(2, "Example: -out:foo");
- print_usage_line(0, "");
+ if (doc) {
+ if (print_flag("-all-packages")) {
+ print_usage_line(2, "Generates documentation for all packages used in the current project.");
+ }
+ }
+ if (test_only) {
+ if (print_flag("-all-packages")) {
+ print_usage_line(2, "Tests all packages imported into the given initial package.");
+ }
}
- if (run_or_build) {
- print_usage_line(1, "-out:<filepath>");
- print_usage_line(2, "Sets the file name of the outputted executable.");
- print_usage_line(2, "Example: -out:foo.exe");
- print_usage_line(0, "");
-
- print_usage_line(1, "-o:<string>");
- print_usage_line(2, "Sets the optimization mode for compilation.");
- print_usage_line(2, "Available options:");
- print_usage_line(3, "-o:none");
- print_usage_line(3, "-o:minimal");
- print_usage_line(3, "-o:size");
- print_usage_line(3, "-o:speed");
- if (LB_USE_NEW_PASS_SYSTEM) {
- print_usage_line(3, "-o:aggressive");
- }
- print_usage_line(2, "The default is -o:minimal.");
- print_usage_line(0, "");
+ if (build) {
+ if (print_flag("-build-mode:<mode>")) {
+ print_usage_line(2, "Sets the build mode.");
+ print_usage_line(2, "Available options:");
+ print_usage_line(3, "-build-mode:exe Builds as an executable.");
+ print_usage_line(3, "-build-mode:test Builds as an executable that executes tests.");
+ print_usage_line(3, "-build-mode:dll Builds as a dynamically linked library.");
+ print_usage_line(3, "-build-mode:shared Builds as a dynamically linked library.");
+ print_usage_line(3, "-build-mode:dynamic Builds as a dynamically linked library.");
+ print_usage_line(3, "-build-mode:lib Builds as a statically linked library.");
+ print_usage_line(3, "-build-mode:static Builds as a statically linked library.");
+ print_usage_line(3, "-build-mode:obj Builds as an object file.");
+ print_usage_line(3, "-build-mode:object Builds as an object file.");
+ print_usage_line(3, "-build-mode:assembly Builds as an assembly file.");
+ print_usage_line(3, "-build-mode:assembler Builds as an assembly file.");
+ print_usage_line(3, "-build-mode:asm Builds as an assembly file.");
+ print_usage_line(3, "-build-mode:llvm-ir Builds as an LLVM IR file.");
+ print_usage_line(3, "-build-mode:llvm Builds as an LLVM IR file.");
+ }
}
if (check) {
- print_usage_line(1, "-show-timings");
- print_usage_line(2, "Shows basic overview of the timings of different stages within the compiler in milliseconds.");
- print_usage_line(0, "");
+ if (print_flag("-collection:<name>=<filepath>")) {
+ print_usage_line(2, "Defines a library collection used for imports.");
+ print_usage_line(2, "Example: -collection:shared=dir/to/shared");
+ print_usage_line(2, "Usage in Code:");
+ print_usage_line(3, "import \"shared:foo\"");
+ }
- print_usage_line(1, "-show-more-timings");
- print_usage_line(2, "Shows an advanced overview of the timings of different stages within the compiler in milliseconds.");
- print_usage_line(0, "");
+ if (print_flag("-custom-attribute:<string>")) {
+ print_usage_line(2, "Add a custom attribute which will be ignored if it is unknown.");
+ print_usage_line(2, "This can be used with metaprogramming tools.");
+ print_usage_line(2, "Examples:");
+ print_usage_line(3, "-custom-attribute:my_tag");
+ print_usage_line(3, "-custom-attribute:my_tag,the_other_thing");
+ print_usage_line(3, "-custom-attribute:my_tag -custom-attribute:the_other_thing");
+ }
+ }
- print_usage_line(1, "-show-system-calls");
- print_usage_line(2, "Prints the whole command and arguments for calls to external tools like linker and assembler.");
- print_usage_line(0, "");
+ if (run_or_build) {
+ if (print_flag("-debug")) {
+ print_usage_line(2, "Enables debug information, and defines the global constant ODIN_DEBUG to be 'true'.");
+ }
+ }
- print_usage_line(1, "-export-timings:<format>");
- print_usage_line(2, "Exports timings to one of a few formats. Requires `-show-timings` or `-show-more-timings`.");
- print_usage_line(2, "Available options:");
- print_usage_line(3, "-export-timings:json Exports compile time stats to JSON.");
- print_usage_line(3, "-export-timings:csv Exports compile time stats to CSV.");
- print_usage_line(0, "");
+ if (check) {
+ if (print_flag("-default-to-nil-allocator")) {
+ print_usage_line(2, "Sets the default allocator to be the nil_allocator, an allocator which does nothing.");
+ }
- print_usage_line(1, "-export-timings-file:<filename>");
- print_usage_line(2, "Specifies the filename for `-export-timings`.");
- print_usage_line(2, "Example: -export-timings-file:timings.json");
- print_usage_line(0, "");
+ if (print_flag("-define:<name>=<value>")) {
+ print_usage_line(2, "Defines a scalar boolean, integer or string as global constant.");
+ print_usage_line(2, "Example: -define:SPAM=123");
+ print_usage_line(2, "Usage in code:");
+ print_usage_line(3, "#config(SPAM, default_value)");
+ }
+ }
- print_usage_line(1, "-export-dependencies:<format>");
- print_usage_line(2, "Exports dependencies to one of a few formats. Requires `-export-dependencies-file`.");
- print_usage_line(2, "Available options:");
- print_usage_line(3, "-export-dependencies:make Exports in Makefile format");
- print_usage_line(3, "-export-dependencies:json Exports in JSON format");
- print_usage_line(0, "");
+ if (run_or_build) {
+ if (print_flag("-disable-assert")) {
+ print_usage_line(2, "Disables the code generation of the built-in run-time 'assert' procedure, and defines the global constant ODIN_DISABLE_ASSERT to be 'true'.");
+ }
- print_usage_line(1, "-export-dependencies-file:<filename>");
- print_usage_line(2, "Specifies the filename for `-export-dependencies`.");
- print_usage_line(2, "Example: -export-dependencies-file:dependencies.d");
- print_usage_line(0, "");
+ if (print_flag("-disable-red-zone")) {
+ print_usage_line(2, "Disables red zone on a supported freestanding target.");
+ }
+ }
- print_usage_line(1, "-thread-count:<integer>");
- print_usage_line(2, "Overrides the number of threads the compiler will use to compile with.");
- print_usage_line(2, "Example: -thread-count:2");
- print_usage_line(0, "");
+ if (check) {
+ if (print_flag("-disallow-do")) {
+ print_usage_line(2, "Disallows the 'do' keyword in the project.");
+ }
}
- if (check_only) {
- print_usage_line(1, "-show-unused");
- print_usage_line(2, "Shows unused package declarations within the current project.");
- print_usage_line(0, "");
- print_usage_line(1, "-show-unused-with-location");
- print_usage_line(2, "Shows unused package declarations within the current project with the declarations source location.");
- print_usage_line(0, "");
+ if (doc) {
+ if (print_flag("-doc-format")) {
+ print_usage_line(2, "Generates documentation as the .odin-doc format (useful for external tooling).");
+ }
}
if (run_or_build) {
- print_usage_line(1, "-keep-temp-files");
- print_usage_line(2, "Keeps the temporary files generated during compilation.");
- print_usage_line(0, "");
- } else if (strip_semicolon) {
- print_usage_line(1, "-keep-temp-files");
- print_usage_line(2, "Keeps the temporary files generated during stripping the unneeded semicolons from files.");
- print_usage_line(0, "");
+ if (print_flag("-dynamic-map-calls")) {
+ print_usage_line(2, "Uses dynamic map calls to minimize code generation at the cost of runtime execution.");
+ }
}
if (check) {
- print_usage_line(1, "-collection:<name>=<filepath>");
- print_usage_line(2, "Defines a library collection used for imports.");
- print_usage_line(2, "Example: -collection:shared=dir/to/shared");
- print_usage_line(2, "Usage in Code:");
- print_usage_line(3, "import \"shared:foo\"");
- print_usage_line(0, "");
+ if (print_flag("-error-pos-style:<string>")) {
+ print_usage_line(2, "Available options:");
+ print_usage_line(3, "-error-pos-style:unix file/path:45:3:");
+ print_usage_line(3, "-error-pos-style:odin file/path(45:3)");
+ print_usage_line(3, "-error-pos-style:default (Defaults to 'odin'.)");
+ }
- print_usage_line(1, "-define:<name>=<value>");
- print_usage_line(2, "Defines a scalar boolean, integer or string as global constant.");
- print_usage_line(2, "Example: -define:SPAM=123");
- print_usage_line(2, "Usage in code:");
- print_usage_line(3, "#config(SPAM, default_value)");
- print_usage_line(0, "");
+ if (print_flag("-export-defineables:<filename>")) {
+ print_usage_line(2, "Exports an overview of all the #config/#defined usages in CSV format to the given file path.");
+ print_usage_line(2, "Example: -export-defineables:defineables.csv");
+ }
- print_usage_line(1, "-show-defineables");
- print_usage_line(2, "Shows an overview of all the #config/#defined usages in the project.");
- print_usage_line(0, "");
+ if (print_flag("-export-dependencies:<format>")) {
+ print_usage_line(2, "Exports dependencies to one of a few formats. Requires `-export-dependencies-file`.");
+ print_usage_line(2, "Available options:");
+ print_usage_line(3, "-export-dependencies:make Exports in Makefile format");
+ print_usage_line(3, "-export-dependencies:json Exports in JSON format");
+ }
- print_usage_line(1, "-export-defineables:<filename>");
- print_usage_line(2, "Exports an overview of all the #config/#defined usages in CSV format to the given file path.");
- print_usage_line(2, "Example: -export-defineables:defineables.csv");
- print_usage_line(0, "");
- }
+ if (print_flag("-export-dependencies-file:<filename>")) {
+ print_usage_line(2, "Specifies the filename for `-export-dependencies`.");
+ print_usage_line(2, "Example: -export-dependencies-file:dependencies.d");
+ }
- if (build) {
- print_usage_line(1, "-build-mode:<mode>");
- print_usage_line(2, "Sets the build mode.");
- print_usage_line(2, "Available options:");
- print_usage_line(3, "-build-mode:exe Builds as an executable.");
- print_usage_line(3, "-build-mode:test Builds as an executable that executes tests.");
- print_usage_line(3, "-build-mode:dll Builds as a dynamically linked library.");
- print_usage_line(3, "-build-mode:shared Builds as a dynamically linked library.");
- print_usage_line(3, "-build-mode:lib Builds as a statically linked library.");
- print_usage_line(3, "-build-mode:static Builds as a statically linked library.");
- print_usage_line(3, "-build-mode:obj Builds as an object file.");
- print_usage_line(3, "-build-mode:object Builds as an object file.");
- print_usage_line(3, "-build-mode:assembly Builds as an assembly file.");
- print_usage_line(3, "-build-mode:assembler Builds as an assembly file.");
- print_usage_line(3, "-build-mode:asm Builds as an assembly file.");
- print_usage_line(3, "-build-mode:llvm-ir Builds as an LLVM IR file.");
- print_usage_line(3, "-build-mode:llvm Builds as an LLVM IR file.");
- print_usage_line(0, "");
- }
+ if (print_flag("-export-timings:<format>")) {
+ print_usage_line(2, "Exports timings to one of a few formats. Requires `-show-timings` or `-show-more-timings`.");
+ print_usage_line(2, "Available options:");
+ print_usage_line(3, "-export-timings:json Exports compile time stats to JSON.");
+ print_usage_line(3, "-export-timings:csv Exports compile time stats to CSV.");
+ }
- if (check) {
- print_usage_line(1, "-target:<string>");
- print_usage_line(2, "Sets the target for the executable to be built in.");
- print_usage_line(0, "");
+ if (print_flag("-export-timings-file:<filename>")) {
+ print_usage_line(2, "Specifies the filename for `-export-timings`.");
+ print_usage_line(2, "Example: -export-timings-file:timings.json");
+ }
}
if (run_or_build) {
- print_usage_line(1, "-debug");
- print_usage_line(2, "Enables debug information, and defines the global constant ODIN_DEBUG to be 'true'.");
- print_usage_line(0, "");
+ if (print_flag("-extra-assembler-flags:<string>")) {
+ print_usage_line(2, "Adds extra assembler specific flags in a string.");
+ }
- print_usage_line(1, "-disable-assert");
- print_usage_line(2, "Disables the code generation of the built-in run-time 'assert' procedure, and defines the global constant ODIN_DISABLE_ASSERT to be 'true'.");
- print_usage_line(0, "");
+ if (print_flag("-extra-linker-flags:<string>")) {
+ print_usage_line(2, "Adds extra linker specific flags in a string.");
+ }
+ }
- print_usage_line(1, "-no-bounds-check");
- print_usage_line(2, "Disables bounds checking program wide.");
- print_usage_line(0, "");
+ if (check) {
+ if (print_flag("-file")) {
+ print_usage_line(2, "Tells `%.*s %.*s` to treat the given file as a self-contained package.", LIT(arg0), LIT(command));
+ print_usage_line(2, "This means that `<dir>/a.odin` won't have access to `<dir>/b.odin`'s contents.");
+ }
- print_usage_line(1, "-no-type-assert");
- print_usage_line(2, "Disables type assertion checking program wide.");
- print_usage_line(0, "");
+ if (print_flag("-foreign-error-procedures")) {
+ print_usage_line(2, "States that the error procedures used in the runtime are defined in a separate translation unit.");
+ }
- print_usage_line(1, "-no-crt");
- print_usage_line(2, "Disables automatic linking with the C Run Time.");
- print_usage_line(0, "");
+ if (print_flag("-ignore-unknown-attributes")) {
+ print_usage_line(2, "Ignores unknown attributes.");
+ print_usage_line(2, "This can be used with metaprogramming tools.");
+ }
+ }
- print_usage_line(1, "-no-rpath");
- print_usage_line(2, "Disables automatic addition of an rpath linked to the executable directory.");
- print_usage_line(0, "");
+ if (run_or_build) {
+ #if defined(GB_SYSTEM_WINDOWS)
+ if (print_flag("-ignore-vs-search")) {
+ print_usage_line(2, "[Windows only]");
+ print_usage_line(2, "Ignores the Visual Studio search for library paths.");
+ }
+ #endif
+ }
- print_usage_line(1, "-no-thread-local");
- print_usage_line(2, "Ignores @thread_local attribute, effectively treating the program as if it is single-threaded.");
- print_usage_line(0, "");
+ if (check) {
+ if (print_flag("-ignore-warnings")) {
+ print_usage_line(2, "Ignores warning messages.");
+ }
- print_usage_line(1, "-lld");
- print_usage_line(2, "Uses the LLD linker rather than the default.");
- print_usage_line(0, "");
+ if (print_flag("-json-errors")) {
+ print_usage_line(2, "Prints the error messages as json to stderr.");
+ }
+ }
- print_usage_line(1, "-use-separate-modules");
- print_usage_line(2, "The backend generates multiple build units which are then linked together.");
- print_usage_line(2, "Normally, a single build unit is generated for a standard project.");
- print_usage_line(2, "This is the default behaviour on Windows for '-o:none' and '-o:minimal' builds.");
- print_usage_line(0, "");
+ if (run_or_build) {
+ if (print_flag("-keep-temp-files")) {
+ print_usage_line(2, "Keeps the temporary files generated during compilation.");
+ }
+ } else if (strip_semicolon) {
+ if (print_flag("-keep-temp-files")) {
+ print_usage_line(2, "Keeps the temporary files generated during stripping the unneeded semicolons from files.");
+ }
+ }
+ if (run_or_build) {
+ if (print_flag("-linker:<string>")) {
+ print_usage_line(2, "Specify the linker to use.");
+ print_usage_line(2, "Choices:");
+ for (i32 i = 0; i < Linker_COUNT; i++) {
+ print_usage_line(3, "%.*s", LIT(linker_choices[i]));
+ }
+ }
+
+ if (print_flag("-lld")) {
+ print_usage_line(2, "Uses the LLD linker rather than the default.");
+ }
}
if (check) {
- print_usage_line(1, "-no-threaded-checker");
- print_usage_line(2, "Disables multithreading in the semantic checker stage.");
- print_usage_line(0, "");
+ if (print_flag("-max-error-count:<integer>")) {
+ print_usage_line(2, "Sets the maximum number of errors that can be displayed before the compiler terminates.");
+ print_usage_line(2, "Must be an integer >0.");
+ print_usage_line(2, "If not set, the default max error count is %d.", DEFAULT_MAX_ERROR_COLLECTOR_COUNT);
+ }
+ }
+
+ if (run_or_build) {
+ if (print_flag("-microarch:<string>")) {
+ print_usage_line(2, "Specifies the specific micro-architecture for the build in a string.");
+ print_usage_line(2, "Examples:");
+ print_usage_line(3, "-microarch:sandybridge");
+ print_usage_line(3, "-microarch:native");
+ print_usage_line(3, "-microarch:\"?\" for a list");
+ }
}
if (check) {
- print_usage_line(1, "-vet");
- print_usage_line(2, "Does extra checks on the code.");
- print_usage_line(2, "Extra checks include:");
- print_usage_line(3, "-vet-unused");
- print_usage_line(3, "-vet-unused-variables");
- print_usage_line(3, "-vet-unused-imports");
- print_usage_line(3, "-vet-shadowing");
- print_usage_line(3, "-vet-using-stmt");
- print_usage_line(0, "");
+ if (print_flag("-min-link-libs")) {
+ print_usage_line(2, "If set, the number of linked libraries will be minimized to prevent duplications.");
+ print_usage_line(2, "This is useful for so called \"dumb\" linkers compared to \"smart\" linkers.");
+ }
+ }
- print_usage_line(1, "-vet-unused");
- print_usage_line(2, "Checks for unused declarations (variables and imports).");
- print_usage_line(0, "");
+ if (run_or_build) {
+ if (print_flag("-minimum-os-version:<string>")) {
+ print_usage_line(2, "Sets the minimum OS version targeted by the application.");
+ print_usage_line(2, "Default: -minimum-os-version:11.0.0");
+ print_usage_line(2, "Only used when target is Darwin, if given, linking mismatched versions will emit a warning.");
+ }
- print_usage_line(1, "-vet-unused-variables");
- print_usage_line(2, "Checks for unused variable declarations.");
- print_usage_line(0, "");
+ if (print_flag("-no-bounds-check")) {
+ print_usage_line(2, "Disables bounds checking program wide.");
+ }
- print_usage_line(1, "-vet-unused-imports");
- print_usage_line(2, "Checks for unused import declarations.");
- print_usage_line(0, "");
+ if (print_flag("-no-crt")) {
+ print_usage_line(2, "Disables automatic linking with the C Run Time.");
+ }
+ }
- print_usage_line(1, "-vet-shadowing");
- print_usage_line(2, "Checks for variable shadowing within procedures.");
- print_usage_line(0, "");
+ if (check && command != "test") {
+ if (print_flag("-no-entry-point")) {
+ print_usage_line(2, "Removes default requirement of an entry point (e.g. main procedure).");
+ }
+ }
- print_usage_line(1, "-vet-using-stmt");
- print_usage_line(2, "Checks for the use of 'using' as a statement.");
- print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring.");
- print_usage_line(0, "");
+ if (run_or_build) {
+ if (print_flag("-no-rpath")) {
+ print_usage_line(2, "Disables automatic addition of an rpath linked to the executable directory.");
+ }
- print_usage_line(1, "-vet-using-param");
- print_usage_line(2, "Checks for the use of 'using' on procedure parameters.");
- print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring.");
- print_usage_line(0, "");
+ if (print_flag("-no-thread-local")) {
+ print_usage_line(2, "Ignores @thread_local attribute, effectively treating the program as if it is single-threaded.");
+ }
- print_usage_line(1, "-vet-style");
- print_usage_line(2, "Errs on missing trailing commas followed by a newline.");
- print_usage_line(2, "Errs on deprecated syntax.");
- print_usage_line(2, "Does not err on unneeded tokens (unlike -strict-style).");
- print_usage_line(0, "");
+ if (print_flag("-no-threaded-checker")) {
+ print_usage_line(2, "Disables multithreading in the semantic checker stage.");
+ }
- print_usage_line(1, "-vet-semicolon");
- print_usage_line(2, "Errs on unneeded semicolons.");
- print_usage_line(0, "");
+ if (print_flag("-no-type-assert")) {
+ print_usage_line(2, "Disables type assertion checking program wide.");
+ }
+ }
- print_usage_line(1, "-vet-cast");
- print_usage_line(2, "Errs on casting a value to its own type or using `transmute` rather than `cast`.");
- print_usage_line(0, "");
+ if (run_or_build) {
+ if (print_flag("-o:<string>")) {
+ print_usage_line(2, "Sets the optimization mode for compilation.");
+ print_usage_line(2, "Available options:");
+ print_usage_line(3, "-o:none");
+ print_usage_line(3, "-o:minimal");
+ print_usage_line(3, "-o:size");
+ print_usage_line(3, "-o:speed");
+ if (LB_USE_NEW_PASS_SYSTEM) {
+ print_usage_line(3, "-o:aggressive (use this with caution)");
+ }
+ print_usage_line(2, "The default is -o:minimal.");
+ }
- print_usage_line(1, "-vet-tabs");
- print_usage_line(2, "Errs when the use of tabs has not been used for indentation.");
- print_usage_line(0, "");
- print_usage_line(1, "-vet-packages:<comma-separated-strings>");
- print_usage_line(2, "Sets which packages by name will be vetted.");
- print_usage_line(2, "Files with specific +vet tags will not be ignored if they are not in the packages set.");
- print_usage_line(0, "");
+ if (print_flag("-obfuscate-source-code-locations")) {
+ print_usage_line(2, "Obfuscate the file and procedure strings, and line and column numbers, stored with a 'runtime.Source_Code_Location' value.");
+ }
- print_usage_line(1, "-vet-unused-procedures");
- print_usage_line(2, "Checks for unused procedures.");
- print_usage_line(2, "Must be used with -vet-packages or specified on a per file with +vet tags.");
- print_usage_line(0, "");
- }
- if (check) {
- print_usage_line(1, "-custom-attribute:<string>");
- print_usage_line(2, "Add a custom attribute which will be ignored if it is unknown.");
- print_usage_line(2, "This can be used with metaprogramming tools.");
- print_usage_line(2, "Examples:");
- print_usage_line(3, "-custom-attribute:my_tag");
- print_usage_line(3, "-custom-attribute:my_tag,the_other_thing");
- print_usage_line(3, "-custom-attribute:my_tag -custom-attribute:the_other_thing");
- print_usage_line(0, "");
+ if (print_flag("-out:<filepath>")) {
+ print_usage_line(2, "Sets the file name of the outputted executable.");
+ print_usage_line(2, "Example: -out:foo.exe");
+ }
+ }
- print_usage_line(1, "-ignore-unknown-attributes");
- print_usage_line(2, "Ignores unknown attributes.");
- print_usage_line(2, "This can be used with metaprogramming tools.");
- print_usage_line(0, "");
+ if (doc) {
+ if (print_flag("-out:<filepath>")) {
+ print_usage_line(2, "Sets the base name of the resultig .odin-doc file.");
+ print_usage_line(2, "The extension can be optionally included; the resulting file will always have an extension of '.odin-doc'.");
+ print_usage_line(2, "Example: -out:foo");
+ }
+ }
- if (command != "test") {
- print_usage_line(1, "-no-entry-point");
- print_usage_line(2, "Removes default requirement of an entry point (e.g. main procedure).");
- print_usage_line(0, "");
+ if (run_or_build) {
+ #if defined(GB_SYSTEM_WINDOWS)
+ if (print_flag("-pdb-name:<filepath>")) {
+ print_usage_line(2, "[Windows only]");
+ print_usage_line(2, "Defines the generated PDB name when -debug is enabled.");
+ print_usage_line(2, "Example: -pdb-name:different.pdb");
}
+ #endif
}
- if (test_only) {
- print_usage_line(1, "-all-packages");
- print_usage_line(2, "Tests all packages imported into the given initial package.");
- print_usage_line(0, "");
+ if (build) {
+ if (print_flag("-print-linker-flags")) {
+ print_usage_line(2, "Prints the all of the flags/arguments that will be passed to the linker.");
+ }
}
if (run_or_build) {
- print_usage_line(1, "-minimum-os-version:<string>");
- print_usage_line(2, "Sets the minimum OS version targeted by the application.");
- print_usage_line(2, "Default: -minimum-os-version:11.0.0");
- print_usage_line(2, "Only used when target is Darwin, if given, linking mismatched versions will emit a warning.");
- print_usage_line(0, "");
+ if (print_flag("-radlink")) {
+ print_usage_line(2, "Uses the RAD linker rather than the default.");
+ }
- print_usage_line(1, "-extra-linker-flags:<string>");
- print_usage_line(2, "Adds extra linker specific flags in a string.");
- print_usage_line(0, "");
+ if (print_flag("-reloc-mode:<string>")) {
+ print_usage_line(2, "Specifies the reloc mode.");
+ print_usage_line(2, "Available options:");
+ print_usage_line(3, "-reloc-mode:default");
+ print_usage_line(3, "-reloc-mode:static");
+ print_usage_line(3, "-reloc-mode:pic");
+ print_usage_line(3, "-reloc-mode:dynamic-no-pic");
+ }
- print_usage_line(1, "-extra-assembler-flags:<string>");
- print_usage_line(2, "Adds extra assembler specific flags in a string.");
- print_usage_line(0, "");
+ #if defined(GB_SYSTEM_WINDOWS)
+ if (print_flag("-resource:<filepath>")) {
+ print_usage_line(2, "[Windows only]");
+ print_usage_line(2, "Defines the resource file for the executable.");
+ print_usage_line(2, "Example: -resource:path/to/file.rc");
+ print_usage_line(2, "or: -resource:path/to/file.res for a precompiled one.");
+ }
+ #endif
- print_usage_line(1, "-microarch:<string>");
- print_usage_line(2, "Specifies the specific micro-architecture for the build in a string.");
- print_usage_line(2, "Examples:");
- print_usage_line(3, "-microarch:sandybridge");
- print_usage_line(3, "-microarch:native");
- print_usage_line(3, "-microarch:\"?\" for a list");
- print_usage_line(0, "");
+ if (print_flag("-sanitize:<string>")) {
+ print_usage_line(2, "Enables sanitization analysis.");
+ print_usage_line(2, "Available options:");
+ print_usage_line(3, "-sanitize:address");
+ print_usage_line(3, "-sanitize:memory");
+ print_usage_line(3, "-sanitize:thread");
+ print_usage_line(2, "NOTE: This flag can be used multiple times.");
+ }
+ }
- print_usage_line(1, "-target-features:<string>");
- print_usage_line(2, "Specifies CPU features to enable on top of the enabled features implied by -microarch.");
- print_usage_line(2, "Examples:");
- print_usage_line(3, "-target-features:atomics");
- print_usage_line(3, "-target-features:\"sse2,aes\"");
- print_usage_line(3, "-target-features:\"?\" for a list");
- print_usage_line(0, "");
+ if (doc) {
+ if (print_flag("-short")) {
+ print_usage_line(2, "Shows shortened documentation for the packages.");
+ }
+ }
- print_usage_line(1, "-strict-target-features");
- print_usage_line(2, "Makes @(enable_target_features=\"...\") behave the same way as @(require_target_features=\"...\").");
- print_usage_line(2, "This enforces that all generated code uses features supported by the combination of -target, -microarch, and -target-features.");
- print_usage_line(0, "");
+ if (check) {
+ if (print_flag("-show-defineables")) {
+ print_usage_line(2, "Shows an overview of all the #config/#defined usages in the project.");
+ }
- print_usage_line(1, "-reloc-mode:<string>");
- print_usage_line(2, "Specifies the reloc mode.");
- print_usage_line(2, "Available options:");
- print_usage_line(3, "-reloc-mode:default");
- print_usage_line(3, "-reloc-mode:static");
- print_usage_line(3, "-reloc-mode:pic");
- print_usage_line(3, "-reloc-mode:dynamic-no-pic");
- print_usage_line(0, "");
+ if (print_flag("-show-system-calls")) {
+ print_usage_line(2, "Prints the whole command and arguments for calls to external tools like linker and assembler.");
+ }
- print_usage_line(1, "-disable-red-zone");
- print_usage_line(2, "Disables red zone on a supported freestanding target.");
- print_usage_line(0, "");
+ if (print_flag("-show-timings")) {
+ print_usage_line(2, "Shows basic overview of the timings of different stages within the compiler in milliseconds.");
+ }
- print_usage_line(1, "-dynamic-map-calls");
- print_usage_line(2, "Uses dynamic map calls to minimize code generation at the cost of runtime execution.");
- print_usage_line(0, "");
+ if (print_flag("-show-more-timings")) {
+ print_usage_line(2, "Shows an advanced overview of the timings of different stages within the compiler in milliseconds.");
+ }
}
- if (build) {
- print_usage_line(1, "-print-linker-flags");
- print_usage_line(2, "Prints the all of the flags/arguments that will be passed to the linker.");
- print_usage_line(0, "");
+ if (check_only) {
+ if (print_flag("-show-unused")) {
+ print_usage_line(2, "Shows unused package declarations within the current project.");
+ }
+ if (print_flag("-show-unused-with-location")) {
+ print_usage_line(2, "Shows unused package declarations within the current project with the declarations source location.");
+ }
}
if (check) {
- print_usage_line(1, "-disallow-do");
- print_usage_line(2, "Disallows the 'do' keyword in the project.");
- print_usage_line(0, "");
+ if (print_flag("-strict-style")) {
+ print_usage_line(2, "This enforces parts of same style as the Odin compiler, prefer '-vet-style -vet-semicolon' if you do not want to match it exactly.");
+ print_usage_line(2, "");
+ print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons.");
+ print_usage_line(2, "Errs on missing trailing commas followed by a newline.");
+ print_usage_line(2, "Errs on deprecated syntax.");
+ print_usage_line(2, "Errs when the attached-brace style in not adhered to (also known as 1TBS).");
+ print_usage_line(2, "Errs when 'case' labels are not in the same column as the associated 'switch' token.");
+ }
+ }
- print_usage_line(1, "-default-to-nil-allocator");
- print_usage_line(2, "Sets the default allocator to be the nil_allocator, an allocator which does nothing.");
- print_usage_line(0, "");
+ if (run_or_build) {
+ if (print_flag("-strict-target-features")) {
+ print_usage_line(2, "Makes @(enable_target_features=\"...\") behave the same way as @(require_target_features=\"...\").");
+ print_usage_line(2, "This enforces that all generated code uses features supported by the combination of -target, -microarch, and -target-features.");
+ }
- print_usage_line(1, "-strict-style");
- print_usage_line(2, "This enforces parts of same style as the Odin compiler, prefer '-vet-style -vet-semicolon' if you do not want to match it exactly.");
- print_usage_line(2, "");
- print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons.");
- print_usage_line(2, "Errs on missing trailing commas followed by a newline.");
- print_usage_line(2, "Errs on deprecated syntax.");
- print_usage_line(2, "Errs when the attached-brace style in not adhered to (also known as 1TBS).");
- print_usage_line(2, "Errs when 'case' labels are not in the same column as the associated 'switch' token.");
- print_usage_line(0, "");
+ #if defined(GB_SYSTEM_WINDOWS)
+ if (print_flag("-subsystem:<option>")) {
+ print_usage_line(2, "[Windows only]");
+ print_usage_line(2, "Defines the subsystem for the application.");
+ print_usage_line(2, "Available options:");
+ print_usage_line(3, "-subsystem:console");
+ print_usage_line(3, "-subsystem:windows");
+ }
+ #endif
- print_usage_line(1, "-ignore-warnings");
- print_usage_line(2, "Ignores warning messages.");
- print_usage_line(0, "");
+ if (print_flag("-target-features:<string>")) {
+ print_usage_line(2, "Specifies CPU features to enable on top of the enabled features implied by -microarch.");
+ print_usage_line(2, "Examples:");
+ print_usage_line(3, "-target-features:atomics");
+ print_usage_line(3, "-target-features:\"sse2,aes\"");
+ print_usage_line(3, "-target-features:\"?\" for a list");
+ }
+ }
- print_usage_line(1, "-warnings-as-errors");
- print_usage_line(2, "Treats warning messages as error messages.");
- print_usage_line(0, "");
+ if (check) {
+ if (print_flag("-target:<string>")) {
+ print_usage_line(2, "Sets the target for the executable to be built in.");
+ }
- print_usage_line(1, "-terse-errors");
- print_usage_line(2, "Prints a terse error message without showing the code on that line and the location in that line.");
- print_usage_line(0, "");
+ if (print_flag("-terse-errors")) {
+ print_usage_line(2, "Prints a terse error message without showing the code on that line and the location in that line.");
+ }
- print_usage_line(1, "-json-errors");
- print_usage_line(2, "Prints the error messages as json to stderr.");
- print_usage_line(0, "");
+ if (print_flag("-thread-count:<integer>")) {
+ print_usage_line(2, "Overrides the number of threads the compiler will use to compile with.");
+ print_usage_line(2, "Example: -thread-count:2");
+ }
+ }
- print_usage_line(1, "-error-pos-style:<string>");
- print_usage_line(2, "Available options:");
- print_usage_line(3, "-error-pos-style:unix file/path:45:3:");
- print_usage_line(3, "-error-pos-style:odin file/path(45:3)");
- print_usage_line(3, "-error-pos-style:default (Defaults to 'odin'.)");
- print_usage_line(0, "");
+ if (run_or_build) {
+ if (print_flag("-use-separate-modules")) {
+ print_usage_line(2, "The backend generates multiple build units which are then linked together.");
+ print_usage_line(2, "Normally, a single build unit is generated for a standard project.");
+ print_usage_line(2, "This is the default behaviour on Windows for '-o:none' and '-o:minimal' builds.");
+ }
- print_usage_line(1, "-max-error-count:<integer>");
- print_usage_line(2, "Sets the maximum number of errors that can be displayed before the compiler terminates.");
- print_usage_line(2, "Must be an integer >0.");
- print_usage_line(2, "If not set, the default max error count is %d.", DEFAULT_MAX_ERROR_COLLECTOR_COUNT);
- print_usage_line(0, "");
+ }
- print_usage_line(1, "-min-link-libs");
- print_usage_line(2, "If set, the number of linked libraries will be minimized to prevent duplications.");
- print_usage_line(2, "This is useful for so called \"dumb\" linkers compared to \"smart\" linkers.");
- print_usage_line(0, "");
- print_usage_line(1, "-foreign-error-procedures");
- print_usage_line(2, "States that the error procedures used in the runtime are defined in a separate translation unit.");
- print_usage_line(0, "");
+ if (check) {
+ if (print_flag("-vet")) {
+ print_usage_line(2, "Does extra checks on the code.");
+ print_usage_line(2, "Extra checks include:");
+ print_usage_line(3, "-vet-unused");
+ print_usage_line(3, "-vet-unused-variables");
+ print_usage_line(3, "-vet-unused-imports");
+ print_usage_line(3, "-vet-shadowing");
+ print_usage_line(3, "-vet-using-stmt");
+ }
- }
+ if (print_flag("-vet-cast")) {
+ print_usage_line(2, "Errs on casting a value to its own type or using `transmute` rather than `cast`.");
+ }
- if (run_or_build) {
- print_usage_line(1, "-obfuscate-source-code-locations");
- print_usage_line(2, "Obfuscate the file and procedure strings, and line and column numbers, stored with a 'runtime.Source_Code_Location' value.");
- print_usage_line(0, "");
+ if (print_flag("-vet-packages:<comma-separated-strings>")) {
+ print_usage_line(2, "Sets which packages by name will be vetted.");
+ print_usage_line(2, "Files with specific +vet tags will not be ignored if they are not in the packages set.");
+ }
- print_usage_line(1, "-sanitize:<string>");
- print_usage_line(2, "Enables sanitization analysis.");
- print_usage_line(2, "Available options:");
- print_usage_line(3, "-sanitize:address");
- print_usage_line(3, "-sanitize:memory");
- print_usage_line(3, "-sanitize:thread");
- print_usage_line(2, "NOTE: This flag can be used multiple times.");
- print_usage_line(0, "");
+ if (print_flag("-vet-semicolon")) {
+ print_usage_line(2, "Errs on unneeded semicolons.");
+ }
- }
- if (run_or_build) {
- #if defined(GB_SYSTEM_WINDOWS)
- print_usage_line(1, "-ignore-vs-search");
- print_usage_line(2, "[Windows only]");
- print_usage_line(2, "Ignores the Visual Studio search for library paths.");
- print_usage_line(0, "");
+ if (print_flag("-vet-shadowing")) {
+ print_usage_line(2, "Checks for variable shadowing within procedures.");
+ }
- print_usage_line(1, "-resource:<filepath>");
- print_usage_line(2, "[Windows only]");
- print_usage_line(2, "Defines the resource file for the executable.");
- print_usage_line(2, "Example: -resource:path/to/file.rc");
- print_usage_line(2, "or: -resource:path/to/file.res for a precompiled one.");
- print_usage_line(0, "");
+ if (print_flag("-vet-style")) {
+ print_usage_line(2, "Errs on missing trailing commas followed by a newline.");
+ print_usage_line(2, "Errs on deprecated syntax.");
+ print_usage_line(2, "Does not err on unneeded tokens (unlike -strict-style).");
+ }
- print_usage_line(1, "-pdb-name:<filepath>");
- print_usage_line(2, "[Windows only]");
- print_usage_line(2, "Defines the generated PDB name when -debug is enabled.");
- print_usage_line(2, "Example: -pdb-name:different.pdb");
- print_usage_line(0, "");
- print_usage_line(1, "-subsystem:<option>");
- print_usage_line(2, "[Windows only]");
- print_usage_line(2, "Defines the subsystem for the application.");
- print_usage_line(2, "Available options:");
- print_usage_line(3, "-subsystem:console");
- print_usage_line(3, "-subsystem:windows");
- print_usage_line(0, "");
+ if (print_flag("-vet-tabs")) {
+ print_usage_line(2, "Errs when the use of tabs has not been used for indentation.");
+ }
- #endif
+
+ if (print_flag("-vet-unused")) {
+ print_usage_line(2, "Checks for unused declarations (variables and imports).");
+ }
+
+ if (print_flag("-vet-unused-imports")) {
+ print_usage_line(2, "Checks for unused import declarations.");
+ }
+
+ if (print_flag("-vet-unused-procedures")) {
+ print_usage_line(2, "Checks for unused procedures.");
+ print_usage_line(2, "Must be used with -vet-packages or specified on a per file with +vet tags.");
+ }
+
+ if (print_flag("-vet-unused-variables")) {
+ print_usage_line(2, "Checks for unused variable declarations.");
+ }
+
+
+ if (print_flag("-vet-using-param")) {
+ print_usage_line(2, "Checks for the use of 'using' on procedure parameters.");
+ print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring.");
+ }
+
+ if (print_flag("-vet-using-stmt")) {
+ print_usage_line(2, "Checks for the use of 'using' as a statement.");
+ print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring.");
+ }
+ }
+
+ if (check) {
+ if (print_flag("-warnings-as-errors")) {
+ print_usage_line(2, "Treats warning messages as error messages.");
+ }
}
}
@@ -3132,7 +3268,7 @@ int main(int arg_count, char const **arg_ptr) {
usage(args[0]);
return 1;
} else {
- print_show_help(args[0], args[2]);
+ print_show_help(args[0], args[1], args[2]);
return 0;
}
} else if (command == "root") {
@@ -3276,6 +3412,19 @@ int main(int arg_count, char const **arg_ptr) {
}
}
+ #if defined(GB_CPU_X86)
+ // We've detected that the CPU doesn't support popcnt, or another reason to use `-microarch:native`,
+ // and that no custom microarch was chosen.
+ if (should_use_march_native() && march == get_default_microarchitecture()) {
+ if (command == "run" || command == "test") {
+ gb_printf_err("Error: Try using '-microarch:native' as Odin defaults to %.*s (close to Nehalem), and your CPU seems to be older.\n", LIT(march));
+ gb_exit(1);
+ } else if (command == "build") {
+ gb_printf("Suggestion: Try using '-microarch:native' as Odin defaults to %.*s (close to Nehalem), and your CPU seems to be older.\n", LIT(march));
+ }
+ }
+ #endif
+
if (build_context.target_features_string.len != 0) {
String_Iterator target_it = {build_context.target_features_string, 0};
for (;;) {
@@ -3325,7 +3474,7 @@ int main(int arg_count, char const **arg_ptr) {
if (LLVM_VERSION_MAJOR < 17) {
gb_printf_err("Invalid LLVM version %s, RISC-V targets require at least LLVM 17\n", LLVM_VERSION_STRING);
gb_exit(1);
- }
+ }
}
if (build_context.show_debug_messages) {
@@ -3347,6 +3496,7 @@ int main(int arg_count, char const **arg_ptr) {
Parser *parser = gb_alloc_item(permanent_allocator(), Parser);
Checker *checker = gb_alloc_item(permanent_allocator(), Checker);
+ bool failed_to_cache_parsing = false;
MAIN_TIME_SECTION("parse files");
@@ -3366,10 +3516,6 @@ int main(int arg_count, char const **arg_ptr) {
print_all_errors();
return 1;
}
- if (any_warnings()) {
- print_all_errors();
- }
-
checker->parser = parser;
init_checker(checker);
@@ -3396,7 +3542,7 @@ int main(int arg_count, char const **arg_ptr) {
if (build_context.show_defineables || build_context.export_defineables_file != "") {
TEMPORARY_ALLOCATOR_GUARD();
temp_alloc_defineable_strings(checker);
- sort_defineables(checker);
+ sort_defineables_and_remove_duplicates(checker);
if (build_context.show_defineables) {
show_defineables(checker);
@@ -3440,6 +3586,7 @@ int main(int arg_count, char const **arg_ptr) {
if (try_cached_build(checker, args)) {
goto end_of_code_gen;
}
+ failed_to_cache_parsing = true;
}
#if ALLOW_TILDE
@@ -3505,18 +3652,23 @@ int main(int arg_count, char const **arg_ptr) {
end_of_code_gen:;
- if (build_context.show_timings) {
- show_timings(checker, &global_timings);
- }
-
if (build_context.export_dependencies_format != DependenciesExportUnspecified) {
export_dependencies(checker);
}
+ if (build_context.cached) {
+ MAIN_TIME_SECTION("write cached build");
+ if (!build_context.build_cache_data.copy_already_done) {
+ try_copy_executable_to_cache();
+ }
+
+ if (failed_to_cache_parsing) {
+ write_cached_build(checker, args);
+ }
+ }
- if (!build_context.build_cache_data.copy_already_done &&
- build_context.cached) {
- try_copy_executable_to_cache();
+ if (build_context.show_timings) {
+ show_timings(checker, &global_timings);
}
if (run_output) {
diff --git a/src/parser.cpp b/src/parser.cpp
index 520a23c5a..aa90651d3 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -448,7 +448,8 @@ gb_internal Ast *clone_ast(Ast *node, AstFile *f) {
n->StructType.fields = clone_ast_array(n->StructType.fields, f);
n->StructType.polymorphic_params = clone_ast(n->StructType.polymorphic_params, f);
n->StructType.align = clone_ast(n->StructType.align, f);
- n->StructType.field_align = clone_ast(n->StructType.field_align, f);
+ n->StructType.min_field_align = clone_ast(n->StructType.min_field_align, f);
+ n->StructType.max_field_align = clone_ast(n->StructType.max_field_align, f);
n->StructType.where_clauses = clone_ast_array(n->StructType.where_clauses, f);
break;
case Ast_UnionType:
@@ -1217,7 +1218,7 @@ gb_internal Ast *ast_dynamic_array_type(AstFile *f, Token token, Ast *elem) {
gb_internal Ast *ast_struct_type(AstFile *f, Token token, Slice<Ast *> fields, isize field_count,
Ast *polymorphic_params, bool is_packed, bool is_raw_union, bool is_no_copy,
- Ast *align, Ast *field_align,
+ Ast *align, Ast *min_field_align, Ast *max_field_align,
Token where_token, Array<Ast *> const &where_clauses) {
Ast *result = alloc_ast_node(f, Ast_StructType);
result->StructType.token = token;
@@ -1228,7 +1229,8 @@ gb_internal Ast *ast_struct_type(AstFile *f, Token token, Slice<Ast *> fields, i
result->StructType.is_raw_union = is_raw_union;
result->StructType.is_no_copy = is_no_copy;
result->StructType.align = align;
- result->StructType.field_align = field_align;
+ result->StructType.min_field_align = min_field_align;
+ result->StructType.max_field_align = max_field_align;
result->StructType.where_token = where_token;
result->StructType.where_clauses = slice_from_array(where_clauses);
return result;
@@ -2486,6 +2488,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
tag = parse_call_expr(f, tag);
}
Ast *type = parse_type(f);
+ syntax_error(tag, "#relative types have now been removed in favour of \"core:relative\"");
return ast_relative_type(f, tag, type);
} else if (name.string == "force_inline" ||
name.string == "force_no_inline") {
@@ -2757,7 +2760,8 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
bool is_raw_union = false;
bool no_copy = false;
Ast *align = nullptr;
- Ast *field_align = nullptr;
+ Ast *min_field_align = nullptr;
+ Ast *max_field_align = nullptr;
if (allow_token(f, Token_OpenParen)) {
isize param_count = 0;
@@ -2795,18 +2799,43 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
gb_string_free(s);
}
} else if (tag.string == "field_align") {
- if (field_align) {
+ if (min_field_align) {
syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string));
}
- field_align = parse_expr(f, true);
- if (field_align && field_align->kind != Ast_ParenExpr) {
+ syntax_warning(tag, "#field_align has been deprecated in favour of #min_field_align");
+ min_field_align = parse_expr(f, true);
+ if (min_field_align && min_field_align->kind != Ast_ParenExpr) {
ERROR_BLOCK();
- gbString s = expr_to_string(field_align);
+ gbString s = expr_to_string(min_field_align);
syntax_warning(tag, "#field_align requires parentheses around the expression");
- error_line("\tSuggestion: #field_align(%s)", s);
+ error_line("\tSuggestion: #min_field_align(%s)", s);
gb_string_free(s);
}
- } else if (tag.string == "raw_union") {
+ } else if (tag.string == "min_field_align") {
+ if (min_field_align) {
+ syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string));
+ }
+ min_field_align = parse_expr(f, true);
+ if (min_field_align && min_field_align->kind != Ast_ParenExpr) {
+ ERROR_BLOCK();
+ gbString s = expr_to_string(min_field_align);
+ syntax_warning(tag, "#min_field_align requires parentheses around the expression");
+ error_line("\tSuggestion: #min_field_align(%s)", s);
+ gb_string_free(s);
+ }
+ } else if (tag.string == "max_field_align") {
+ if (max_field_align) {
+ syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string));
+ }
+ max_field_align = parse_expr(f, true);
+ if (max_field_align && max_field_align->kind != Ast_ParenExpr) {
+ ERROR_BLOCK();
+ gbString s = expr_to_string(max_field_align);
+ syntax_warning(tag, "#max_field_align requires parentheses around the expression");
+ error_line("\tSuggestion: #max_field_align(%s)", s);
+ gb_string_free(s);
+ }
+ }else if (tag.string == "raw_union") {
if (is_raw_union) {
syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string));
}
@@ -2856,7 +2885,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
parser_check_polymorphic_record_parameters(f, polymorphic_params);
- return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_raw_union, no_copy, align, field_align, where_token, where_clauses);
+ return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_raw_union, no_copy, align, min_field_align, max_field_align, where_token, where_clauses);
} break;
case Token_union: {
@@ -4234,8 +4263,6 @@ gb_internal bool allow_field_separator(AstFile *f) {
gb_internal Ast *parse_struct_field_list(AstFile *f, isize *name_count_) {
Token start_token = f->curr_token;
- auto decls = array_make<Ast *>(ast_allocator(f));
-
isize total_name_count = 0;
Ast *params = parse_field_list(f, &total_name_count, FieldFlag_Struct, Token_CloseBrace, false, false);
@@ -4377,10 +4404,14 @@ gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_fl
}
}
- allow_field_separator(f);
+ bool more_fields = allow_field_separator(f);
Ast *param = ast_field(f, names, type, default_value, set_flags, tag, docs, f->line_comment);
array_add(&params, param);
+ if (!more_fields) {
+ if (name_count_) *name_count_ = total_name_count;
+ return ast_field_list(f, start_token, params);
+ }
while (f->curr_token.kind != follow &&
f->curr_token.kind != Token_EOF &&
diff --git a/src/parser.hpp b/src/parser.hpp
index d5117a31e..e332fed50 100644
--- a/src/parser.hpp
+++ b/src/parser.hpp
@@ -736,7 +736,8 @@ AST_KIND(_TypeBegin, "", bool) \
isize field_count; \
Ast *polymorphic_params; \
Ast *align; \
- Ast *field_align; \
+ Ast *min_field_align; \
+ Ast *max_field_align; \
Token where_token; \
Slice<Ast *> where_clauses; \
bool is_packed; \
diff --git a/src/string.cpp b/src/string.cpp
index 3c7d96934..f8ee6c53e 100644
--- a/src/string.cpp
+++ b/src/string.cpp
@@ -156,6 +156,7 @@ gb_internal isize string_index_byte(String const &s, u8 x) {
gb_internal gb_inline bool str_eq(String const &a, String const &b) {
if (a.len != b.len) return false;
+ if (a.len == 0) return true;
return memcmp(a.text, b.text, a.len) == 0;
}
gb_internal gb_inline bool str_ne(String const &a, String const &b) { return !str_eq(a, b); }
@@ -411,6 +412,32 @@ gb_internal String concatenate4_strings(gbAllocator a, String const &x, String c
return make_string(data, len);
}
+#if defined(GB_SYSTEM_WINDOWS)
+gb_internal String escape_char(gbAllocator a, String s, char cte) {
+ isize buf_len = s.len;
+ isize cte_count = 0;
+ for (isize j = 0; j < s.len; j++) {
+ if (s.text[j] == cte) {
+ cte_count++;
+ }
+ }
+
+ u8 *buf = gb_alloc_array(a, u8, buf_len+cte_count);
+ isize i = 0;
+ for (isize j = 0; j < s.len; j++) {
+ u8 c = s.text[j];
+
+ if (c == cte) {
+ buf[i++] = '\\';
+ buf[i++] = c;
+ } else {
+ buf[i++] = c;
+ }
+ }
+ return make_string(buf, i);
+}
+#endif
+
gb_internal String string_join_and_quote(gbAllocator a, Array<String> strings) {
if (!strings.count) {
return make_string(nullptr, 0);
@@ -426,7 +453,11 @@ gb_internal String string_join_and_quote(gbAllocator a, Array<String> strings) {
if (i > 0) {
s = gb_string_append_fmt(s, " ");
}
+#if defined(GB_SYSTEM_WINDOWS)
+ s = gb_string_append_fmt(s, "\"%.*s\" ", LIT(escape_char(a, strings[i], '\\')));
+#else
s = gb_string_append_fmt(s, "\"%.*s\" ", LIT(strings[i]));
+#endif
}
return make_string(cast(u8 *) s, gb_string_length(s));
diff --git a/src/types.cpp b/src/types.cpp
index a9a7d6dda..c51df7261 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -137,7 +137,8 @@ struct TypeStruct {
Scope * scope;
i64 custom_align;
- i64 custom_field_align;
+ i64 custom_min_field_align;
+ i64 custom_max_field_align;
Type * polymorphic_params; // Type_Tuple
Type * polymorphic_parent;
Wait_Signal polymorphic_wait_signal;
@@ -271,14 +272,6 @@ struct TypeProc {
Type *elem; \
Type *generic_count; \
}) \
- TYPE_KIND(RelativePointer, struct { \
- Type *pointer_type; \
- Type *base_integer; \
- }) \
- TYPE_KIND(RelativeMultiPointer, struct { \
- Type *pointer_type; \
- Type *base_integer; \
- }) \
TYPE_KIND(Matrix, struct { \
Type *elem; \
i64 row_count; \
@@ -366,8 +359,6 @@ enum Typeid_Kind : u8 {
Typeid_Map,
Typeid_Bit_Set,
Typeid_Simd_Vector,
- Typeid_Relative_Pointer,
- Typeid_Relative_Multi_Pointer,
Typeid_Matrix,
Typeid_SoaPointer,
Typeid_Bit_Field,
@@ -677,8 +668,6 @@ gb_global Type *t_type_info_enum = nullptr;
gb_global Type *t_type_info_map = nullptr;
gb_global Type *t_type_info_bit_set = nullptr;
gb_global Type *t_type_info_simd_vector = nullptr;
-gb_global Type *t_type_info_relative_pointer = nullptr;
-gb_global Type *t_type_info_relative_multi_pointer = nullptr;
gb_global Type *t_type_info_matrix = nullptr;
gb_global Type *t_type_info_soa_pointer = nullptr;
gb_global Type *t_type_info_bit_field = nullptr;
@@ -707,8 +696,6 @@ gb_global Type *t_type_info_enum_ptr = nullptr;
gb_global Type *t_type_info_map_ptr = nullptr;
gb_global Type *t_type_info_bit_set_ptr = nullptr;
gb_global Type *t_type_info_simd_vector_ptr = nullptr;
-gb_global Type *t_type_info_relative_pointer_ptr = nullptr;
-gb_global Type *t_type_info_relative_multi_pointer_ptr = nullptr;
gb_global Type *t_type_info_matrix_ptr = nullptr;
gb_global Type *t_type_info_soa_pointer_ptr = nullptr;
gb_global Type *t_type_info_bit_field_ptr = nullptr;
@@ -1117,24 +1104,6 @@ gb_internal Type *alloc_type_bit_field() {
return t;
}
-gb_internal Type *alloc_type_relative_pointer(Type *pointer_type, Type *base_integer) {
- GB_ASSERT(is_type_pointer(pointer_type));
- GB_ASSERT(is_type_integer(base_integer));
- Type *t = alloc_type(Type_RelativePointer);
- t->RelativePointer.pointer_type = pointer_type;
- t->RelativePointer.base_integer = base_integer;
- return t;
-}
-
-gb_internal Type *alloc_type_relative_multi_pointer(Type *pointer_type, Type *base_integer) {
- GB_ASSERT(is_type_multi_pointer(pointer_type));
- GB_ASSERT(is_type_integer(base_integer));
- Type *t = alloc_type(Type_RelativeMultiPointer);
- t->RelativeMultiPointer.pointer_type = pointer_type;
- t->RelativeMultiPointer.base_integer = base_integer;
- return t;
-}
-
gb_internal Type *alloc_type_named(String name, Type *base, Entity *type_name) {
Type *t = alloc_type(Type_Named);
t->Named.name = name;
@@ -1226,8 +1195,6 @@ gb_internal Type *type_deref(Type *t, bool allow_multi_pointer) {
switch (bt->kind) {
case Type_Pointer:
return bt->Pointer.elem;
- case Type_RelativePointer:
- return type_deref(bt->RelativePointer.pointer_type);
case Type_SoaPointer:
{
Type *elem = base_type(bt->SoaPointer.elem);
@@ -1666,15 +1633,6 @@ gb_internal bool is_type_generic(Type *t) {
return t->kind == Type_Generic;
}
-gb_internal bool is_type_relative_pointer(Type *t) {
- t = base_type(t);
- return t->kind == Type_RelativePointer;
-}
-gb_internal bool is_type_relative_multi_pointer(Type *t) {
- t = base_type(t);
- return t->kind == Type_RelativeMultiPointer;
-}
-
gb_internal bool is_type_u8_slice(Type *t) {
t = base_type(t);
if (t->kind == Type_Slice) {
@@ -2117,8 +2075,6 @@ gb_internal bool is_type_indexable(Type *t) {
return true;
case Type_EnumeratedArray:
return true;
- case Type_RelativeMultiPointer:
- return true;
case Type_Matrix:
return true;
}
@@ -2136,8 +2092,6 @@ gb_internal bool is_type_sliceable(Type *t) {
return true;
case Type_EnumeratedArray:
return false;
- case Type_RelativeMultiPointer:
- return true;
case Type_Matrix:
return false;
}
@@ -2344,27 +2298,7 @@ gb_internal bool is_type_polymorphic(Type *t, bool or_specialized=false) {
return true;
}
break;
-
- case Type_RelativeMultiPointer:
- if (is_type_polymorphic(t->RelativeMultiPointer.pointer_type, or_specialized)) {
- return true;
- }
- if (t->RelativeMultiPointer.base_integer != nullptr &&
- is_type_polymorphic(t->RelativeMultiPointer.base_integer, or_specialized)) {
- return true;
- }
- break;
- case Type_RelativePointer:
- if (is_type_polymorphic(t->RelativePointer.pointer_type, or_specialized)) {
- return true;
- }
- if (t->RelativePointer.base_integer != nullptr &&
- is_type_polymorphic(t->RelativePointer.base_integer, or_specialized)) {
- return true;
- }
- break;
}
-
return false;
}
@@ -2406,10 +2340,6 @@ gb_internal bool type_has_nil(Type *t) {
}
}
return false;
-
- case Type_RelativePointer:
- case Type_RelativeMultiPointer:
- return true;
}
return false;
}
@@ -2578,10 +2508,6 @@ gb_internal bool is_type_load_safe(Type *type) {
}
return true;
- case Type_RelativePointer:
- case Type_RelativeMultiPointer:
- return true;
-
case Type_Pointer:
case Type_MultiPointer:
case Type_Slice:
@@ -3912,6 +3838,14 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) {
max = align;
}
}
+
+ if (t->Struct.custom_min_field_align > 0) {
+ max = gb_max(max, t->Struct.custom_min_field_align);
+ }
+ if (t->Struct.custom_max_field_align != 0 &&
+ t->Struct.custom_max_field_align > t->Struct.custom_min_field_align) {
+ max = gb_min(max, t->Struct.custom_max_field_align);
+ }
return max;
} break;
@@ -3936,11 +3870,6 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) {
case Type_Matrix:
return matrix_align_of(t, path);
- case Type_RelativePointer:
- return type_align_of_internal(t->RelativePointer.base_integer, path);
- case Type_RelativeMultiPointer:
- return type_align_of_internal(t->RelativeMultiPointer.base_integer, path);
-
case Type_SoaPointer:
return build_context.int_size;
}
@@ -3950,7 +3879,7 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) {
return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.max_align);
}
-gb_internal i64 *type_set_offsets_of(Slice<Entity *> const &fields, bool is_packed, bool is_raw_union, i64 min_field_align) {
+gb_internal i64 *type_set_offsets_of(Slice<Entity *> const &fields, bool is_packed, bool is_raw_union, i64 min_field_align, i64 max_field_align) {
gbAllocator a = permanent_allocator();
auto offsets = gb_alloc_array(a, i64, fields.count);
i64 curr_offset = 0;
@@ -3980,6 +3909,9 @@ gb_internal i64 *type_set_offsets_of(Slice<Entity *> const &fields, bool is_pack
} else {
Type *t = fields[i]->type;
i64 align = gb_max(type_align_of(t), min_field_align);
+ if (max_field_align > min_field_align) {
+ align = gb_min(align, max_field_align);
+ }
i64 size = gb_max(type_size_of( t), 0);
curr_offset = align_formula(curr_offset, align);
offsets[i] = curr_offset;
@@ -3996,7 +3928,7 @@ gb_internal bool type_set_offsets(Type *t) {
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, t->Struct.custom_field_align);
+ t->Struct.offsets = type_set_offsets_of(t->Struct.fields, t->Struct.is_packed, t->Struct.is_raw_union, t->Struct.custom_min_field_align, t->Struct.custom_max_field_align);
t->Struct.are_offsets_being_processed = false;
t->Struct.are_offsets_set = true;
return true;
@@ -4005,7 +3937,7 @@ gb_internal bool type_set_offsets(Type *t) {
MUTEX_GUARD(&t->Tuple.mutex);
if (!t->Tuple.are_offsets_set) {
t->Tuple.are_offsets_being_processed = true;
- t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, t->Tuple.is_packed, false, 1);
+ t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, t->Tuple.is_packed, false, 1, 0);
t->Tuple.are_offsets_being_processed = false;
t->Tuple.are_offsets_set = true;
return true;
@@ -4230,11 +4162,6 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) {
case Type_BitField:
return type_size_of_internal(t->BitField.backing_type, path);
-
- case Type_RelativePointer:
- return type_size_of_internal(t->RelativePointer.base_integer, path);
- case Type_RelativeMultiPointer:
- return type_size_of_internal(t->RelativeMultiPointer.base_integer, path);
}
// Catch all
@@ -4860,19 +4787,6 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
str = gb_string_append_fmt(str, "#simd[%d]", cast(int)type->SimdVector.count);
str = write_type_to_string(str, type->SimdVector.elem);
break;
-
- case Type_RelativePointer:
- str = gb_string_append_fmt(str, "#relative(");
- str = write_type_to_string(str, type->RelativePointer.base_integer);
- str = gb_string_append_fmt(str, ") ");
- str = write_type_to_string(str, type->RelativePointer.pointer_type);
- break;
- case Type_RelativeMultiPointer:
- str = gb_string_append_fmt(str, "#relative(");
- str = write_type_to_string(str, type->RelativePointer.base_integer);
- str = gb_string_append_fmt(str, ") ");
- str = write_type_to_string(str, type->RelativePointer.pointer_type);
- break;
case Type_Matrix:
if (type->Matrix.is_row_major) {
diff --git a/src/unicode.cpp b/src/unicode.cpp
index 665d5b182..cb9fb12ab 100644
--- a/src/unicode.cpp
+++ b/src/unicode.cpp
@@ -1,10 +1,15 @@
-#pragma warning(push)
-#pragma warning(disable: 4245)
+#if defined(GB_SYSTEM_WINDOWS)
+ #pragma warning(push)
+ #pragma warning(disable: 4245)
+#endif
extern "C" {
#include "utf8proc/utf8proc.c"
}
-#pragma warning(pop)
+
+#if defined(GB_SYSTEM_WINDOWS)
+ #pragma warning(pop)
+#endif
gb_internal bool rune_is_letter(Rune r) {
@@ -109,7 +114,7 @@ gb_internal isize utf8_decode(u8 const *str, isize str_len, Rune *codepoint_out)
u8 b1, b2, b3;
Utf8AcceptRange accept;
if (x >= 0xf0) {
- Rune mask = (cast(Rune)x << 31) >> 31;
+ Rune mask = -cast(Rune)(x & 1);
codepoint = (cast(Rune)s0 & (~mask)) | (GB_RUNE_INVALID & mask);
width = 1;
goto end;