Merge branch 'master' into netbsd

This commit is contained in:
Andreas T Jonsson
2024-04-25 22:04:40 +02:00
111 changed files with 6783 additions and 922 deletions
+58 -88
View File
@@ -274,13 +274,16 @@ enum BuildPath : u8 {
};
enum VetFlags : u64 {
VetFlag_NONE = 0,
VetFlag_Unused = 1u<<0, // 1
VetFlag_Shadowing = 1u<<1, // 2
VetFlag_UsingStmt = 1u<<2, // 4
VetFlag_UsingParam = 1u<<3, // 8
VetFlag_Style = 1u<<4, // 16
VetFlag_Semicolon = 1u<<5, // 32
VetFlag_NONE = 0,
VetFlag_Shadowing = 1u<<0,
VetFlag_UsingStmt = 1u<<1,
VetFlag_UsingParam = 1u<<2,
VetFlag_Style = 1u<<3,
VetFlag_Semicolon = 1u<<4,
VetFlag_UnusedVariables = 1u<<5,
VetFlag_UnusedImports = 1u<<6,
VetFlag_Unused = VetFlag_UnusedVariables|VetFlag_UnusedImports,
VetFlag_All = VetFlag_Unused|VetFlag_Shadowing|VetFlag_UsingStmt,
@@ -290,6 +293,10 @@ enum VetFlags : u64 {
u64 get_vet_flag_from_name(String const &name) {
if (name == "unused") {
return VetFlag_Unused;
} else if (name == "unused-variables") {
return VetFlag_UnusedVariables;
} else if (name == "unused-imports") {
return VetFlag_UnusedImports;
} else if (name == "shadowing") {
return VetFlag_Shadowing;
} else if (name == "using-stmt") {
@@ -377,6 +384,7 @@ struct BuildContext {
bool keep_temp_files;
bool ignore_unknown_attributes;
bool no_bounds_check;
bool no_type_assert;
bool no_dynamic_literals;
bool no_output_files;
bool no_crt;
@@ -634,6 +642,15 @@ gb_global TargetMetrics target_freestanding_amd64_sysv = {
TargetABI_SysV,
};
gb_global TargetMetrics target_freestanding_amd64_win64 = {
TargetOs_freestanding,
TargetArch_amd64,
8, 8, 8, 16,
str_lit("x86_64-pc-none-msvc"),
str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
TargetABI_Win64,
};
gb_global TargetMetrics target_freestanding_arm64 = {
TargetOs_freestanding,
TargetArch_arm64,
@@ -676,7 +693,9 @@ gb_global NamedTargetMetrics named_targets[] = {
{ str_lit("js_wasm64p32"), &target_js_wasm64p32 },
{ str_lit("wasi_wasm64p32"), &target_wasi_wasm64p32 },
{ str_lit("freestanding_amd64_sysv"), &target_freestanding_amd64_sysv },
{ str_lit("freestanding_amd64_sysv"), &target_freestanding_amd64_sysv },
{ str_lit("freestanding_amd64_win64"), &target_freestanding_amd64_win64 },
{ str_lit("freestanding_arm64"), &target_freestanding_arm64 },
};
@@ -832,13 +851,11 @@ gb_internal String odin_root_dir(void) {
char const *found = gb_get_env("ODIN_ROOT", a);
if (found) {
String path = path_to_full_path(a, make_string_c(found));
if (path[path.len-1] != '/' && path[path.len-1] != '\\') {
#if defined(GB_SYSTEM_WINDOWS)
path = concatenate_strings(a, path, WIN32_SEPARATOR_STRING);
path = normalize_path(a, path, WIN32_SEPARATOR_STRING);
#else
path = concatenate_strings(a, path, NIX_SEPARATOR_STRING);
path = normalize_path(a, path, NIX_SEPARATOR_STRING);
#endif
}
global_module_path = path;
global_module_path_set = true;
@@ -1461,26 +1478,6 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
}
bc->metrics = *metrics;
if (metrics->os == TargetOs_darwin) {
if (!bc->minimum_os_version_string_given) {
bc->minimum_os_version_string = str_lit("11.0.0");
}
switch (subtarget) {
case Subtarget_Default:
bc->metrics.target_triplet = concatenate_strings(permanent_allocator(), bc->metrics.target_triplet, bc->minimum_os_version_string);
break;
case Subtarget_iOS:
if (metrics->arch == TargetArch_arm64) {
bc->metrics.target_triplet = str_lit("arm64-apple-ios");
} else if (metrics->arch == TargetArch_amd64) {
bc->metrics.target_triplet = str_lit("x86_64-apple-ios");
} else {
GB_PANIC("Unknown architecture for darwin");
}
break;
}
}
bc->ODIN_OS = target_os_names[metrics->os];
bc->ODIN_ARCH = target_arch_names[metrics->arch];
@@ -1516,65 +1513,26 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
bc->ODIN_WINDOWS_SUBSYSTEM = windows_subsystem_names[Windows_Subsystem_CONSOLE];
}
// NOTE(zangent): The linker flags to set the build architecture are different
// across OSs. It doesn't make sense to allocate extra data on the heap
// here, so I just #defined the linker flags to keep things concise.
if (bc->metrics.arch == TargetArch_amd64) {
switch (bc->metrics.os) {
case TargetOs_windows:
bc->link_flags = str_lit("/machine:x64 ");
if (metrics->os == TargetOs_darwin && subtarget == Subtarget_iOS) {
switch (metrics->arch) {
case TargetArch_arm64:
bc->metrics.target_triplet = str_lit("arm64-apple-ios");
break;
case TargetOs_darwin:
bc->link_flags = str_lit("-arch x86_64 ");
break;
case TargetOs_linux:
bc->link_flags = str_lit("-arch x86-64 ");
break;
case TargetOs_freebsd:
bc->link_flags = str_lit("-arch x86-64 ");
break;
case TargetOs_openbsd:
bc->link_flags = str_lit("-arch x86-64 ");
break;
case TargetOs_netbsd:
bc->link_flags = str_lit("-arch x86-64 ");
break;
case TargetOs_haiku:
bc->link_flags = str_lit("-arch x86-64 ");
break;
}
} else if (bc->metrics.arch == TargetArch_i386) {
switch (bc->metrics.os) {
case TargetOs_windows:
bc->link_flags = str_lit("/machine:x86 ");
break;
case TargetOs_darwin:
gb_printf_err("Unsupported architecture\n");
gb_exit(1);
break;
case TargetOs_linux:
bc->link_flags = str_lit("-arch x86 ");
break;
case TargetOs_freebsd:
bc->link_flags = str_lit("-arch x86 ");
break;
}
} else if (bc->metrics.arch == TargetArch_arm32) {
switch (bc->metrics.os) {
case TargetOs_linux:
bc->link_flags = str_lit("-arch arm ");
case TargetArch_amd64:
bc->metrics.target_triplet = str_lit("x86_64-apple-ios");
break;
default:
gb_printf_err("Compiler Error: Unsupported architecture\n");
gb_exit(1);
GB_PANIC("Unknown architecture for darwin");
}
} else if (bc->metrics.arch == TargetArch_arm64) {
switch (bc->metrics.os) {
case TargetOs_darwin:
bc->link_flags = str_lit("-arch arm64 ");
}
if (bc->metrics.os == TargetOs_windows) {
switch (bc->metrics.arch) {
case TargetArch_amd64:
bc->link_flags = str_lit("/machine:x64 ");
break;
case TargetOs_linux:
bc->link_flags = str_lit("-arch aarch64 ");
case TargetArch_i386:
bc->link_flags = str_lit("/machine:x86 ");
break;
}
} else if (is_arch_wasm()) {
@@ -1594,8 +1552,20 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
// Disallow on wasm
bc->use_separate_modules = false;
} else {
gb_printf_err("Compiler Error: Unsupported architecture\n");
gb_exit(1);
bc->link_flags = concatenate3_strings(permanent_allocator(),
str_lit("-target "), bc->metrics.target_triplet, str_lit(" "));
}
// NOTE: needs to be done after adding the -target flag to the linker flags so the linker
// does not annoy the user with version warnings.
if (metrics->os == TargetOs_darwin) {
if (!bc->minimum_os_version_string_given) {
bc->minimum_os_version_string = str_lit("11.0.0");
}
if (subtarget == Subtarget_Default) {
bc->metrics.target_triplet = concatenate_strings(permanent_allocator(), bc->metrics.target_triplet, bc->minimum_os_version_string);
}
}
if (bc->ODIN_DEBUG && !bc->custom_optimization_level) {
+45 -2
View File
@@ -474,16 +474,59 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O
}
Entity *e = entity_of_node(lhs->expr);
Entity *original_e = e;
Ast *name = unparen_expr(lhs->expr);
while (name->kind == Ast_SelectorExpr) {
name = name->SelectorExpr.expr;
e = entity_of_node(name);
}
if (e == nullptr) {
e = original_e;
}
gbString str = expr_to_string(lhs->expr);
if (e != nullptr && e->flags & EntityFlag_Param) {
ERROR_BLOCK();
if (e->flags & EntityFlag_Using) {
error(lhs->expr, "Cannot assign to '%s' which is from a 'using' procedure parameter", str);
} else {
error(lhs->expr, "Cannot assign to '%s' which is a procedure parameter", str);
}
error_line("\tSuggestion: Did you mean to pass '%.*s' by pointer?\n", LIT(e->token.string));
show_error_on_line(e->token.pos, token_pos_end(e->token));
} else {
ERROR_BLOCK();
error(lhs->expr, "Cannot assign to '%s'", str);
if (e && e->flags & EntityFlag_ForValue) {
isize offset = show_error_on_line(e->token.pos, token_pos_end(e->token), "Suggestion:");
if (offset < 0) {
if (is_type_map(e->type)) {
error_line("\tSuggestion: Did you mean? 'for key, &%.*s in ...'\n", LIT(e->token.string));
} else {
error_line("\tSuggestion: Did you mean? 'for &%.*s in ...'\n", LIT(e->token.string));
}
} else {
error_line("\t");
for (isize i = 0; i < offset-1; i++) {
error_line(" ");
}
error_line("'%.*s' is immutable, declare it as '&%.*s' to make it mutable\n", LIT(e->token.string), LIT(e->token.string));
}
} else if (e && e->flags & EntityFlag_SwitchValue) {
isize offset = show_error_on_line(e->token.pos, token_pos_end(e->token), "Suggestion:");
if (offset < 0) {
error_line("\tSuggestion: Did you mean? 'switch &%.*s in ...'\n", LIT(e->token.string));
} else {
error_line("\t");
for (isize i = 0; i < offset-1; i++) {
error_line(" ");
}
error_line("'%.*s' is immutable, declare it as '&%.*s' to make it mutable\n", LIT(e->token.string), LIT(e->token.string));
}
}
}
gb_string_free(str);
@@ -2355,14 +2398,14 @@ gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) {
unsafe_return_error(o, "the address of a compound literal");
} else if (x->kind == Ast_IndexExpr) {
Entity *f = entity_of_node(x->IndexExpr.expr);
if (is_type_array_like(f->type) || is_type_matrix(f->type)) {
if (f && (is_type_array_like(f->type) || is_type_matrix(f->type))) {
if (is_entity_local_variable(f)) {
unsafe_return_error(o, "the address of an indexed variable", f->type);
}
}
} else if (x->kind == Ast_MatrixIndexExpr) {
Entity *f = entity_of_node(x->MatrixIndexExpr.expr);
if (is_type_matrix(f->type) && is_entity_local_variable(f)) {
if (f && (is_type_matrix(f->type) && is_entity_local_variable(f))) {
unsafe_return_error(o, "the address of an indexed variable", f->type);
}
}
+76 -16
View File
@@ -29,10 +29,11 @@ gb_internal void populate_using_array_index(CheckerContext *ctx, Ast *node, AstF
}
}
gb_internal void populate_using_entity_scope(CheckerContext *ctx, Ast *node, AstField *field, Type *t) {
gb_internal void populate_using_entity_scope(CheckerContext *ctx, Ast *node, AstField *field, Type *t, isize level) {
if (t == nullptr) {
return;
}
Type *original_type = t;
t = base_type(type_deref(t));
gbString str = nullptr;
defer (gb_string_free(str));
@@ -46,16 +47,18 @@ gb_internal void populate_using_entity_scope(CheckerContext *ctx, Ast *node, Ast
String name = f->token.string;
Entity *e = scope_lookup_current(ctx->scope, name);
if (e != nullptr && name != "_") {
gbString ot = type_to_string(original_type);
// TODO(bill): Better type error
if (str != nullptr) {
error(e->token, "'%.*s' is already declared in '%s'", LIT(name), str);
error(e->token, "'%.*s' is already declared in '%s', through 'using' from '%s'", LIT(name), str, ot);
} else {
error(e->token, "'%.*s' is already declared", LIT(name));
error(e->token, "'%.*s' is already declared, through 'using' from '%s'", LIT(name), ot);
}
gb_string_free(ot);
} else {
add_entity(ctx, ctx->scope, nullptr, f);
if (f->flags & EntityFlag_Using) {
populate_using_entity_scope(ctx, node, field, f->type);
populate_using_entity_scope(ctx, node, field, f->type, level+1);
}
}
}
@@ -200,7 +203,7 @@ gb_internal void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entit
continue;
}
populate_using_entity_scope(ctx, node, p, type);
populate_using_entity_scope(ctx, node, p, type, 1);
}
if (is_subtype && p->names.count > 0) {
@@ -952,13 +955,18 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type,
GB_ASSERT(is_type_bit_field(bit_field_type));
Type *backing_type = check_type(ctx, bf->backing_type);
if (backing_type == nullptr || !is_valid_bit_field_backing_type(backing_type)) {
error(node, "Backing type for a bit_field must be an integer or an array of an integer");
bit_field_type->BitField.backing_type = backing_type ? backing_type : t_u8;
bit_field_type->BitField.scope = ctx->scope;
if (backing_type == nullptr) {
error(bf->backing_type, "Backing type for a bit_field must be an integer or an array of an integer");
return;
}
if (!is_valid_bit_field_backing_type(backing_type)) {
error(bf->backing_type, "Backing type for a bit_field must be an integer or an array of an integer");
return;
}
bit_field_type->BitField.backing_type = backing_type;
bit_field_type->BitField.scope = ctx->scope;
auto fields = array_make<Entity *>(permanent_allocator(), 0, bf->fields.count);
auto bit_sizes = array_make<u8> (permanent_allocator(), 0, bf->fields.count);
@@ -1093,6 +1101,45 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type,
gb_string_free(s);
}
enum EndianKind {
Endian_Unknown,
Endian_Native,
Endian_Little,
Endian_Big,
};
auto const &determine_endian_kind = [](Type *type) -> EndianKind {
if (is_type_boolean(type)) {
// NOTE(bill): it doesn't matter, and when it does,
// that api is absolutely stupid
return Endian_Unknown;
} else if (is_type_endian_specific(type)) {
if (is_type_endian_little(type)) {
return Endian_Little;
} else {
return Endian_Big;
}
}
return Endian_Native;
};
EndianKind backing_type_endian_kind = determine_endian_kind(core_array_type(backing_type));
EndianKind endian_kind = Endian_Unknown;
for (Entity *f : fields) {
EndianKind field_kind = determine_endian_kind(f->type);
if (field_kind && backing_type_endian_kind != field_kind) {
error(f->token, "All 'bit_field' field types must match the same endian kind as the backing type, i.e. all native, all little, or all big");
}
if (endian_kind == Endian_Unknown) {
endian_kind = field_kind;
} else if (field_kind && endian_kind != field_kind) {
error(f->token, "All 'bit_field' field types must be of the same endian variety, i.e. all native, all little, or all big");
}
}
if (bit_sizes.count > 0 && is_type_integer(backing_type)) {
bool all_booleans = is_type_boolean(fields[0]->type);
bool all_ones = bit_sizes[0] == 1;
@@ -2495,18 +2542,16 @@ gb_internal Type *get_map_cell_type(Type *type) {
return s;
}
gb_internal void init_map_internal_types(Type *type) {
gb_internal void init_map_internal_debug_types(Type *type) {
GB_ASSERT(type->kind == Type_Map);
GB_ASSERT(t_allocator != nullptr);
if (type->Map.lookup_result_type != nullptr) return;
if (type->Map.debug_metadata_type != nullptr) return;
Type *key = type->Map.key;
Type *value = type->Map.value;
GB_ASSERT(key != nullptr);
GB_ASSERT(value != nullptr);
Type *key_cell = get_map_cell_type(key);
Type *value_cell = get_map_cell_type(value);
@@ -2541,6 +2586,18 @@ gb_internal void init_map_internal_types(Type *type) {
gb_unused(type_size_of(debug_type));
type->Map.debug_metadata_type = debug_type;
}
gb_internal void init_map_internal_types(Type *type) {
GB_ASSERT(type->kind == Type_Map);
GB_ASSERT(t_allocator != nullptr);
if (type->Map.lookup_result_type != nullptr) return;
Type *key = type->Map.key;
Type *value = type->Map.value;
GB_ASSERT(key != nullptr);
GB_ASSERT(value != nullptr);
type->Map.lookup_result_type = make_optional_ok_type(value);
}
@@ -2613,8 +2670,6 @@ gb_internal void check_map_type(CheckerContext *ctx, Type *type, Ast *node) {
init_core_map_type(ctx->checker);
init_map_internal_types(type);
// error(node, "'map' types are not yet implemented");
}
gb_internal void check_matrix_type(CheckerContext *ctx, Type **type, Ast *node) {
@@ -3233,6 +3288,11 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
Type *elem = t_invalid;
Operand o = {};
if (unparen_expr(pt->type) == nullptr) {
error(e, "Invalid pointer type");
return false;
}
check_expr_or_type(&c, &o, pt->type);
if (o.mode != Addressing_Invalid && o.mode != Addressing_Type) {
if (o.mode == Addressing_Variable) {
+9 -4
View File
@@ -703,11 +703,11 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) {
array_add(&vetted_entities, ve_unused);
} else if (is_shadowed) {
array_add(&vetted_entities, ve_shadowed);
} else if (e->kind == Entity_Variable && (e->flags & (EntityFlag_Param|EntityFlag_Using)) == 0) {
} else if (e->kind == Entity_Variable && (e->flags & (EntityFlag_Param|EntityFlag_Using|EntityFlag_Static)) == 0 && !e->Variable.is_global) {
i64 sz = type_size_of(e->type);
// TODO(bill): When is a good size warn?
// Is 128 KiB good enough?
if (sz >= 1ll<<17) {
// Is >256 KiB good enough?
if (sz > 1ll<<18) {
gbString type_str = type_to_string(e->type);
warning(e->token, "Declaration of '%.*s' may cause a stack overflow due to its type '%s' having a size of %lld bytes", LIT(e->token.string), type_str, cast(long long)sz);
gb_string_free(type_str);
@@ -728,7 +728,10 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) {
} else if (vet_flags) {
switch (ve.kind) {
case VettedEntity_Unused:
if (vet_flags & VetFlag_Unused) {
if (e->kind == Entity_Variable && (vet_flags & VetFlag_UnusedVariables) != 0) {
error(e->token, "'%.*s' declared but not used", LIT(name));
}
if ((e->kind == Entity_ImportName || e->kind == Entity_LibraryName) && (vet_flags & VetFlag_UnusedImports) != 0) {
error(e->token, "'%.*s' declared but not used", LIT(name));
}
break;
@@ -1109,6 +1112,8 @@ gb_internal void init_universal(void) {
add_global_bool_constant("ODIN_DEBUG", bc->ODIN_DEBUG);
add_global_bool_constant("ODIN_DISABLE_ASSERT", bc->ODIN_DISABLE_ASSERT);
add_global_bool_constant("ODIN_DEFAULT_TO_NIL_ALLOCATOR", bc->ODIN_DEFAULT_TO_NIL_ALLOCATOR);
add_global_bool_constant("ODIN_NO_BOUNDS_CHECK", build_context.no_bounds_check);
add_global_bool_constant("ODIN_NO_TYPE_ASSERT", build_context.no_type_assert);
add_global_bool_constant("ODIN_DEFAULT_TO_PANIC_ALLOCATOR", bc->ODIN_DEFAULT_TO_PANIC_ALLOCATOR);
add_global_bool_constant("ODIN_NO_DYNAMIC_LITERALS", bc->no_dynamic_literals);
add_global_bool_constant("ODIN_NO_CRT", bc->no_crt);
+4 -1
View File
@@ -563,4 +563,7 @@ gb_internal void init_mem_allocator(Checker *c);
gb_internal void add_untyped_expressions(CheckerInfo *cinfo, UntypedExprInfoMap *untyped);
gb_internal GenTypesData *ensure_polymorphic_record_entity_has_gen_types(CheckerContext *ctx, Type *original_type);
gb_internal GenTypesData *ensure_polymorphic_record_entity_has_gen_types(CheckerContext *ctx, Type *original_type);
gb_internal void init_map_internal_types(Type *type);
+4
View File
@@ -163,6 +163,10 @@ gb_internal void platform_virtual_memory_protect(void *memory, isize size);
GB_ASSERT(is_protected);
}
#else
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
#define MAP_ANONYMOUS MAP_ANON
#endif
gb_internal void platform_virtual_memory_init(void) {
global_platform_memory_block_sentinel.prev = &global_platform_memory_block_sentinel;
global_platform_memory_block_sentinel.next = &global_platform_memory_block_sentinel;
+1 -1
View File
@@ -496,7 +496,7 @@ gb_internal bool is_entity_local_variable(Entity *e) {
if (e->scope == nullptr) {
return true;
}
if (e->flags & (EntityFlag_ForValue|EntityFlag_SwitchValue)) {
if (e->flags & (EntityFlag_ForValue|EntityFlag_SwitchValue|EntityFlag_Static)) {
return false;
}
+134 -76
View File
@@ -7,7 +7,8 @@ struct ErrorValue {
ErrorValueKind kind;
TokenPos pos;
TokenPos end;
Array<String> msgs;
Array<u8> msg;
bool seen_newline;
};
struct ErrorCollector {
@@ -30,19 +31,21 @@ gb_global ErrorCollector global_error_collector;
gb_internal void push_error_value(TokenPos const &pos, ErrorValueKind kind = ErrorValue_Error) {
GB_ASSERT_MSG(global_error_collector.curr_error_value_set.load() == false, "Possible race condition in error handling system, please report this with an issue");
ErrorValue ev = {kind, pos};
ev.msgs.allocator = heap_allocator();
ev.msg.allocator = heap_allocator();
global_error_collector.curr_error_value = ev;
global_error_collector.curr_error_value_set.store(true);
}
gb_internal void pop_error_value(void) {
mutex_lock(&global_error_collector.mutex);
if (global_error_collector.curr_error_value_set.load()) {
array_add(&global_error_collector.error_values, global_error_collector.curr_error_value);
global_error_collector.curr_error_value = {};
global_error_collector.curr_error_value_set.store(false);
}
mutex_unlock(&global_error_collector.mutex);
}
@@ -84,6 +87,7 @@ gb_internal bool set_file_path_string(i32 index, String const &path) {
bool ok = false;
GB_ASSERT(index >= 0);
mutex_lock(&global_error_collector.path_mutex);
mutex_lock(&global_files_mutex);
if (index >= global_file_path_strings.count) {
array_resize(&global_file_path_strings, index+1);
@@ -94,6 +98,7 @@ gb_internal bool set_file_path_string(i32 index, String const &path) {
ok = true;
}
mutex_unlock(&global_files_mutex);
mutex_unlock(&global_error_collector.path_mutex);
return ok;
}
@@ -102,6 +107,7 @@ gb_internal bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) {
bool ok = false;
GB_ASSERT(index >= 0);
mutex_lock(&global_error_collector.path_mutex);
mutex_lock(&global_files_mutex);
if (index >= global_files.count) {
array_resize(&global_files, index+1);
@@ -111,7 +117,7 @@ gb_internal bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) {
global_files[index] = file;
ok = true;
}
mutex_unlock(&global_files_mutex);
mutex_unlock(&global_error_collector.path_mutex);
return ok;
}
@@ -119,12 +125,14 @@ gb_internal bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) {
gb_internal String get_file_path_string(i32 index) {
GB_ASSERT(index >= 0);
mutex_lock(&global_error_collector.path_mutex);
mutex_lock(&global_files_mutex);
String path = {};
if (index < global_file_path_strings.count) {
path = global_file_path_strings[index];
}
mutex_unlock(&global_files_mutex);
mutex_unlock(&global_error_collector.path_mutex);
return path;
}
@@ -132,12 +140,14 @@ gb_internal String get_file_path_string(i32 index) {
gb_internal AstFile *thread_safe_get_ast_file_from_id(i32 index) {
GB_ASSERT(index >= 0);
mutex_lock(&global_error_collector.path_mutex);
mutex_lock(&global_files_mutex);
AstFile *file = nullptr;
if (index < global_files.count) {
file = global_files[index];
}
mutex_unlock(&global_files_mutex);
mutex_unlock(&global_error_collector.path_mutex);
return file;
}
@@ -173,9 +183,18 @@ gb_internal ERROR_OUT_PROC(default_error_out_va) {
isize n = len-1;
if (n > 0) {
String msg = copy_string(permanent_allocator(), {(u8 *)buf, n});
ErrorValue *ev = get_error_value();
array_add(&ev->msgs, msg);
if (terse_errors()) {
for (isize i = 0; i < n && !ev->seen_newline; i++) {
u8 c = cast(u8)buf[i];
if (c == '\n') {
ev->seen_newline = true;
}
array_add(&ev->msg, c);
}
} else {
array_add_elems(&ev->msg, (u8 *)buf, n);
}
}
}
@@ -247,10 +266,10 @@ gb_internal void terminal_reset_colours(void) {
}
gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) {
gb_internal isize show_error_on_line(TokenPos const &pos, TokenPos end, char const *prefix=nullptr) {
get_error_value()->end = end;
if (!show_error_line()) {
return false;
return -1;
}
i32 offset = 0;
@@ -270,6 +289,10 @@ gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) {
MAX_LINE_LENGTH_PADDED = MAX_LINE_LENGTH-MAX_TAB_WIDTH-ELLIPSIS_PADDING,
};
if (prefix) {
error_out("\t%s\n\n", prefix);
}
error_out("\t");
terminal_set_colours(TerminalStyle_Bold, TerminalColour_White);
@@ -281,10 +304,11 @@ gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) {
if (line_len > MAX_LINE_LENGTH_PADDED) {
i32 left = MAX_TAB_WIDTH;
if (offset > 0) {
line_text += offset-left;
line_len -= offset-left;
offset = left+MAX_TAB_WIDTH/2;
i32 diff = gb_max(offset-left, 0);
if (diff > 0) {
line_text += diff;
line_len -= diff;
offset = left + ELLIPSIS_PADDING/2;
}
if (line_len > MAX_LINE_LENGTH_PADDED) {
line_len = MAX_LINE_LENGTH_PADDED;
@@ -293,7 +317,7 @@ gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) {
squiggle_extra = 1;
}
}
if (offset > 0) {
if (diff > 0) {
error_out("... %.*s ...", cast(i32)line_len, line_text);
} else {
error_out("%.*s ...", cast(i32)line_len, line_text);
@@ -328,9 +352,9 @@ gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) {
terminal_reset_colours();
error_out("\n");
return true;
return offset;
}
return false;
return -1;
}
gb_internal void error_out_empty(void) {
@@ -367,7 +391,11 @@ gb_internal void error_va(TokenPos const &pos, TokenPos end, char const *fmt, va
error_out("\n");
} else if (global_error_collector.prev != pos) {
global_error_collector.prev = pos;
error_out_pos(pos);
if (json_errors()) {
error_out_empty();
} else {
error_out_pos(pos);
}
if (has_ansi_terminal_colours()) {
error_out_coloured("Error: ", TerminalStyle_Normal, TerminalColour_Red);
}
@@ -400,7 +428,11 @@ gb_internal void warning_va(TokenPos const &pos, TokenPos end, char const *fmt,
error_out("\n");
} else if (global_error_collector.prev != pos) {
global_error_collector.prev = pos;
error_out_pos(pos);
if (json_errors()) {
error_out_empty();
} else {
error_out_pos(pos);
}
error_out_coloured("Warning: ", TerminalStyle_Normal, TerminalColour_Yellow);
error_out_va(fmt, va);
error_out("\n");
@@ -433,7 +465,11 @@ gb_internal void error_no_newline_va(TokenPos const &pos, char const *fmt, va_li
error_out_va(fmt, va);
} else if (global_error_collector.prev != pos) {
global_error_collector.prev = pos;
error_out_pos(pos);
if (json_errors()) {
error_out_empty();
} else {
error_out_pos(pos);
}
if (has_ansi_terminal_colours()) {
error_out_coloured("Error: ", TerminalStyle_Normal, TerminalColour_Red);
}
@@ -458,7 +494,11 @@ gb_internal void syntax_error_va(TokenPos const &pos, TokenPos end, char const *
// NOTE(bill): Duplicate error, skip it
if (global_error_collector.prev != pos) {
global_error_collector.prev = pos;
error_out_pos(pos);
if (json_errors()) {
error_out_empty();
} else {
error_out_pos(pos);
}
error_out_coloured("Syntax Error: ", TerminalStyle_Normal, TerminalColour_Red);
error_out_va(fmt, va);
error_out("\n");
@@ -492,7 +532,11 @@ gb_internal void syntax_error_with_verbose_va(TokenPos const &pos, TokenPos end,
error_out("\n");
} else if (global_error_collector.prev != pos) {
global_error_collector.prev = pos;
error_out_pos(pos);
if (json_errors()) {
error_out_empty();
} else {
error_out_pos(pos);
}
if (has_ansi_terminal_colours()) {
error_out_coloured("Syntax_Error: ", TerminalStyle_Normal, TerminalColour_Red);
}
@@ -521,7 +565,11 @@ gb_internal void syntax_warning_va(TokenPos const &pos, TokenPos end, char const
// NOTE(bill): Duplicate error, skip it
if (global_error_collector.prev != pos) {
global_error_collector.prev = pos;
error_out_pos(pos);
if (json_errors()) {
error_out_empty();
} else {
error_out_pos(pos);
}
error_out_coloured("Syntax Warning: ", TerminalStyle_Normal, TerminalColour_Yellow);
error_out_va(fmt, va);
error_out("\n");
@@ -633,109 +681,119 @@ gb_internal int error_value_cmp(void const *a, void const *b) {
}
gb_internal void print_all_errors(void) {
auto const &escape_char = [](gbFile *f, u8 c) {
auto const &escape_char = [](gbString res, u8 c) -> gbString {
switch (c) {
case '\n': gb_file_write(f, "\\n", 2); break;
case '"': gb_file_write(f, "\\\"", 2); break;
case '\\': gb_file_write(f, "\\\\", 2); break;
case '\b': gb_file_write(f, "\\b", 2); break;
case '\f': gb_file_write(f, "\\f", 2); break;
case '\r': gb_file_write(f, "\\r", 2); break;
case '\t': gb_file_write(f, "\\t", 2); break;
case '\n': res = gb_string_append_length(res, "\\n", 2); break;
case '"': res = gb_string_append_length(res, "\\\"", 2); break;
case '\\': res = gb_string_append_length(res, "\\\\", 2); break;
case '\b': res = gb_string_append_length(res, "\\b", 2); break;
case '\f': res = gb_string_append_length(res, "\\f", 2); break;
case '\r': res = gb_string_append_length(res, "\\r", 2); break;
case '\t': res = gb_string_append_length(res, "\\t", 2); break;
default:
if ('\x00' <= c && c <= '\x1f') {
gb_fprintf(f, "\\u%04x", c);
res = gb_string_append_fmt(res, "\\u%04x", c);
} else {
gb_file_write(f, &c, 1);
res = gb_string_append_length(res, &c, 1);
}
break;
}
return res;
};
GB_ASSERT(any_errors() || any_warnings());
gbFile *f = gb_file_get_standard(gbFileStandard_Error);
array_sort(global_error_collector.error_values, error_value_cmp);
gbString res = gb_string_make(heap_allocator(), "");
defer (gb_string_free(res));
if (json_errors()) {
gb_fprintf(f, "{\n");
gb_fprintf(f, "\t\"error_count\": %td,\n", global_error_collector.error_values.count);
gb_fprintf(f, "\t\"errors\": [\n");
res = gb_string_append_fmt(res, "{\n");
res = gb_string_append_fmt(res, "\t\"error_count\": %td,\n", global_error_collector.error_values.count);
res = gb_string_append_fmt(res, "\t\"errors\": [\n");
for_array(i, global_error_collector.error_values) {
ErrorValue ev = global_error_collector.error_values[i];
gb_fprintf(f, "\t\t{\n");
res = gb_string_append_fmt(res, "\t\t{\n");
gb_fprintf(f, "\t\t\t\"type\": \"");
res = gb_string_append_fmt(res, "\t\t\t\"type\": \"");
if (ev.kind == ErrorValue_Warning) {
gb_fprintf(f, "warning");
res = gb_string_append_fmt(res, "warning");
} else {
gb_fprintf(f, "error");
res = gb_string_append_fmt(res, "error");
}
gb_fprintf(f, "\",\n");
res = gb_string_append_fmt(res, "\",\n");
gb_fprintf(f, "\t\t\t\"pos\": {\n");
res = gb_string_append_fmt(res, "\t\t\t\"pos\": {\n");
if (ev.pos.file_id) {
gb_fprintf(f, "\t\t\t\t\"file\": \"");
res = gb_string_append_fmt(res, "\t\t\t\t\"file\": \"");
String file = get_file_path_string(ev.pos.file_id);
for (isize k = 0; k < file.len; k++) {
escape_char(f, file.text[k]);
res = escape_char(res, file.text[k]);
}
gb_fprintf(f, "\",\n");
gb_fprintf(f, "\t\t\t\t\"offset\": %d,\n", ev.pos.offset);
gb_fprintf(f, "\t\t\t\t\"line\": %d,\n", ev.pos.line);
gb_fprintf(f, "\t\t\t\t\"column\": %d,\n", ev.pos.column);
res = gb_string_append_fmt(res, "\",\n");
res = gb_string_append_fmt(res, "\t\t\t\t\"offset\": %d,\n", ev.pos.offset);
res = gb_string_append_fmt(res, "\t\t\t\t\"line\": %d,\n", ev.pos.line);
res = gb_string_append_fmt(res, "\t\t\t\t\"column\": %d,\n", ev.pos.column);
i32 end_column = gb_max(ev.end.column, ev.pos.column);
gb_fprintf(f, "\t\t\t\t\"end_column\": %d\n", end_column);
gb_fprintf(f, "\t\t\t},\n");
res = gb_string_append_fmt(res, "\t\t\t\t\"end_column\": %d\n", end_column);
res = gb_string_append_fmt(res, "\t\t\t},\n");
}
gb_fprintf(f, "\t\t\t\"msgs\": [\n");
res = gb_string_append_fmt(res, "\t\t\t\"msgs\": [\n");
if (ev.msgs.count > 1) {
gb_fprintf(f, "\t\t\t\t\"");
auto lines = split_lines_from_array(ev.msg, heap_allocator());
defer (array_free(&lines));
for (isize j = 1; j < ev.msgs.count; j++) {
String msg = ev.msgs[j];
for (isize k = 0; k < msg.len; k++) {
u8 c = msg.text[k];
if (c == '\n') {
if (k+1 == msg.len && j+1 == ev.msgs.count) {
// don't do the last one
} else {
gb_fprintf(f, "\",\n");
gb_fprintf(f, "\t\t\t\t\"");
}
} else {
escape_char(f, c);
}
if (lines.count > 0) {
res = gb_string_append_fmt(res, "\t\t\t\t\"");
for (isize j = 0; j < lines.count; j++) {
String line = lines[j];
for (isize k = 0; k < line.len; k++) {
u8 c = line.text[k];
res = escape_char(res, c);
}
if (j+1 < lines.count) {
res = gb_string_append_fmt(res, "\",\n");
res = gb_string_append_fmt(res, "\t\t\t\t\"");
}
}
gb_fprintf(f, "\"\n");
res = gb_string_append_fmt(res, "\"\n");
}
gb_fprintf(f, "\t\t\t]\n");
gb_fprintf(f, "\t\t}");
res = gb_string_append_fmt(res, "\t\t\t]\n");
res = gb_string_append_fmt(res, "\t\t}");
if (i+1 != global_error_collector.error_values.count) {
gb_fprintf(f, ",");
res = gb_string_append_fmt(res, ",");
}
gb_fprintf(f, "\n");
res = gb_string_append_fmt(res, "\n");
}
gb_fprintf(f, "\t]\n");
gb_fprintf(f, "}\n");
res = gb_string_append_fmt(res, "\t]\n");
res = gb_string_append_fmt(res, "}\n");
} else {
for_array(i, global_error_collector.error_values) {
ErrorValue ev = global_error_collector.error_values[i];
for (isize j = 0; j < ev.msgs.count; j++) {
String msg = ev.msgs[j];
gb_file_write(f, msg.text, msg.len);
if (terse_errors() && string_contains_char(msg, '\n')) {
String_Iterator it = {{ev.msg.data, ev.msg.count}, 0};
for (isize line_idx = 0; /**/; line_idx++) {
String line = string_split_iterator(&it, '\n');
if (line.len == 0) {
break;
}
line = string_trim_trailing_whitespace(line);
res = gb_string_append_length(res, line.text, line.len);
res = gb_string_append_length(res, " \n", 2);
if (line_idx == 0 && terse_errors()) {
break;
}
}
}
}
gbFile *f = gb_file_get_standard(gbFileStandard_Error);
gb_file_write(f, res, gb_string_length(res));
}
+3 -2
View File
@@ -1131,8 +1131,9 @@ namespace lbAbiArm64 {
if (size <= 16) {
LLVMTypeRef cast_type = nullptr;
GB_ASSERT(size > 0);
if (size <= 8) {
if (size == 0) {
cast_type = LLVMStructTypeInContext(c, nullptr, 0, false);
} else if (size <= 8) {
cast_type = LLVMIntTypeInContext(c, cast(unsigned)(size*8));
} else {
unsigned count = cast(unsigned)((size+7)/8);
+1 -1
View File
@@ -2659,7 +2659,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
LLVMSetInitializer(g, LLVMConstNull(internal_llvm_type));
LLVMSetLinkage(g, USE_SEPARATE_MODULES ? LLVMExternalLinkage : LLVMInternalLinkage);
LLVMSetUnnamedAddress(g, LLVMGlobalUnnamedAddr);
LLVMSetGlobalConstant(g, /*true*/false);
LLVMSetGlobalConstant(g, true);
lbValue value = {};
value.value = g;
-1
View File
@@ -122,7 +122,6 @@ struct lbAddr {
} swizzle_large;
struct {
Type *type;
i64 index;
i64 bit_offset;
i64 bit_size;
} bitfield;
+4 -10
View File
@@ -739,6 +739,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
}
case Type_Map: {
init_map_internal_debug_types(type);
Type *bt = base_type(type->Map.debug_metadata_type);
GB_ASSERT(bt->kind == Type_Struct);
@@ -945,6 +946,7 @@ gb_internal LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) {
}
case Type_Map: {
init_map_internal_debug_types(bt);
bt = base_type(bt->Map.debug_metadata_type);
GB_ASSERT(bt->kind == Type_Struct);
return lb_debug_struct(m, type, bt, name, scope, file, line);
@@ -1025,7 +1027,7 @@ gb_internal void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, T
LLVMDIBuilderInsertDeclareAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block);
}
gb_internal void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, Token const &token, unsigned arg_number, lbBlock *block, lbArgKind arg_kind) {
gb_internal void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, Token const &token, unsigned arg_number, lbBlock *block) {
if (p->debug_info == nullptr) {
return;
}
@@ -1086,15 +1088,7 @@ gb_internal void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, T
// NOTE(bill, 2022-02-01): For parameter values, you must insert them at the end of the decl block
// The reason is that if the parameter is at index 0 and a pointer, there is not such things as an
// instruction "before" it.
switch (arg_kind) {
case lbArg_Direct:
LLVMDIBuilderInsertDbgValueAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block->block);
break;
case lbArg_Indirect:
LLVMDIBuilderInsertDeclareAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block->block);
break;
}
LLVMDIBuilderInsertDeclareAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block->block);
}
+211 -22
View File
@@ -2138,14 +2138,45 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
if (is_type_array_like(dst)) {
Type *elem = base_array_type(dst);
lbValue e = lb_emit_conv(p, value, elem);
// NOTE(bill): Doesn't need to be zero because it will be initialized in the loops
lbAddr v = lb_add_local_generated(p, t, false);
isize index_count = cast(isize)get_array_type_count(dst);
for (isize i = 0; i < index_count; i++) {
lbValue elem = lb_emit_array_epi(p, v.addr, i);
isize inlineable = type_size_of(dst) <= build_context.max_simd_align;
lbValue e = lb_emit_conv(p, value, elem);
if (inlineable && lb_is_const(e)) {
lbAddr v = {};
if (e.value) {
TEMPORARY_ALLOCATOR_GUARD();
LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, index_count);
for (isize i = 0; i < index_count; i++) {
values[i] = e.value;
}
lbValue array_const_value = {};
array_const_value.type = t;
array_const_value.value = LLVMConstArray(lb_type(m, elem), values, cast(unsigned)index_count);
v = lb_add_global_generated(m, t, array_const_value);
} else {
v = lb_add_global_generated(m, t);
}
lb_make_global_private_const(v);
return lb_addr_load(p, v);
}
// NOTE(bill): Doesn't need to be zero because it will be initialized in the loops
lbAddr v = lb_add_local_generated(p, t, false);
if (!inlineable) {
auto loop_data = lb_loop_start(p, index_count, t_int);
lbValue elem = lb_emit_array_ep(p, v.addr, loop_data.idx);
lb_emit_store(p, elem, e);
lb_loop_end(p, loop_data);
} else {
for (isize i = 0; i < index_count; i++) {
lbValue elem = lb_emit_array_epi(p, v.addr, i);
lb_emit_store(p, elem, e);
}
}
return lb_addr_load(p, v);
}
@@ -3085,7 +3116,7 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
Type *dst_type = type;
if ((p->state_flags & StateFlag_no_type_assert) == 0) {
if (!build_context.no_type_assert && (p->state_flags & StateFlag_no_type_assert) == 0) {
lbValue src_tag = {};
lbValue dst_tag = {};
if (is_type_union_maybe_pointer(src_type)) {
@@ -3125,7 +3156,7 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
v = lb_emit_load(p, v);
}
lbValue data_ptr = lb_emit_struct_ev(p, v, 0);
if ((p->state_flags & StateFlag_no_type_assert) == 0) {
if (!build_context.no_type_assert && (p->state_flags & StateFlag_no_type_assert) == 0) {
GB_ASSERT(!build_context.no_rtti);
lbValue any_id = lb_emit_struct_ev(p, v, 1);
@@ -4265,7 +4296,19 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
switch (bt->kind) {
default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break;
case Type_BitField:
case Type_BitField: {
TEMPORARY_ALLOCATOR_GUARD();
// Type *backing_type = core_type(bt->BitField.backing_type);
struct FieldData {
Type *field_type;
u64 bit_offset;
u64 bit_size;
};
auto values = array_make<lbValue>(temporary_allocator(), 0, cl->elems.count);
auto fields = array_make<FieldData>(temporary_allocator(), 0, cl->elems.count);
for (Ast *elem : cl->elems) {
ast_node(fv, FieldValue, elem);
String name = fv->field->Ident.token.string;
@@ -4276,26 +4319,172 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
GB_ASSERT(sel.entity != nullptr);
i64 index = sel.index[0];
i64 bit_offset = 0;
i64 bit_size = -1;
for_array(i, bt->BitField.fields) {
Entity *f = bt->BitField.fields[i];
if (f == sel.entity) {
bit_offset = bt->BitField.bit_offsets[i];
bit_size = bt->BitField.bit_sizes[i];
break;
}
}
Entity *f = bt->BitField.fields[index];
GB_ASSERT(f == sel.entity);
i64 bit_offset = bt->BitField.bit_offsets[index];
i64 bit_size = bt->BitField.bit_sizes[index];
GB_ASSERT(bit_size > 0);
Type *field_type = sel.entity->type;
lbValue field_expr = lb_build_expr(p, fv->value);
field_expr = lb_emit_conv(p, field_expr, field_type);
lbAddr field_addr = lb_addr_bit_field(v.addr, field_type, index, bit_offset, bit_size);
lb_addr_store(p, field_addr, field_expr);
array_add(&values, field_expr);
array_add(&fields, FieldData{field_type, cast(u64)bit_offset, cast(u64)bit_size});
}
// NOTE(bill): inline insertion sort should be good enough, right?
for (isize i = 1; i < values.count; i++) {
for (isize j = i;
j > 0 && fields[i].bit_offset < fields[j].bit_offset;
j--) {
auto vtmp = values[j];
values[j] = values[j-1];
values[j-1] = vtmp;
auto ftmp = fields[j];
fields[j] = fields[j-1];
fields[j-1] = ftmp;
}
}
bool any_fields_different_endian = false;
for (auto const &f : fields) {
if (is_type_different_to_arch_endianness(f.field_type)) {
// NOTE(bill): Just be slow for this, to be correct
any_fields_different_endian = true;
break;
}
}
if (!any_fields_different_endian &&
fields.count == bt->BitField.fields.count) {
// SINGLE INTEGER BACKING ONLY
Type *backing_type = core_type(bt->BitField.backing_type);
GB_ASSERT(is_type_integer(backing_type) ||
(is_type_array(backing_type) && is_type_integer(backing_type->Array.elem)));
// NOTE(bill): all fields are present
// this means no masking is necessary since on write, the bits will be overridden
lbValue dst_byte_ptr = lb_emit_conv(p, v.addr, t_u8_ptr);
u64 total_bit_size = cast(u64)(8*type_size_of(bt));
if (is_type_integer(backing_type)) {
LLVMTypeRef lit = lb_type(p->module, backing_type);
LLVMValueRef res = LLVMConstInt(lit, 0, false);
for (isize i = 0; i < fields.count; i++) {
auto const &f = fields[i];
LLVMValueRef mask = LLVMConstInt(lit, 1, false);
mask = LLVMConstShl(mask, LLVMConstInt(lit, f.bit_size, false));
mask = LLVMConstSub(mask, LLVMConstInt(lit, 1, false));
LLVMValueRef elem = values[i].value;
elem = LLVMBuildZExt(p->builder, elem, lit, "");
elem = LLVMBuildAnd(p->builder, elem, mask, "");
elem = LLVMBuildShl(p->builder, elem, LLVMConstInt(lit, f.bit_offset, false), "");
res = LLVMBuildOr(p->builder, res, elem, "");
}
LLVMBuildStore(p->builder, res, v.addr.value);
} else if (is_type_array(backing_type)) {
// ARRAY OF INTEGER BACKING
i64 array_count = backing_type->Array.count;
LLVMTypeRef lit = lb_type(p->module, core_type(backing_type->Array.elem));
gb_unused(array_count);
gb_unused(lit);
LLVMValueRef *elems = gb_alloc_array(temporary_allocator(), LLVMValueRef, array_count);
for (i64 i = 0; i < array_count; i++) {
elems[i] = LLVMConstInt(lit, 0, false);
}
u64 elem_bit_size = cast(u64)(8*type_size_of(backing_type->Array.elem));
u64 curr_bit_offset = 0;
for (isize i = 0; i < fields.count; i++) {
auto const &f = fields[i];
LLVMValueRef val = values[i].value;
LLVMTypeRef vt = lb_type(p->module, values[i].type);
for (u64 bits_to_set = f.bit_size;
bits_to_set > 0;
/**/) {
i64 elem_idx = curr_bit_offset/elem_bit_size;
u64 elem_bit_offset = curr_bit_offset%elem_bit_size;
u64 mask_width = gb_min(bits_to_set, elem_bit_size-elem_bit_offset);
GB_ASSERT(mask_width > 0);
bits_to_set -= mask_width;
LLVMValueRef mask = LLVMConstInt(vt, 1, false);
mask = LLVMConstShl(mask, LLVMConstInt(vt, mask_width, false));
mask = LLVMConstSub(mask, LLVMConstInt(vt, 1, false));
LLVMValueRef to_set = LLVMBuildAnd(p->builder, val, mask, "");
if (elem_bit_offset != 0) {
to_set = LLVMBuildShl(p->builder, to_set, LLVMConstInt(vt, elem_bit_offset, false), "");
}
to_set = LLVMBuildTrunc(p->builder, to_set, lit, "");
if (LLVMIsNull(elems[elem_idx])) {
elems[elem_idx] = to_set; // don't even bother doing `0 | to_set`
} else {
elems[elem_idx] = LLVMBuildOr(p->builder, elems[elem_idx], to_set, "");
}
if (mask_width != 0) {
val = LLVMBuildLShr(p->builder, val, LLVMConstInt(vt, mask_width, false), "");
}
curr_bit_offset += mask_width;
}
GB_ASSERT(curr_bit_offset == f.bit_offset + f.bit_size);
}
for (i64 i = 0; i < array_count; i++) {
LLVMValueRef elem_ptr = LLVMBuildStructGEP2(p->builder, lb_type(p->module, backing_type), v.addr.value, cast(unsigned)i, "");
LLVMBuildStore(p->builder, elems[i], elem_ptr);
}
} else {
// SLOW STORAGE
for_array(i, fields) {
auto const &f = fields[i];
if ((f.bit_offset & 7) == 0) {
u64 unpacked_bit_size = cast(u64)(8*type_size_of(f.field_type));
u64 byte_size = (f.bit_size+7)/8;
if (f.bit_offset + unpacked_bit_size <= total_bit_size) {
byte_size = unpacked_bit_size/8;
}
lbValue dst = lb_emit_ptr_offset(p, dst_byte_ptr, lb_const_int(p->module, t_int, f.bit_offset/8));
lbValue src = lb_address_from_load_or_generate_local(p, values[i]);
lb_mem_copy_non_overlapping(p, dst, src, lb_const_int(p->module, t_uintptr, byte_size));
} else {
lbAddr dst = lb_addr_bit_field(v.addr, f.field_type, f.bit_offset, f.bit_size);
lb_addr_store(p, dst, values[i]);
}
}
}
} else {
// individual storing
for_array(i, values) {
auto const &f = fields[i];
lbAddr dst = lb_addr_bit_field(v.addr, f.field_type, f.bit_offset, f.bit_size);
lb_addr_store(p, dst, values[i]);
}
}
return v;
}
case Type_Struct: {
// TODO(bill): "constant" '#raw_union's are not initialized constantly at the moment.
@@ -4740,7 +4929,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
u8 bit_size = bf_type->BitField.bit_sizes[index];
i64 bit_offset = bf_type->BitField.bit_offsets[index];
return lb_addr_bit_field(ptr, f->type, index, bit_offset, bit_size);
return lb_addr_bit_field(ptr, f->type, bit_offset, bit_size);
}
{
+98 -29
View File
@@ -211,7 +211,7 @@ gb_internal void lb_loop_end(lbProcedure *p, lbLoopData const &data) {
gb_internal void lb_make_global_private_const(LLVMValueRef global_data) {
LLVMSetLinkage(global_data, LLVMPrivateLinkage);
LLVMSetLinkage(global_data, LLVMLinkerPrivateLinkage);
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
LLVMSetGlobalConstant(global_data, true);
}
@@ -450,14 +450,13 @@ gb_internal lbAddr lb_addr_swizzle_large(lbValue addr, Type *array_type, Slice<i
return v;
}
gb_internal lbAddr lb_addr_bit_field(lbValue addr, Type *type, i64 index, i64 bit_offset, i64 bit_size) {
gb_internal lbAddr lb_addr_bit_field(lbValue addr, Type *type, i64 bit_offset, i64 bit_size) {
GB_ASSERT(is_type_pointer(addr.type));
Type *mt = type_deref(addr.type);
GB_ASSERT_MSG(is_type_bit_field(mt), "%s", type_to_string(mt));
lbAddr v = {lbAddr_BitField, addr};
v.bitfield.type = type;
v.bitfield.index = index;
v.bitfield.bit_offset = bit_offset;
v.bitfield.bit_size = bit_size;
return v;
@@ -774,13 +773,40 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
if (addr.kind == lbAddr_BitField) {
lbValue dst = addr.addr;
if (is_type_endian_big(addr.bitfield.type)) {
i64 shift_amount = 8*type_size_of(value.type) - addr.bitfield.bit_size;
lbValue shifted_value = value;
shifted_value.value = LLVMBuildLShr(p->builder,
shifted_value.value,
LLVMConstInt(LLVMTypeOf(shifted_value.value), shift_amount, false), "");
auto args = array_make<lbValue>(temporary_allocator(), 4);
args[0] = dst;
args[1] = lb_address_from_load_or_generate_local(p, value);
args[2] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset);
args[3] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size);
lb_emit_runtime_call(p, "__write_bits", args);
lbValue src = lb_address_from_load_or_generate_local(p, shifted_value);
auto args = array_make<lbValue>(temporary_allocator(), 4);
args[0] = dst;
args[1] = src;
args[2] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset);
args[3] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size);
lb_emit_runtime_call(p, "__write_bits", args);
} else if ((addr.bitfield.bit_offset % 8) == 0 &&
(addr.bitfield.bit_size % 8) == 0) {
lbValue src = lb_address_from_load_or_generate_local(p, value);
lbValue byte_offset = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset/8);
lbValue byte_size = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size/8);
lbValue dst_offset = lb_emit_conv(p, dst, t_u8_ptr);
dst_offset = lb_emit_ptr_offset(p, dst_offset, byte_offset);
lb_mem_copy_non_overlapping(p, dst_offset, src, byte_size);
} else {
lbValue src = lb_address_from_load_or_generate_local(p, value);
auto args = array_make<lbValue>(temporary_allocator(), 4);
args[0] = dst;
args[1] = src;
args[2] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset);
args[3] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size);
lb_emit_runtime_call(p, "__write_bits", args);
}
return;
} else if (addr.kind == lbAddr_RelativePointer) {
Type *rel_ptr = base_type(lb_addr_type(addr));
@@ -954,16 +980,6 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
GB_ASSERT(value.value != nullptr);
value = lb_emit_conv(p, value, lb_addr_type(addr));
// if (lb_is_const_or_global(value)) {
// // NOTE(bill): Just bypass the actual storage and set the initializer
// if (LLVMGetValueKind(addr.addr.value) == LLVMGlobalVariableValueKind) {
// LLVMValueRef dst = addr.addr.value;
// LLVMValueRef src = value.value;
// LLVMSetInitializer(dst, src);
// return;
// }
// }
lb_emit_store(p, addr.addr, value);
}
@@ -1098,23 +1114,76 @@ gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) {
GB_ASSERT(addr.addr.value != nullptr);
if (addr.kind == lbAddr_BitField) {
Type *ct = core_type(addr.bitfield.type);
bool do_mask = false;
if (is_type_unsigned(ct) || is_type_boolean(ct)) {
// Mask
if (addr.bitfield.bit_size != 8*type_size_of(ct)) {
do_mask = true;
}
}
i64 total_bitfield_bit_size = 8*type_size_of(lb_addr_type(addr));
i64 dst_byte_size = type_size_of(addr.bitfield.type);
lbAddr dst = lb_add_local_generated(p, addr.bitfield.type, true);
lbValue src = addr.addr;
auto args = array_make<lbValue>(temporary_allocator(), 4);
args[0] = dst.addr;
args[1] = src;
args[2] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset);
args[3] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size);
lb_emit_runtime_call(p, "__read_bits", args);
lbValue bit_offset = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset);
lbValue bit_size = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size);
lbValue byte_offset = lb_const_int(p->module, t_uintptr, (addr.bitfield.bit_offset+7)/8);
lbValue byte_size = lb_const_int(p->module, t_uintptr, (addr.bitfield.bit_size+7)/8);
lbValue r = lb_addr_load(p, dst);
GB_ASSERT(type_size_of(addr.bitfield.type) >= ((addr.bitfield.bit_size+7)/8));
if (!is_type_unsigned(core_type(addr.bitfield.type))) {
lbValue r = {};
if (is_type_endian_big(addr.bitfield.type)) {
auto args = array_make<lbValue>(temporary_allocator(), 4);
args[0] = dst.addr;
args[1] = src;
args[2] = bit_offset;
args[3] = bit_size;
lb_emit_runtime_call(p, "__read_bits", args);
LLVMValueRef shift_amount = LLVMConstInt(
lb_type(p->module, lb_addr_type(dst)),
8*dst_byte_size - addr.bitfield.bit_size,
false
);
r = lb_addr_load(p, dst);
r.value = LLVMBuildShl(p->builder, r.value, shift_amount, "");
} else if ((addr.bitfield.bit_offset % 8) == 0) {
lbValue copy_size = byte_size;
lbValue src_offset = lb_emit_conv(p, src, t_u8_ptr);
src_offset = lb_emit_ptr_offset(p, src_offset, byte_offset);
if (addr.bitfield.bit_offset + dst_byte_size <= total_bitfield_bit_size) {
do_mask = true;
copy_size = lb_const_int(p->module, t_uintptr, dst_byte_size);
}
lb_mem_copy_non_overlapping(p, dst.addr, src_offset, copy_size, false);
r = lb_addr_load(p, dst);
} else {
auto args = array_make<lbValue>(temporary_allocator(), 4);
args[0] = dst.addr;
args[1] = src;
args[2] = bit_offset;
args[3] = bit_size;
lb_emit_runtime_call(p, "__read_bits", args);
r = lb_addr_load(p, dst);
}
Type *t = addr.bitfield.type;
if (do_mask) {
GB_ASSERT(addr.bitfield.bit_size < 8*type_size_of(ct));
lbValue mask = lb_const_int(p->module, t, (1ull<<cast(u64)addr.bitfield.bit_size)-1);
r = lb_emit_arith(p, Token_And, r, mask, t);
}
if (!is_type_unsigned(ct) && !is_type_boolean(ct)) {
// Sign extension
// m := 1<<(bit_size-1)
// r = (r XOR m) - m
Type *t = addr.bitfield.type;
lbValue m = lb_const_int(p->module, t, 1ull<<(addr.bitfield.bit_size-1));
r = lb_emit_arith(p, Token_Xor, r, m, t);
r = lb_emit_arith(p, Token_Sub, r, m, t);
@@ -2080,7 +2149,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
break;
case Type_Map:
init_map_internal_types(type);
init_map_internal_debug_types(type);
GB_ASSERT(t_raw_map != nullptr);
return lb_type_internal(m, t_raw_map);
+2 -11
View File
@@ -597,16 +597,7 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) {
lbValue ptr = lb_address_from_load_or_generate_local(p, param);
GB_ASSERT(LLVMIsAAllocaInst(ptr.value));
lb_add_entity(p->module, e, ptr);
lbBlock *block = p->decl_block;
if (original_value != value) {
block = p->curr_block;
}
LLVMValueRef debug_storage_value = value;
if (original_value != value && LLVMIsALoadInst(value)) {
debug_storage_value = LLVMGetOperand(value, 0);
}
lb_add_debug_param_variable(p, debug_storage_value, e->type, e->token, param_index+1, block, arg_type->kind);
lb_add_debug_param_variable(p, ptr.value, e->type, e->token, param_index+1, p->curr_block);
}
} else if (arg_type->kind == lbArg_Indirect) {
if (e->token.string.len != 0 && !is_blank_ident(e->token.string)) {
@@ -614,7 +605,7 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) {
ptr.value = LLVMGetParam(p->value, param_offset+param_index);
ptr.type = alloc_type_pointer(e->type);
lb_add_entity(p->module, e, ptr);
lb_add_debug_param_variable(p, ptr.value, e->type, e->token, param_index+1, p->decl_block, arg_type->kind);
lb_add_debug_param_variable(p, ptr.value, e->type, e->token, param_index+1, p->decl_block);
}
}
}
+6 -4
View File
@@ -249,9 +249,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
char name[64] = {};
gb_snprintf(name, 63, "__$ti-%lld", cast(long long)index);
LLVMValueRef g = LLVMAddGlobal(m->mod, type, name);
LLVMSetLinkage(g, LLVMInternalLinkage);
LLVMSetUnnamedAddress(g, LLVMGlobalUnnamedAddr);
LLVMSetGlobalConstant(g, true);
lb_make_global_private_const(g);
return g;
};
@@ -903,7 +901,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
case Type_Map: {
tag_type = t_type_info_map;
init_map_internal_types(t);
init_map_internal_debug_types(t);
LLVMValueRef vals[3] = {
get_type_info_ptr(m, t->Map.key),
@@ -1103,6 +1101,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
LLVMValueRef giant_const = LLVMConstArray(lb_type(m, t_type_info_ptr), giant_const_values, cast(unsigned)global_type_info_data_entity_count);
LLVMValueRef giant_array = lb_global_type_info_data_ptr(m).value;
LLVMSetInitializer(giant_array, giant_const);
lb_make_global_private_const(giant_array);
}
@@ -1132,4 +1131,7 @@ gb_internal void lb_setup_type_info_data(lbModule *m) { // NOTE(bill): Setup typ
LLVMValueRef slice = llvm_const_slice_internal(m, data, len);
LLVMSetInitializer(global_type_table.value, slice);
// force it to be constant
LLVMSetGlobalConstant(global_type_table.value, true);
}
+47 -46
View File
@@ -97,15 +97,12 @@ gb_internal void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, u
LLVMTypeRef llvm_type = lb_type(p->module, type);
LLVMTypeKind kind = LLVMGetTypeKind(llvm_type);
i64 sz = type_size_of(type);
switch (kind) {
case LLVMStructTypeKind:
case LLVMArrayTypeKind:
{
// NOTE(bill): Enforce zeroing through memset to make sure padding is zeroed too
i32 sz = cast(i32)type_size_of(type);
lb_mem_zero_ptr_internal(p, ptr, lb_const_int(p->module, t_int, sz).value, alignment, false);
}
// 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);
@@ -728,30 +725,32 @@ gb_internal lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type
lb_start_block(p, end_block);
if (!is_tuple) {
GB_ASSERT((p->state_flags & StateFlag_no_type_assert) == 0);
// NOTE(bill): Panic on invalid conversion
Type *dst_type = tuple->Tuple.variables[0]->type;
if (!build_context.no_type_assert) {
GB_ASSERT((p->state_flags & StateFlag_no_type_assert) == 0);
// NOTE(bill): Panic on invalid conversion
Type *dst_type = tuple->Tuple.variables[0]->type;
isize arg_count = 7;
if (build_context.no_rtti) {
arg_count = 4;
isize arg_count = 7;
if (build_context.no_rtti) {
arg_count = 4;
}
lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1));
auto args = array_make<lbValue>(permanent_allocator(), arg_count);
args[0] = ok;
args[1] = lb_const_string(m, get_file_path_string(pos.file_id));
args[2] = lb_const_int(m, t_i32, pos.line);
args[3] = lb_const_int(m, t_i32, pos.column);
if (!build_context.no_rtti) {
args[4] = lb_typeid(m, src_type);
args[5] = lb_typeid(m, dst_type);
args[6] = lb_emit_conv(p, value_, t_rawptr);
}
lb_emit_runtime_call(p, "type_assertion_check2", args);
}
lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1));
auto args = array_make<lbValue>(permanent_allocator(), arg_count);
args[0] = ok;
args[1] = lb_const_string(m, get_file_path_string(pos.file_id));
args[2] = lb_const_int(m, t_i32, pos.line);
args[3] = lb_const_int(m, t_i32, pos.column);
if (!build_context.no_rtti) {
args[4] = lb_typeid(m, src_type);
args[5] = lb_typeid(m, dst_type);
args[6] = lb_emit_conv(p, value_, t_rawptr);
}
lb_emit_runtime_call(p, "type_assertion_check2", args);
return lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 0));
}
return lb_addr_load(p, v);
@@ -806,25 +805,27 @@ gb_internal lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *ty
if (!is_tuple) {
// NOTE(bill): Panic on invalid conversion
lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1));
if (!build_context.no_type_assert) {
lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1));
isize arg_count = 7;
if (build_context.no_rtti) {
arg_count = 4;
isize arg_count = 7;
if (build_context.no_rtti) {
arg_count = 4;
}
auto args = array_make<lbValue>(permanent_allocator(), arg_count);
args[0] = ok;
args[1] = lb_const_string(m, get_file_path_string(pos.file_id));
args[2] = lb_const_int(m, t_i32, pos.line);
args[3] = lb_const_int(m, t_i32, pos.column);
if (!build_context.no_rtti) {
args[4] = any_typeid;
args[5] = dst_typeid;
args[6] = lb_emit_struct_ev(p, value, 0);
}
lb_emit_runtime_call(p, "type_assertion_check2", args);
}
auto args = array_make<lbValue>(permanent_allocator(), arg_count);
args[0] = ok;
args[1] = lb_const_string(m, get_file_path_string(pos.file_id));
args[2] = lb_const_int(m, t_i32, pos.line);
args[3] = lb_const_int(m, t_i32, pos.column);
if (!build_context.no_rtti) {
args[4] = any_typeid;
args[5] = dst_typeid;
args[6] = lb_emit_struct_ev(p, value, 0);
}
lb_emit_runtime_call(p, "type_assertion_check2", args);
return lb_addr(lb_emit_struct_ep(p, v.addr, 0));
}
@@ -1125,7 +1126,7 @@ gb_internal lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
case 3: result_type = t_allocator; break;
}
} else if (is_type_map(t)) {
init_map_internal_types(t);
init_map_internal_debug_types(t);
Type *itp = alloc_type_pointer(t_raw_map);
s = lb_emit_transmute(p, s, itp);
@@ -1264,7 +1265,7 @@ gb_internal lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) {
case Type_Map:
{
init_map_internal_types(t);
init_map_internal_debug_types(t);
switch (index) {
case 0: result_type = get_struct_field_type(t_raw_map, 0); break;
case 1: result_type = get_struct_field_type(t_raw_map, 1); break;
+51 -14
View File
@@ -198,7 +198,12 @@ gb_internal void print_usage_line(i32 indent, char const *fmt, ...) {
gb_printf("\n");
}
gb_internal void usage(String argv0) {
gb_internal void usage(String argv0, String argv1 = {}) {
if (argv1 == "run.") {
print_usage_line(0, "Did you mean 'odin run .'?");
} else if (argv1 == "build.") {
print_usage_line(0, "Did you mean 'odin build .'?");
}
print_usage_line(0, "%.*s is a tool for managing Odin source code.", LIT(argv0));
print_usage_line(0, "Usage:");
print_usage_line(1, "%.*s command [arguments]", LIT(argv0));
@@ -212,6 +217,7 @@ gb_internal void usage(String argv0) {
print_usage_line(1, "doc Generates documentation on a directory of .odin files.");
print_usage_line(1, "version Prints version.");
print_usage_line(1, "report Prints information useful to reporting a bug.");
print_usage_line(1, "root Prints the root path where Odin looks for the builtin collections.");
print_usage_line(0, "");
print_usage_line(0, "For further details on a command, invoke command help:");
print_usage_line(1, "e.g. `odin build -help` or `odin help build`");
@@ -242,6 +248,7 @@ enum BuildFlagKind {
BuildFlag_Debug,
BuildFlag_DisableAssert,
BuildFlag_NoBoundsCheck,
BuildFlag_NoTypeAssert,
BuildFlag_NoDynamicLiterals,
BuildFlag_NoCRT,
BuildFlag_NoEntryPoint,
@@ -253,6 +260,8 @@ enum BuildFlagKind {
BuildFlag_Vet,
BuildFlag_VetShadowing,
BuildFlag_VetUnused,
BuildFlag_VetUnusedImports,
BuildFlag_VetUnusedVariables,
BuildFlag_VetUsingStmt,
BuildFlag_VetUsingParam,
BuildFlag_VetStyle,
@@ -333,12 +342,12 @@ struct BuildFlag {
String name;
BuildFlagParamKind param_kind;
u32 command_support;
bool allow_mulitple;
bool allow_multiple;
};
gb_internal void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, BuildFlagParamKind param_kind, u32 command_support, bool allow_mulitple=false) {
BuildFlag flag = {kind, name, param_kind, command_support, allow_mulitple};
gb_internal void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, BuildFlagParamKind param_kind, u32 command_support, bool allow_multiple=false) {
BuildFlag flag = {kind, name, param_kind, command_support, allow_multiple};
array_add(build_flags, flag);
}
@@ -433,6 +442,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_DisableAssert, str_lit("disable-assert"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_NoBoundsCheck, str_lit("no-bounds-check"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_NoTypeAssert, str_lit("no-type-assert"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_NoThreadLocal, str_lit("no-thread-local"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_NoDynamicLiterals, str_lit("no-dynamic-literals"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None, Command__does_build);
@@ -444,6 +454,8 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_VetUnused, str_lit("vet-unused"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_VetUnusedVariables, str_lit("vet-unused-variables"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_VetUnusedImports, str_lit("vet-unused-imports"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_VetShadowing, str_lit("vet-shadowing"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_VetUsingStmt, str_lit("vet-using-stmt"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_VetUsingParam, str_lit("vet-using-param"), BuildFlagParam_None, Command__does_check);
@@ -1008,6 +1020,9 @@ gb_internal bool parse_build_flags(Array<String> args) {
case BuildFlag_NoBoundsCheck:
build_context.no_bounds_check = true;
break;
case BuildFlag_NoTypeAssert:
build_context.no_type_assert = true;
break;
case BuildFlag_NoDynamicLiterals:
build_context.no_dynamic_literals = true;
break;
@@ -1026,10 +1041,9 @@ gb_internal bool parse_build_flags(Array<String> args) {
case BuildFlag_UseSeparateModules:
build_context.use_separate_modules = true;
break;
case BuildFlag_NoThreadedChecker: {
case BuildFlag_NoThreadedChecker:
build_context.no_threaded_checker = true;
break;
}
case BuildFlag_ShowDebugMessages:
build_context.show_debug_messages = true;
break;
@@ -1037,12 +1051,14 @@ gb_internal bool parse_build_flags(Array<String> args) {
build_context.vet_flags |= VetFlag_All;
break;
case BuildFlag_VetUnused: build_context.vet_flags |= VetFlag_Unused; break;
case BuildFlag_VetShadowing: build_context.vet_flags |= VetFlag_Shadowing; break;
case BuildFlag_VetUsingStmt: build_context.vet_flags |= VetFlag_UsingStmt; break;
case BuildFlag_VetUsingParam: build_context.vet_flags |= VetFlag_UsingParam; break;
case BuildFlag_VetStyle: build_context.vet_flags |= VetFlag_Style; break;
case BuildFlag_VetSemicolon: build_context.vet_flags |= VetFlag_Semicolon; break;
case BuildFlag_VetUnusedVariables: build_context.vet_flags |= VetFlag_UnusedVariables; break;
case BuildFlag_VetUnusedImports: build_context.vet_flags |= VetFlag_UnusedImports; break;
case BuildFlag_VetUnused: build_context.vet_flags |= VetFlag_Unused; break;
case BuildFlag_VetShadowing: build_context.vet_flags |= VetFlag_Shadowing; break;
case BuildFlag_VetUsingStmt: build_context.vet_flags |= VetFlag_UsingStmt; break;
case BuildFlag_VetUsingParam: build_context.vet_flags |= VetFlag_UsingParam; break;
case BuildFlag_VetStyle: build_context.vet_flags |= VetFlag_Style; break;
case BuildFlag_VetSemicolon: build_context.vet_flags |= VetFlag_Semicolon; break;
case BuildFlag_IgnoreUnknownAttributes:
build_context.ignore_unknown_attributes = true;
@@ -1347,7 +1363,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
}
}
if (!bf.allow_mulitple) {
if (!bf.allow_multiple) {
set_flags[bf.kind] = ok;
}
}
@@ -1844,6 +1860,10 @@ gb_internal void print_show_help(String const arg0, String const &command) {
print_usage_line(2, "Disables bounds checking program wide.");
print_usage_line(0, "");
print_usage_line(1, "-no-type-assert");
print_usage_line(2, "Disables type assertion checking program wide.");
print_usage_line(0, "");
print_usage_line(1, "-no-crt");
print_usage_line(2, "Disables automatic linking with the C Run Time.");
print_usage_line(0, "");
@@ -1875,6 +1895,8 @@ gb_internal void print_show_help(String const arg0, String const &command) {
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, "");
@@ -1883,6 +1905,14 @@ gb_internal void print_show_help(String const arg0, String const &command) {
print_usage_line(2, "Checks for unused declarations.");
print_usage_line(0, "");
print_usage_line(1, "-vet-unused-variables");
print_usage_line(2, "Checks for unused variable declarations.");
print_usage_line(0, "");
print_usage_line(1, "-vet-unused-imports");
print_usage_line(2, "Checks for unused import declarations.");
print_usage_line(0, "");
print_usage_line(1, "-vet-shadowing");
print_usage_line(2, "Checks for variable shadowing within procedures.");
print_usage_line(0, "");
@@ -2557,8 +2587,15 @@ int main(int arg_count, char const **arg_ptr) {
print_show_help(args[0], args[2]);
return 0;
}
} else if (command == "root") {
gb_printf("%.*s", LIT(odin_root_dir()));
return 0;
} else {
usage(args[0]);
String argv1 = {};
if (args.count > 1) {
argv1 = args[1];
}
usage(args[0], argv1);
return 1;
}
+6
View File
@@ -6114,7 +6114,13 @@ gb_internal bool parse_file(Parser *p, AstFile *f) {
CommentGroup *docs = f->lead_comment;
if (f->curr_token.kind != Token_package) {
ERROR_BLOCK();
syntax_error(f->curr_token, "Expected a package declaration at the beginning of the file");
// IMPORTANT NOTE(bill): this is technically a race condition with the suggestion, but it's ony a suggession
// so in practice is should be "fine"
if (f->pkg && f->pkg->name != "") {
error_line("\tSuggestion: Add 'package %.*s' to the top of the file\n", LIT(f->pkg->name));
}
return false;
}
+68 -6
View File
@@ -171,6 +171,9 @@ template <isize N> gb_internal bool operator > (String const &a, char const (&b
template <isize N> gb_internal bool operator <= (String const &a, char const (&b)[N]) { return str_le(a, make_string(cast(u8 *)b, N-1)); }
template <isize N> gb_internal bool operator >= (String const &a, char const (&b)[N]) { return str_ge(a, make_string(cast(u8 *)b, N-1)); }
template <> bool operator == (String const &a, char const (&b)[1]) { return a.len == 0; }
template <> bool operator != (String const &a, char const (&b)[1]) { return a.len != 0; }
gb_internal gb_inline bool string_starts_with(String const &s, String const &prefix) {
if (prefix.len > s.len) {
return false;
@@ -234,11 +237,16 @@ gb_internal String string_split_iterator(String_Iterator *it, const char sep) {
return substring(it->str, start, end);
}
gb_internal gb_inline bool is_separator(u8 const &ch) {
return (ch == '/' || ch == '\\');
}
gb_internal gb_inline isize string_extension_position(String const &str) {
isize dot_pos = -1;
isize i = str.len;
while (i --> 0) {
if (str[i] == '\\' || str[i] == '/')
if (is_separator(str[i]))
break;
if (str[i] == '.') {
dot_pos = i;
@@ -273,6 +281,43 @@ gb_internal String string_trim_whitespace(String str) {
return str;
}
gb_internal String string_trim_trailing_whitespace(String str) {
while (str.len > 0) {
u8 c = str[str.len-1];
if (rune_is_whitespace(c) || c == 0) {
str.len -= 1;
} else {
break;
}
}
return str;
}
gb_internal String split_lines_first_line_from_array(Array<u8> const &array, gbAllocator allocator) {
String_Iterator it = {{array.data, array.count}, 0};
String line = string_split_iterator(&it, '\n');
line = string_trim_trailing_whitespace(line);
return line;
}
gb_internal Array<String> split_lines_from_array(Array<u8> const &array, gbAllocator allocator) {
Array<String> lines = {};
lines.allocator = allocator;
String_Iterator it = {{array.data, array.count}, 0};
for (;;) {
String line = string_split_iterator(&it, '\n');
if (line.len == 0) {
break;
}
line = string_trim_trailing_whitespace(line);
array_add(&lines, line);
}
return lines;
}
gb_internal bool string_contains_char(String const &s, u8 c) {
isize i;
@@ -292,8 +337,7 @@ gb_internal String filename_from_path(String s) {
if (i > 0) {
isize j = 0;
for (j = s.len-1; j >= 0; j--) {
if (s[j] == '/' ||
s[j] == '\\') {
if (is_separator(s[j])) {
break;
}
}
@@ -306,8 +350,7 @@ gb_internal String filename_from_path(String s) {
gb_internal String filename_without_directory(String s) {
isize j = 0;
for (j = s.len-1; j >= 0; j--) {
if (s[j] == '/' ||
s[j] == '\\') {
if (is_separator(s[j])) {
break;
}
}
@@ -370,7 +413,26 @@ gb_internal String copy_string(gbAllocator a, String const &s) {
return make_string(data, s.len);
}
gb_internal String normalize_path(gbAllocator a, String const &path, String const &sep) {
String s;
if (sep.len < 1) {
return path;
}
if (path.len < 1) {
s = STR_LIT("");
} else if (is_separator(path[path.len-1])) {
s = copy_string(a, path);
} else {
s = concatenate_strings(a, path, sep);
}
isize i;
for (i = 0; i < s.len; i++) {
if (is_separator(s.text[i])) {
s.text[i] = sep.text[0];
}
}
return s;
}
#if defined(GB_SYSTEM_WINDOWS)
+1
View File
@@ -193,6 +193,7 @@ gb_internal void init_keyword_hash_table(void) {
gb_global Array<String> global_file_path_strings; // index is file id
gb_global Array<struct AstFile *> global_files; // index is file id
gb_global BlockingMutex global_files_mutex;
gb_internal String get_file_path_string(i32 index);
gb_internal struct AstFile *thread_safe_get_ast_file_from_id(i32 index);
-1
View File
@@ -769,7 +769,6 @@ gb_internal gbString type_to_string (Type *type, bool shorthand=true);
gb_internal gbString type_to_string (Type *type, gbAllocator allocator, bool shorthand=true);
gb_internal i64 type_size_of_internal(Type *t, TypePath *path);
gb_internal i64 type_align_of_internal(Type *t, TypePath *path);
gb_internal void init_map_internal_types(Type *type);
gb_internal Type * bit_set_to_int(Type *t);
gb_internal bool are_types_identical(Type *x, Type *y);