mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-24 22:54:59 -07:00
Merge branch 'master' into netbsd
This commit is contained in:
+58
-88
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -122,7 +122,6 @@ struct lbAddr {
|
||||
} swizzle_large;
|
||||
struct {
|
||||
Type *type;
|
||||
i64 index;
|
||||
i64 bit_offset;
|
||||
i64 bit_size;
|
||||
} bitfield;
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user