Merge remote-tracking branch 'upstream/master' into fix_odin_test

This commit is contained in:
Jason Kercher
2022-03-09 17:17:40 -05:00
210 changed files with 19327 additions and 3937 deletions

View File

@@ -89,7 +89,9 @@ template <typename T>
void slice_init(Slice<T> *s, gbAllocator const &allocator, isize count) {
GB_ASSERT(count >= 0);
s->data = gb_alloc_array(allocator, T, count);
GB_ASSERT(s->data != nullptr);
if (count > 0) {
GB_ASSERT(s->data != nullptr);
}
s->count = count;
}

View File

@@ -17,6 +17,11 @@
#include <sys/sysctl.h>
#endif
#if defined(GB_SYSTEM_OPENBSD)
#include <sys/sysctl.h>
#include <sys/utsname.h>
#endif
/*
NOTE(Jeroen): This prints the Windows product edition only, to be called from `print_platform_details`.
*/
@@ -242,6 +247,14 @@ void report_ram_info() {
if (sysctl(sysctls, 2, &ram_amount, &val_size, NULL, 0) != -1) {
gb_printf("%lld MiB\n", ram_amount / gb_megabytes(1));
}
#elif defined(GB_SYSTEM_OPENBSD)
uint64_t ram_amount;
size_t val_size = sizeof(ram_amount);
int sysctls[] = { CTL_HW, HW_PHYSMEM64 };
if (sysctl(sysctls, 2, &ram_amount, &val_size, NULL, 0) != -1) {
gb_printf("%lld MiB\n", ram_amount / gb_megabytes(1));
}
#else
gb_printf("Unknown.\n");
#endif
@@ -473,11 +486,11 @@ void print_bug_report_help() {
#elif defined(GB_SYSTEM_LINUX)
/*
Try to parse `/usr/lib/os-release` for `PRETTY_NAME="Ubuntu 20.04.3 LTS`
Try to parse `/etc/os-release` for `PRETTY_NAME="Ubuntu 20.04.3 LTS`
*/
gbAllocator a = heap_allocator();
gbFileContents release = gb_file_read_contents(a, 1, "/usr/lib/os-release");
gbFileContents release = gb_file_read_contents(a, 1, "/etc/os-release");
defer (gb_file_free_contents(&release));
b32 found = 0;
@@ -643,6 +656,14 @@ void print_bug_report_help() {
} else {
gb_printf("macOS: Unknown\n");
}
#elif defined(GB_SYSTEM_OPENBSD)
struct utsname un;
if (uname(&un) != -1) {
gb_printf("%s %s %s %s\n", un.sysname, un.release, un.version, un.machine);
} else {
gb_printf("OpenBSD: Unknown\n");
}
#else
gb_printf("Unknown\n");
@@ -657,4 +678,4 @@ void print_bug_report_help() {
And RAM info.
*/
report_ram_info();
}
}

View File

@@ -1,4 +1,4 @@
#if defined(GB_SYSTEM_FREEBSD)
#if defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD)
#include <sys/types.h>
#include <sys/sysctl.h>
#endif
@@ -16,6 +16,7 @@ enum TargetOsKind {
TargetOs_linux,
TargetOs_essence,
TargetOs_freebsd,
TargetOs_openbsd,
TargetOs_wasi,
TargetOs_js,
@@ -53,6 +54,7 @@ String target_os_names[TargetOs_COUNT] = {
str_lit("linux"),
str_lit("essence"),
str_lit("freebsd"),
str_lit("openbsd"),
str_lit("wasi"),
str_lit("js"),
@@ -278,7 +280,7 @@ bool global_ignore_warnings(void) {
}
gb_global TargetMetrics target_windows_386 = {
gb_global TargetMetrics target_windows_i386 = {
TargetOs_windows,
TargetArch_i386,
4,
@@ -294,7 +296,7 @@ gb_global TargetMetrics target_windows_amd64 = {
str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
};
gb_global TargetMetrics target_linux_386 = {
gb_global TargetMetrics target_linux_i386 = {
TargetOs_linux,
TargetArch_i386,
4,
@@ -337,7 +339,7 @@ gb_global TargetMetrics target_darwin_arm64 = {
str_lit("e-m:o-i64:64-i128:128-n32:64-S128"), // TODO(bill): Is this correct?
};
gb_global TargetMetrics target_freebsd_386 = {
gb_global TargetMetrics target_freebsd_i386 = {
TargetOs_freebsd,
TargetArch_i386,
4,
@@ -354,6 +356,15 @@ gb_global TargetMetrics target_freebsd_amd64 = {
str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
};
gb_global TargetMetrics target_openbsd_amd64 = {
TargetOs_openbsd,
TargetArch_amd64,
8,
16,
str_lit("x86_64-unknown-openbsd-elf"),
str_lit("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"),
};
gb_global TargetMetrics target_essence_amd64 = {
TargetOs_essence,
TargetArch_amd64,
@@ -410,13 +421,14 @@ gb_global NamedTargetMetrics named_targets[] = {
{ str_lit("darwin_amd64"), &target_darwin_amd64 },
{ str_lit("darwin_arm64"), &target_darwin_arm64 },
{ str_lit("essence_amd64"), &target_essence_amd64 },
{ str_lit("linux_386"), &target_linux_386 },
{ str_lit("linux_i386"), &target_linux_i386 },
{ str_lit("linux_amd64"), &target_linux_amd64 },
{ str_lit("linux_arm64"), &target_linux_arm64 },
{ str_lit("windows_386"), &target_windows_386 },
{ str_lit("windows_i386"), &target_windows_i386 },
{ str_lit("windows_amd64"), &target_windows_amd64 },
{ str_lit("freebsd_386"), &target_freebsd_386 },
{ str_lit("freebsd_i386"), &target_freebsd_i386 },
{ str_lit("freebsd_amd64"), &target_freebsd_amd64 },
{ str_lit("openbsd_amd64"), &target_openbsd_amd64 },
{ str_lit("freestanding_wasm32"), &target_freestanding_wasm32 },
{ str_lit("wasi_wasm32"), &target_wasi_wasm32 },
{ str_lit("js_wasm32"), &target_js_wasm32 },
@@ -722,10 +734,38 @@ String internal_odin_root_dir(void) {
len = readlink("/proc/curproc/exe", &path_buf[0], path_buf.count);
#elif defined(GB_SYSTEM_DRAGONFLYBSD)
len = readlink("/proc/curproc/file", &path_buf[0], path_buf.count);
#else
#elif defined(GB_SYSTEM_LINUX)
len = readlink("/proc/self/exe", &path_buf[0], path_buf.count);
#elif defined(GB_SYSTEM_OPENBSD)
int error;
int mib[] = {
CTL_KERN,
KERN_PROC_ARGS,
getpid(),
KERN_PROC_ARGV,
};
// get argv size
error = sysctl(mib, 4, NULL, (size_t *) &len, NULL, 0);
if (error == -1) {
// sysctl error
return make_string(nullptr, 0);
}
// get argv
char **argv = (char **)gb_malloc(len);
error = sysctl(mib, 4, argv, (size_t *) &len, NULL, 0);
if (error == -1) {
// sysctl error
gb_mfree(argv);
return make_string(nullptr, 0);
}
// copy argv[0] to path_buf
len = gb_strlen(argv[0]);
if(len < path_buf.count) {
gb_memmove(&path_buf[0], argv[0], len);
}
gb_mfree(argv);
#endif
if(len == 0) {
if(len == 0 || len == -1) {
return make_string(nullptr, 0);
}
if (len < path_buf.count) {
@@ -922,6 +962,8 @@ void init_build_context(TargetMetrics *cross_target) {
#endif
#elif defined(GB_SYSTEM_FREEBSD)
metrics = &target_freebsd_amd64;
#elif defined(GB_SYSTEM_OPENBSD)
metrics = &target_openbsd_amd64;
#elif defined(GB_CPU_ARM)
metrics = &target_linux_arm64;
#else
@@ -929,13 +971,13 @@ void init_build_context(TargetMetrics *cross_target) {
#endif
#else
#if defined(GB_SYSTEM_WINDOWS)
metrics = &target_windows_386;
metrics = &target_windows_i386;
#elif defined(GB_SYSTEM_OSX)
#error "Build Error: Unsupported architecture"
#elif defined(GB_SYSTEM_FREEBSD)
metrics = &target_freebsd_386;
metrics = &target_freebsd_i386;
#else
metrics = &target_linux_386;
metrics = &target_linux_i386;
#endif
#endif
@@ -980,6 +1022,9 @@ void init_build_context(TargetMetrics *cross_target) {
case TargetOs_freebsd:
bc->link_flags = str_lit("-arch x86-64 ");
break;
case TargetOs_openbsd:
bc->link_flags = str_lit("-arch x86-64 ");
break;
}
} else if (bc->metrics.arch == TargetArch_i386) {
switch (bc->metrics.os) {

View File

@@ -223,36 +223,35 @@ void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Slice<T
map_set(&c->info->objc_msgSend_types, call, data);
mutex_unlock(&c->info->objc_types_mutex);
add_package_dependency(c, "runtime", "objc_lookUpClass");
add_package_dependency(c, "runtime", "sel_registerName");
add_package_dependency(c, "runtime", "objc_allocateClassPair");
try_to_add_package_dependency(c, "runtime", "objc_msgSend");
try_to_add_package_dependency(c, "runtime", "objc_msgSend_fpret");
try_to_add_package_dependency(c, "runtime", "objc_msgSend_fp2ret");
try_to_add_package_dependency(c, "runtime", "objc_msgSend_stret");
}
add_package_dependency(c, "runtime", "objc_msgSend");
add_package_dependency(c, "runtime", "objc_msgSend_fpret");
add_package_dependency(c, "runtime", "objc_msgSend_fp2ret");
add_package_dependency(c, "runtime", "objc_msgSend_stret");
bool is_constant_string(CheckerContext *c, String const &builtin_name, Ast *expr, String *name_) {
Operand op = {};
check_expr(c, &op, expr);
if (op.mode == Addressing_Constant && op.value.kind == ExactValue_String) {
if (name_) *name_ = op.value.value_string;
return true;
}
gbString e = expr_to_string(op.expr);
gbString t = type_to_string(op.type);
error(op.expr, "'%.*s' expected a constant string value, got %s of type %s", LIT(builtin_name), e, t);
gb_string_free(t);
gb_string_free(e);
return false;
}
bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
auto const is_constant_string = [](CheckerContext *c, String const &builtin_name, Ast *expr, String *name_) -> bool {
Operand op = {};
check_expr(c, &op, expr);
if (op.mode == Addressing_Constant && op.value.kind == ExactValue_String) {
if (name_) *name_ = op.value.value_string;
return true;
}
gbString e = expr_to_string(op.expr);
gbString t = type_to_string(op.type);
error(op.expr, "'%.*s' expected a constant string value, got %s of type %s", LIT(builtin_name), e, t);
gb_string_free(t);
gb_string_free(e);
return false;
};
String builtin_name = builtin_procs[id].name;
if (build_context.metrics.os != TargetOs_darwin) {
error(call, "'%.*s' only works on darwin", LIT(builtin_name));
return false;
// allow on doc generation (e.g. Metal stuff)
if (build_context.command_kind != Command_doc && build_context.command_kind != Command_check) {
error(call, "'%.*s' only works on darwin", LIT(builtin_name));
}
}
@@ -371,6 +370,10 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call
}
operand->mode = Addressing_Value;
try_to_add_package_dependency(c, "runtime", "objc_lookUpClass");
try_to_add_package_dependency(c, "runtime", "sel_registerName");
try_to_add_package_dependency(c, "runtime", "objc_allocateClassPair");
return true;
} break;
}
@@ -949,7 +952,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
mode = Addressing_Constant;
value = exact_value_i64(at->EnumeratedArray.count);
type = t_untyped_integer;
} else if (is_type_slice(op_type) && id == BuiltinProc_len) {
} else if ((is_type_slice(op_type) || is_type_relative_slice(op_type)) && id == BuiltinProc_len) {
mode = Addressing_Value;
} else if (is_type_dynamic_array(op_type)) {
mode = Addressing_Value;
@@ -1103,7 +1106,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
Selection sel = lookup_field(type, field_name, false);
if (sel.entity == nullptr) {
gbString type_str = type_to_string(type);
gbString type_str = type_to_string_shorthand(type);
error(ce->args[0],
"'%s' has no field named '%.*s'", type_str, LIT(field_name));
gb_string_free(type_str);
@@ -1115,7 +1118,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
return false;
}
if (sel.indirect) {
gbString type_str = type_to_string(type);
gbString type_str = type_to_string_shorthand(type);
error(ce->args[0],
"Field '%.*s' is embedded via a pointer in '%s'", LIT(field_name), type_str);
gb_string_free(type_str);
@@ -1176,7 +1179,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
Selection sel = lookup_field(type, field_name, false);
if (sel.entity == nullptr) {
gbString type_str = type_to_string(type);
gbString type_str = type_to_string_shorthand(type);
error(ce->args[0],
"'%s' has no field named '%.*s'", type_str, LIT(field_name));
gb_string_free(type_str);
@@ -1188,7 +1191,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
return false;
}
if (sel.indirect) {
gbString type_str = type_to_string(type);
gbString type_str = type_to_string_shorthand(type);
error(ce->args[0],
"Field '%.*s' is embedded via a pointer in '%s'", LIT(field_name), type_str);
gb_string_free(type_str);
@@ -3503,6 +3506,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
case TargetOs_linux:
case TargetOs_essence:
case TargetOs_freebsd:
case TargetOs_openbsd:
switch (build_context.metrics.arch) {
case TargetArch_i386:
case TargetArch_amd64:
@@ -4086,6 +4090,18 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
break;
}
case BuiltinProc_constant_utf16_cstring:
{
String value = {};
if (!is_constant_string(c, builtin_name, ce->args[0], &value)) {
return false;
}
operand->mode = Addressing_Value;
operand->type = alloc_type_multi_pointer(t_u16);
operand->value = {};
break;
}
}

View File

@@ -174,6 +174,10 @@ void check_init_constant(CheckerContext *ctx, Entity *e, Operand *operand) {
return;
}
if (is_type_proc(e->type)) {
error(e->token, "Illegal declaration of a constant procedure value");
}
e->parent_proc_decl = ctx->curr_proc_decl;
e->Constant.value = operand->value;

View File

@@ -132,6 +132,62 @@ void check_did_you_mean_print(DidYouMeanAnswers *d, char const *prefix = "") {
}
}
void populate_check_did_you_mean_objc_entity(StringSet *set, Entity *e, bool is_type) {
if (e->kind != Entity_TypeName) {
return;
}
if (e->TypeName.objc_metadata == nullptr) {
return;
}
TypeNameObjCMetadata *objc_metadata = e->TypeName.objc_metadata;
Type *t = base_type(e->type);
GB_ASSERT(t->kind == Type_Struct);
if (is_type) {
for_array(i, objc_metadata->type_entries) {
String name = objc_metadata->type_entries[i].name;
string_set_add(set, name);
}
} else {
for_array(i, objc_metadata->value_entries) {
String name = objc_metadata->value_entries[i].name;
string_set_add(set, name);
}
}
for_array(i, t->Struct.fields) {
Entity *f = t->Struct.fields[i];
if (f->flags & EntityFlag_Using && f->type != nullptr) {
if (f->type->kind == Type_Named && f->type->Named.type_name) {
populate_check_did_you_mean_objc_entity(set, f->type->Named.type_name, is_type);
}
}
}
}
void check_did_you_mean_objc_entity(String const &name, Entity *e, bool is_type, char const *prefix = "") {
ERROR_BLOCK();
GB_ASSERT(e->kind == Entity_TypeName);
GB_ASSERT(e->TypeName.objc_metadata != nullptr);
auto *objc_metadata = e->TypeName.objc_metadata;
mutex_lock(objc_metadata->mutex);
defer (mutex_unlock(objc_metadata->mutex));
StringSet set = {};
string_set_init(&set, heap_allocator());
defer (string_set_destroy(&set));
populate_check_did_you_mean_objc_entity(&set, e, is_type);
DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), set.entries.count, name);
defer (did_you_mean_destroy(&d));
for_array(i, set.entries) {
did_you_mean_append(&d, set.entries[i].value);
}
check_did_you_mean_print(&d, prefix);
}
void check_did_you_mean_type(String const &name, Array<Entity *> const &fields, char const *prefix = "") {
ERROR_BLOCK();
@@ -144,6 +200,7 @@ void check_did_you_mean_type(String const &name, Array<Entity *> const &fields,
check_did_you_mean_print(&d, prefix);
}
void check_did_you_mean_type(String const &name, Slice<Entity *> const &fields, char const *prefix = "") {
ERROR_BLOCK();
@@ -4413,14 +4470,19 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
if (entity == nullptr) {
gbString op_str = expr_to_string(op_expr);
gbString type_str = type_to_string(operand->type);
gbString type_str = type_to_string_shorthand(operand->type);
gbString sel_str = expr_to_string(selector);
error(op_expr, "'%s' of type '%s' has no field '%s'", op_str, type_str, sel_str);
if (operand->type != nullptr && selector->kind == Ast_Ident) {
String const &name = selector->Ident.token.string;
Type *bt = base_type(operand->type);
if (bt->kind == Type_Struct) {
if (operand->type->kind == Type_Named &&
operand->type->Named.type_name &&
operand->type->Named.type_name->kind == Entity_TypeName &&
operand->type->Named.type_name->TypeName.objc_metadata) {
check_did_you_mean_objc_entity(name, operand->type->Named.type_name, operand->mode == Addressing_Type);
} else if (bt->kind == Type_Struct) {
check_did_you_mean_type(name, bt->Struct.fields);
} else if (bt->kind == Type_Enum) {
check_did_you_mean_type(name, bt->Enum.fields);
@@ -4449,7 +4511,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
}
gbString op_str = expr_to_string(op_expr);
gbString type_str = type_to_string(operand->type);
gbString type_str = type_to_string_shorthand(operand->type);
gbString sel_str = expr_to_string(selector);
error(op_expr, "Cannot access non-constant field '%s' from '%s'", sel_str, op_str);
gb_string_free(sel_str);
@@ -4474,7 +4536,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
}
gbString op_str = expr_to_string(op_expr);
gbString type_str = type_to_string(operand->type);
gbString type_str = type_to_string_shorthand(operand->type);
gbString sel_str = expr_to_string(selector);
error(op_expr, "Cannot access non-constant field '%s' from '%s'", sel_str, op_str);
gb_string_free(sel_str);
@@ -4487,7 +4549,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
if (expr_entity != nullptr && is_type_polymorphic(expr_entity->type)) {
gbString op_str = expr_to_string(op_expr);
gbString type_str = type_to_string(operand->type);
gbString type_str = type_to_string_shorthand(operand->type);
gbString sel_str = expr_to_string(selector);
error(op_expr, "Cannot access field '%s' from non-specialized polymorphic type '%s'", sel_str, op_str);
gb_string_free(sel_str);
@@ -9774,6 +9836,9 @@ gbString write_expr_to_string(gbString str, Ast *node, bool shorthand) {
if (f->flags&FieldFlag_const) {
str = gb_string_appendc(str, "#const ");
}
if (f->flags&FieldFlag_subtype) {
str = gb_string_appendc(str, "#subtype ");
}
for_array(i, f->names) {
Ast *name = f->names[i];

View File

@@ -144,6 +144,7 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entity *> *fields
}
bool is_using = (p->flags&FieldFlag_using) != 0;
bool is_subtype = (p->flags&FieldFlag_subtype) != 0;
for_array(j, p->names) {
Ast *name = p->names[j];
@@ -158,6 +159,9 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entity *> *fields
Entity *field = alloc_entity_field(ctx->scope, name_token, type, is_using, field_src_index);
add_entity(ctx, ctx->scope, name, field);
field->Variable.field_group_index = field_group_index;
if (is_subtype) {
field->flags |= EntityFlag_Subtype;
}
if (j == 0) {
field->Variable.docs = docs;
@@ -194,6 +198,20 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entity *> *fields
populate_using_entity_scope(ctx, node, p, type);
}
if (is_subtype && p->names.count > 0) {
Type *first_type = fields_array[fields_array.count-1]->type;
Type *t = base_type(type_deref(first_type));
if (!does_field_type_allow_using(t) &&
p->names.count >= 1 &&
p->names[0]->kind == Ast_Ident) {
Token name_token = p->names[0]->Ident.token;
gbString type_str = type_to_string(first_type);
error(name_token, "'subtype' cannot be applied to the field '%.*s' of type '%s'", LIT(name_token.string), type_str);
gb_string_free(type_str);
}
}
}
*fields = slice_from_array(fields_array);

View File

@@ -225,8 +225,8 @@ bool decl_info_has_init(DeclInfo *d) {
Scope *create_scope(CheckerInfo *info, Scope *parent, isize init_elements_capacity=DEFAULT_SCOPE_CAPACITY) {
Scope *s = gb_alloc_item(permanent_allocator(), Scope);
s->parent = parent;
string_map_init(&s->elements, permanent_allocator(), init_elements_capacity);
ptr_set_init(&s->imported, permanent_allocator(), 0);
string_map_init(&s->elements, heap_allocator(), init_elements_capacity);
ptr_set_init(&s->imported, heap_allocator(), 0);
mutex_init(&s->mutex);
if (parent != nullptr && parent != builtin_pkg->scope) {
@@ -733,12 +733,25 @@ void add_package_dependency(CheckerContext *c, char const *package_name, char co
String n = make_string_c(name);
AstPackage *p = get_core_package(&c->checker->info, make_string_c(package_name));
Entity *e = scope_lookup(p->scope, n);
e->flags |= EntityFlag_Used;
GB_ASSERT_MSG(e != nullptr, "%s", name);
GB_ASSERT(c->decl != nullptr);
e->flags |= EntityFlag_Used;
add_dependency(c->info, c->decl, e);
}
void try_to_add_package_dependency(CheckerContext *c, char const *package_name, char const *name) {
String n = make_string_c(name);
AstPackage *p = get_core_package(&c->checker->info, make_string_c(package_name));
Entity *e = scope_lookup(p->scope, n);
if (e == nullptr) {
return;
}
GB_ASSERT(c->decl != nullptr);
e->flags |= EntityFlag_Used;
add_dependency(c->info, c->decl, e);
}
void add_declaration_dependency(CheckerContext *c, Entity *e) {
if (e == nullptr) {
return;
@@ -893,6 +906,7 @@ void init_universal(void) {
{"Linux", TargetOs_linux},
{"Essence", TargetOs_essence},
{"FreeBSD", TargetOs_freebsd},
{"OpenBSD", TargetOs_openbsd},
{"WASI", TargetOs_wasi},
{"JS", TargetOs_js},
{"Freestanding", TargetOs_freestanding},

View File

@@ -258,6 +258,9 @@ BuiltinProc__type_end,
BuiltinProc_objc_register_selector,
BuiltinProc_objc_register_class,
BuiltinProc_constant_utf16_cstring,
BuiltinProc_COUNT,
};
gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
@@ -517,4 +520,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("objc_find_class"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("objc_register_selector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("objc_register_class"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("constant_utf16_cstring"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
};

View File

@@ -848,7 +848,7 @@ ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
return ReadDirectory_None;
}
#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD)
#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD)
#include <dirent.h>
@@ -1021,7 +1021,7 @@ LoadedFileError load_file_32(char const *fullpath, LoadedFile *memory_mapped_fil
#endif
}
gbFileContents fc = gb_file_read_contents(heap_allocator(), true, fullpath);
gbFileContents fc = gb_file_read_contents(permanent_allocator(), true, fullpath);
if (fc.size > I32_MAX) {
err = LoadedFile_FileTooLarge;

View File

@@ -139,6 +139,7 @@ struct PlatformMemoryBlock {
};
gb_global std::atomic<isize> global_platform_memory_total_usage;
gb_global PlatformMemoryBlock global_platform_memory_block_sentinel;
PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size);
@@ -158,10 +159,17 @@ void platform_virtual_memory_protect(void *memory, isize size);
PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size) {
PlatformMemoryBlock *pmblock = (PlatformMemoryBlock *)VirtualAlloc(0, total_size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
GB_ASSERT_MSG(pmblock != nullptr, "Out of Virtual Memory, oh no...");
if (pmblock == nullptr) {
gb_printf_err("Out of Virtual memory, oh no...\n");
gb_printf_err("Requested: %lld bytes\n", cast(long long)total_size);
gb_printf_err("Total Usage: %lld bytes\n", cast(long long)global_platform_memory_total_usage);
GB_ASSERT_MSG(pmblock != nullptr, "Out of Virtual Memory, oh no...");
}
global_platform_memory_total_usage += total_size;
return pmblock;
}
void platform_virtual_memory_free(PlatformMemoryBlock *block) {
global_platform_memory_total_usage -= block->total_size;
GB_ASSERT(VirtualFree(block, 0, MEM_RELEASE));
}
void platform_virtual_memory_protect(void *memory, isize size) {
@@ -180,11 +188,18 @@ void platform_virtual_memory_protect(void *memory, isize size);
PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size) {
PlatformMemoryBlock *pmblock = (PlatformMemoryBlock *)mmap(nullptr, total_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
GB_ASSERT_MSG(pmblock != nullptr, "Out of Virtual Memory, oh no...");
if (pmblock == nullptr) {
gb_printf_err("Out of Virtual memory, oh no...\n");
gb_printf_err("Requested: %lld bytes\n", cast(long long)total_size);
gb_printf_err("Total Usage: %lld bytes\n", cast(long long)global_platform_memory_total_usage);
GB_ASSERT_MSG(pmblock != nullptr, "Out of Virtual Memory, oh no...");
}
global_platform_memory_total_usage += total_size;
return pmblock;
}
void platform_virtual_memory_free(PlatformMemoryBlock *block) {
isize size = block->total_size;
global_platform_memory_total_usage -= size;
munmap(block, size);
}
void platform_virtual_memory_protect(void *memory, isize size) {

View File

@@ -74,6 +74,7 @@ enum EntityFlag : u64 {
EntityFlag_Test = 1ull<<30,
EntityFlag_Init = 1ull<<31,
EntityFlag_Subtype = 1ull<<32,
EntityFlag_CustomLinkName = 1ull<<40,
EntityFlag_CustomLinkage_Internal = 1ull<<41,
@@ -86,6 +87,10 @@ enum EntityFlag : u64 {
EntityFlag_Overridden = 1ull<<63,
};
enum : u64 {
EntityFlags_IsSubtype = EntityFlag_Using|EntityFlag_Subtype,
};
enum EntityState : u32 {
EntityState_Unresolved = 0,
EntityState_InProgress = 1,

View File

@@ -50,9 +50,9 @@ struct ExactValue {
union {
bool value_bool;
String value_string;
BigInt value_integer; // NOTE(bill): This must be an integer and not a pointer
BigInt value_integer;
f64 value_float;
i64 value_pointer;
i64 value_pointer; // NOTE(bill): This must be an integer and not a pointer
Complex128 *value_complex;
Quaternion256 *value_quaternion;
Ast * value_compound;
@@ -630,6 +630,9 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
case ExactValue_Bool:
case ExactValue_String:
case ExactValue_Quaternion:
case ExactValue_Pointer:
case ExactValue_Procedure:
case ExactValue_Typeid:
return;
case ExactValue_Integer:
@@ -671,9 +674,6 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
return;
}
break;
case ExactValue_Procedure:
return;
}
compiler_error("match_exact_values: How'd you get here? Invalid ExactValueKind %d", x->kind);
@@ -932,6 +932,17 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
break;
}
case ExactValue_Pointer: {
switch (op) {
case Token_CmpEq: return x.value_pointer == y.value_pointer;
case Token_NotEq: return x.value_pointer != y.value_pointer;
case Token_Lt: return x.value_pointer < y.value_pointer;
case Token_LtEq: return x.value_pointer <= y.value_pointer;
case Token_Gt: return x.value_pointer > y.value_pointer;
case Token_GtEq: return x.value_pointer >= y.value_pointer;
}
}
case ExactValue_Typeid:
switch (op) {
case Token_CmpEq: return are_types_identical(x.value_typeid, y.value_typeid);

View File

@@ -79,6 +79,10 @@ extern "C" {
#ifndef GB_SYSTEM_FREEBSD
#define GB_SYSTEM_FREEBSD 1
#endif
#elif defined(__OpenBSD__)
#ifndef GB_SYSTEM_OPENBSD
#define GB_SYSTEM_OPENBSD 1
#endif
#else
#error This UNIX operating system is not supported
#endif
@@ -199,7 +203,7 @@ extern "C" {
#endif
#include <stdlib.h> // NOTE(bill): malloc on linux
#include <sys/mman.h>
#if !defined(GB_SYSTEM_OSX) && !defined(__FreeBSD__)
#if !defined(GB_SYSTEM_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
#include <sys/sendfile.h>
#endif
#include <sys/stat.h>
@@ -235,6 +239,12 @@ extern "C" {
#define sendfile(out, in, offset, count) sendfile(out, in, offset, count, NULL, NULL, 0)
#endif
#if defined(GB_SYSTEM_OPENBSD)
#include <stdio.h>
#include <pthread_np.h>
#define lseek64 lseek
#endif
#if defined(GB_SYSTEM_UNIX)
#include <semaphore.h>
#endif
@@ -783,6 +793,13 @@ typedef struct gbAffinity {
isize thread_count;
isize threads_per_core;
} gbAffinity;
#elif defined(GB_SYSTEM_OPENBSD)
typedef struct gbAffinity {
b32 is_accurate;
isize core_count;
isize thread_count;
isize threads_per_core;
} gbAffinity;
#else
#error TODO(bill): Unknown system
#endif
@@ -3678,6 +3695,30 @@ b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) {
return true;
}
isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) {
GB_ASSERT(0 <= core && core < a->core_count);
return a->threads_per_core;
}
#elif defined(GB_SYSTEM_OPENBSD)
#include <unistd.h>
void gb_affinity_init(gbAffinity *a) {
a->core_count = sysconf(_SC_NPROCESSORS_ONLN);
a->threads_per_core = 1;
a->is_accurate = a->core_count > 0;
a->core_count = a->is_accurate ? a->core_count : 1;
a->thread_count = a->core_count;
}
void gb_affinity_destroy(gbAffinity *a) {
gb_unused(a);
}
b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) {
return true;
}
isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) {
GB_ASSERT(0 <= core && core < a->core_count);
return a->threads_per_core;
@@ -6025,7 +6066,7 @@ gbFileTime gb_file_last_write_time(char const *filepath) {
gb_inline b32 gb_file_copy(char const *existing_filename, char const *new_filename, b32 fail_if_exists) {
#if defined(GB_SYSTEM_OSX)
return copyfile(existing_filename, new_filename, NULL, COPYFILE_DATA) == 0;
#else
#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_FREEBSD)
isize size;
int existing_fd = open(existing_filename, O_RDONLY, 0);
int new_fd = open(new_filename, O_WRONLY|O_CREAT, 0666);
@@ -6041,6 +6082,49 @@ gb_inline b32 gb_file_copy(char const *existing_filename, char const *new_filena
close(new_fd);
close(existing_fd);
return size == stat_existing.st_size;
#else
int new_flags = O_WRONLY | O_CREAT;
if (fail_if_exists) {
new_flags |= O_EXCL;
}
int existing_fd = open(existing_filename, O_RDONLY, 0);
int new_fd = open(new_filename, new_flags, 0666);
struct stat stat_existing;
if (fstat(existing_fd, &stat_existing) == -1) {
return 0;
}
size_t bsize = stat_existing.st_blksize > BUFSIZ ? stat_existing.st_blksize : BUFSIZ;
char *buf = (char *)malloc(bsize);
if (buf == NULL) {
close(new_fd);
close(existing_fd);
return 0;
}
isize size = 0;
ssize_t nread, nwrite, offset;
while ((nread = read(existing_fd, buf, bsize)) != -1 && nread != 0) {
for (offset = 0; nread; nread -= nwrite, offset += nwrite) {
if ((nwrite = write(new_fd, buf + offset, nread)) == -1 || nwrite == 0) {
free(buf);
close(new_fd);
close(existing_fd);
return 0;
}
size += nwrite;
}
}
free(buf);
close(new_fd);
close(existing_fd);
if (nread == -1) {
return 0;
}
return size == stat_existing.st_size;
#endif
}
@@ -6093,6 +6177,7 @@ gbFileContents gb_file_read_contents(gbAllocator a, b32 zero_terminate, char con
}
void gb_file_free_contents(gbFileContents *fc) {
if (fc == NULL || fc->size == 0) return;
GB_ASSERT_NOT_NULL(fc->data);
gb_free(fc->allocator, fc->data);
fc->data = NULL;

View File

@@ -1295,6 +1295,11 @@ void lb_generate_code(lbGenerator *gen) {
reloc_mode = LLVMRelocPIC;
}
if (build_context.metrics.os == TargetOs_openbsd) {
// Always use PIC for OpenBSD: it defaults to PIE
reloc_mode = LLVMRelocPIC;
}
for_array(i, gen->modules.entries) {
target_machines[i] = LLVMCreateTargetMachine(
target, target_triple, llvm_cpu,

View File

@@ -962,7 +962,7 @@ void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, T
LLVMMetadataRef llvm_debug_loc = lb_debug_location_from_token_pos(p, token.pos);
LLVMMetadataRef llvm_expr = LLVMDIBuilderCreateExpression(m->debug_builder, nullptr, 0);
lb_set_llvm_metadata(m, ptr, llvm_expr);
LLVMDIBuilderInsertDbgValueAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block);
LLVMDIBuilderInsertDeclareAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block);
}

View File

@@ -2202,6 +2202,21 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri
}
}
if (is_type_matrix(a) && (op_kind == Token_CmpEq || op_kind == Token_NotEq)) {
Type *tl = base_type(a);
lbValue lhs = lb_address_from_load_or_generate_local(p, left);
lbValue rhs = lb_address_from_load_or_generate_local(p, right);
// TODO(bill): Test to see if this is actually faster!!!!
auto args = array_make<lbValue>(permanent_allocator(), 3);
args[0] = lb_emit_conv(p, lhs, t_rawptr);
args[1] = lb_emit_conv(p, rhs, t_rawptr);
args[2] = lb_const_int(p->module, t_int, type_size_of(tl));
lbValue val = lb_emit_runtime_call(p, "memory_compare", args);
lbValue res = lb_emit_comp(p, op_kind, val, lb_const_nil(p->module, val.type));
return lb_emit_conv(p, res, t_bool);
}
if (is_type_array(a) || is_type_enumerated_array(a)) {
Type *tl = base_type(a);
lbValue lhs = lb_address_from_load_or_generate_local(p, left);

View File

@@ -57,6 +57,7 @@ void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbVal
LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
}
lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) {
GB_ASSERT(entity != nullptr);
GB_ASSERT(entity->kind == Entity_Procedure);
@@ -163,14 +164,6 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
break;
}
// lbCallingConventionKind cc_kind = lbCallingConvention_C;
// // TODO(bill): Clean up this logic
// if (build_context.metrics.os != TargetOs_js) {
// cc_kind = lb_calling_convention_map[pt->Proc.calling_convention];
// }
// LLVMSetFunctionCallConv(p->value, cc_kind);
lbValue proc_value = {p->value, p->type};
lb_add_entity(m, entity, proc_value);
lb_add_member(m, p->name, proc_value);
@@ -1049,7 +1042,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
return lb_string_len(p, v);
} else if (is_type_array(t)) {
GB_PANIC("Array lengths are constant");
} else if (is_type_slice(t)) {
} else if (is_type_slice(t) || is_type_relative_slice(t)) {
return lb_slice_len(p, v);
} else if (is_type_dynamic_array(t)) {
return lb_dynamic_array_len(p, v);
@@ -1075,7 +1068,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
GB_PANIC("Unreachable");
} else if (is_type_array(t)) {
GB_PANIC("Array lengths are constant");
} else if (is_type_slice(t)) {
} else if (is_type_slice(t) || is_type_relative_slice(t)) {
return lb_slice_len(p, v);
} else if (is_type_dynamic_array(t)) {
return lb_dynamic_array_cap(p, v);
@@ -2122,6 +2115,77 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
case BuiltinProc_objc_find_class: return lb_handle_objc_find_class(p, expr);
case BuiltinProc_objc_register_selector: return lb_handle_objc_register_selector(p, expr);
case BuiltinProc_objc_register_class: return lb_handle_objc_register_class(p, expr);
case BuiltinProc_constant_utf16_cstring:
{
auto const encode_surrogate_pair = [](Rune r, u16 *r1, u16 *r2) {
if (r < 0x10000 || r > 0x10ffff) {
*r1 = 0xfffd;
*r2 = 0xfffd;
} else {
r -= 0x10000;
*r1 = 0xd800 + ((r>>10)&0x3ff);
*r2 = 0xdc00 + (r&0x3ff);
}
};
lbModule *m = p->module;
auto tav = type_and_value_of_expr(ce->args[0]);
GB_ASSERT(tav.value.kind == ExactValue_String);
String value = tav.value.value_string;
LLVMTypeRef llvm_u16 = lb_type(m, t_u16);
isize max_len = value.len*2 + 1;
LLVMValueRef *buffer = gb_alloc_array(temporary_allocator(), LLVMValueRef, max_len);
isize n = 0;
while (value.len > 0) {
Rune r = 0;
isize w = gb_utf8_decode(value.text, value.len, &r);
value.text += w;
value.len -= w;
if ((0 <= r && r < 0xd800) || (0xe000 <= r && r < 0x10000)) {
buffer[n++] = LLVMConstInt(llvm_u16, cast(u16)r, false);
} else if (0x10000 <= r && r <= 0x10ffff) {
u16 r1, r2;
encode_surrogate_pair(r, &r1, &r2);
buffer[n++] = LLVMConstInt(llvm_u16, r1, false);
buffer[n++] = LLVMConstInt(llvm_u16, r2, false);
} else {
buffer[n++] = LLVMConstInt(llvm_u16, 0xfffd, false);
}
}
buffer[n++] = LLVMConstInt(llvm_u16, 0, false);
LLVMValueRef array = LLVMConstArray(llvm_u16, buffer, cast(unsigned int)n);
char *name = nullptr;
{
isize max_len = 7+8+1;
name = gb_alloc_array(permanent_allocator(), char, max_len);
u32 id = m->gen->global_array_index.fetch_add(1);
isize len = gb_snprintf(name, max_len, "csbs$%x", id);
len -= 1;
}
LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(array), name);
LLVMSetInitializer(global_data, array);
LLVMSetLinkage(global_data, LLVMInternalLinkage);
LLVMValueRef indices[] = {
LLVMConstInt(lb_type(m, t_u32), 0, false),
LLVMConstInt(lb_type(m, t_u32), 0, false),
};
lbValue res = {};
res.type = tv.type;
res.value = LLVMBuildInBoundsGEP(p->builder, global_data, indices, gb_count_of(indices), "");
return res;
}
}
GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name));

View File

@@ -1373,7 +1373,7 @@ lbValue lb_slice_elem(lbProcedure *p, lbValue slice) {
return lb_emit_struct_ev(p, slice, 0);
}
lbValue lb_slice_len(lbProcedure *p, lbValue slice) {
GB_ASSERT(is_type_slice(slice.type));
GB_ASSERT(is_type_slice(slice.type) || is_type_relative_slice(slice.type));
return lb_emit_struct_ev(p, slice, 1);
}
lbValue lb_dynamic_array_elem(lbProcedure *p, lbValue da) {

View File

@@ -384,7 +384,7 @@ i32 linker_stage(lbGenerator *gen) {
// NOTE(zangent): Sometimes, you have to use -framework on MacOS.
// This allows you to specify '-f' in a #foreign_system_library,
// without having to implement any new syntax specifically for MacOS.
#if defined(GB_SYSTEM_OSX)
if (build_context.metrics.os == TargetOs_darwin) {
if (string_ends_with(lib, str_lit(".framework"))) {
// framework thingie
String lib_name = lib;
@@ -400,14 +400,14 @@ i32 linker_stage(lbGenerator *gen) {
// dynamic or static system lib, just link regularly searching system library paths
lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
}
#else
} else {
// NOTE(vassvik): static libraries (.a files) in linux can be linked to directly using the full path,
// since those are statically linked to at link time. shared libraries (.so) has to be
// available at runtime wherever the executable is run, so we make require those to be
// local to the executable (unless the system collection is used, in which case we search
// the system library paths for the library file).
if (string_ends_with(lib, str_lit(".a"))) {
// static libs, absolute full path relative to the file in which the lib was imported from
if (string_ends_with(lib, str_lit(".a")) || string_ends_with(lib, str_lit(".o"))) {
// static libs and object files, absolute full path relative to the file in which the lib was imported from
lib_str = gb_string_append_fmt(lib_str, " -l:\"%.*s\" ", LIT(lib));
} else if (string_ends_with(lib, str_lit(".so"))) {
// dynamic lib, relative path to executable
@@ -418,7 +418,7 @@ i32 linker_stage(lbGenerator *gen) {
// dynamic or static system lib, just link regularly searching system library paths
lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
}
#endif
}
}
gbString object_files = gb_string_make(heap_allocator(), "");
@@ -456,14 +456,15 @@ i32 linker_stage(lbGenerator *gen) {
// line arguments prepared previously are incompatible with ld.
//
// Shared libraries are .dylib on MacOS and .so on Linux.
#if defined(GB_SYSTEM_OSX)
if (build_context.metrics.os == TargetOs_darwin) {
output_ext = STR_LIT(".dylib");
#else
} else {
output_ext = STR_LIT(".so");
#endif
}
link_settings = gb_string_appendc(link_settings, "-Wl,-init,'_odin_entry_point' ");
link_settings = gb_string_appendc(link_settings, "-Wl,-fini,'_odin_exit_point' ");
} else {
} else if (build_context.metrics.os != TargetOs_openbsd) {
// OpenBSD defaults to PIE executable. do not pass -no-pie for it.
link_settings = gb_string_appendc(link_settings, "-no-pie ");
}
if (build_context.out_filepath.len > 0) {
@@ -474,34 +475,39 @@ i32 linker_stage(lbGenerator *gen) {
}
}
result = system_exec_command_line_app("ld-link",
"clang -Wno-unused-command-line-argument %s -o \"%.*s%.*s\" %s "
" %s "
" %.*s "
" %.*s "
" %s "
#if defined(GB_SYSTEM_OSX)
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
// make sure to also change the 'mtriple' param passed to 'opt'
#if defined(GB_CPU_ARM)
" -mmacosx-version-min=12.0.0 "
#else
" -mmacosx-version-min=10.8.0 "
#endif
// This points the linker to where the entry point is
" -e _main "
#endif
, object_files, LIT(output_base), LIT(output_ext),
#if defined(GB_SYSTEM_OSX)
"-lSystem -lm -Wl,-syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib",
#else
"-lc -lm",
#endif
lib_str,
LIT(build_context.link_flags),
LIT(build_context.extra_linker_flags),
link_settings);
gbString platform_lib_str = gb_string_make(heap_allocator(), "");
defer (gb_string_free(platform_lib_str));
if (build_context.metrics.os == TargetOs_darwin) {
platform_lib_str = gb_string_appendc(platform_lib_str, "-lSystem -lm -Wl,-syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib");
} else {
platform_lib_str = gb_string_appendc(platform_lib_str, "-lc -lm");
}
if (build_context.metrics.os == TargetOs_darwin) {
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
// make sure to also change the 'mtriple' param passed to 'opt'
if (build_context.metrics.arch == TargetArch_arm64) {
link_settings = gb_string_appendc(link_settings, " -mmacosx-version-min=12.0.0 ");
} else {
link_settings = gb_string_appendc(link_settings, " -mmacosx-version-min=10.8.0 ");
}
// This points the linker to where the entry point is
link_settings = gb_string_appendc(link_settings, " -e _main ");
}
gbString link_command_line = gb_string_make(heap_allocator(), "clang -Wno-unused-command-line-argument ");
defer (gb_string_free(link_command_line));
link_command_line = gb_string_appendc(link_command_line, object_files);
link_command_line = gb_string_append_fmt(link_command_line, " -o \"%.*s%.*s\" ", LIT(output_base), LIT(output_ext));
link_command_line = gb_string_append_fmt(link_command_line, " %s ", platform_lib_str);
link_command_line = gb_string_append_fmt(link_command_line, " %s ", lib_str);
link_command_line = gb_string_append_fmt(link_command_line, " %.*s ", LIT(build_context.link_flags));
link_command_line = gb_string_append_fmt(link_command_line, " %.*s ", LIT(build_context.extra_linker_flags));
link_command_line = gb_string_append_fmt(link_command_line, " %s ", link_settings);
result = system_exec_command_line_app("ld-link", link_command_line);
if (result) {
return result;
@@ -572,14 +578,16 @@ void usage(String argv0) {
print_usage_line(0, "Usage:");
print_usage_line(1, "%.*s command [arguments]", LIT(argv0));
print_usage_line(0, "Commands:");
print_usage_line(1, "build compile .odin file, or directory of .odin files, as an executable.");
print_usage_line(1, " one must contain the program's entry point, all must be in the same package.");
print_usage_line(1, "run same as 'build', but also then runs the newly compiled executable.");
print_usage_line(1, "check parse and type check .odin file");
print_usage_line(1, "query parse, type check, and output a .json file containing information about the program");
print_usage_line(1, "doc generate documentation .odin file, or directory of .odin files");
print_usage_line(1, "version print version");
print_usage_line(1, "report print information useful to reporting a bug");
print_usage_line(1, "build compile .odin file, or directory of .odin files, as an executable.");
print_usage_line(1, " one must contain the program's entry point, all must be in the same package.");
print_usage_line(1, "run same as 'build', but also then runs the newly compiled executable.");
print_usage_line(1, "check parse, and type check an .odin file, or directory of .odin files");
print_usage_line(1, "query parse, type check, and output a .json file containing information about the program");
print_usage_line(1, "strip-semicolon parse, type check, and remove unneeded semicolons from the entire program");
print_usage_line(1, "test build ands runs procedures with the attribute @(test) in the initial package");
print_usage_line(1, "doc generate documentation .odin file, or directory of .odin files");
print_usage_line(1, "version print version");
print_usage_line(1, "report print information useful to reporting a bug");
print_usage_line(0, "");
print_usage_line(0, "For further details on a command, use -help after the command name");
print_usage_line(1, "e.g. odin build -help");
@@ -2577,7 +2585,7 @@ int main(int arg_count, char const **arg_ptr) {
// NOTE(bill): add 'shared' directory if it is not already set
if (!find_library_collection_path(str_lit("shared"), nullptr)) {
add_library_collection(str_lit("shared"),
get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("shared")));
get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("shared")));
}

View File

@@ -57,6 +57,9 @@ isize ast_node_size(AstKind kind) {
return align_formula_isize(gb_size_of(AstCommonStuff) + ast_variant_sizes[kind], gb_align_of(void *));
}
gb_global std::atomic<isize> global_total_node_memory_allocated;
// NOTE(bill): And this below is why is I/we need a new language! Discriminated unions are a pain in C/C++
Ast *alloc_ast_node(AstFile *f, AstKind kind) {
gbAllocator a = ast_allocator(f);
@@ -66,6 +69,9 @@ Ast *alloc_ast_node(AstFile *f, AstKind kind) {
Ast *node = cast(Ast *)gb_alloc(a, size);
node->kind = kind;
node->file_id = f ? f->id : 0;
global_total_node_memory_allocated += size;
return node;
}
@@ -1532,7 +1538,7 @@ void fix_advance_to_next_stmt(AstFile *f) {
Token expect_closing(AstFile *f, TokenKind kind, String context) {
if (f->curr_token.kind != kind &&
f->curr_token.kind == Token_Semicolon &&
f->curr_token.string == "\n") {
(f->curr_token.string == "\n" || f->curr_token.kind == Token_EOF)) {
Token tok = f->prev_token;
tok.pos.column += cast(i32)tok.string.len;
syntax_error(tok, "Missing ',' before newline in %.*s", LIT(context));
@@ -1554,6 +1560,7 @@ void assign_removal_flag_to_semicolon(AstFile *f) {
switch (curr_token->kind) {
case Token_CloseBrace:
case Token_CloseParen:
case Token_EOF:
ok = true;
break;
}
@@ -3009,64 +3016,62 @@ i32 token_precedence(AstFile *f, TokenKind t) {
Ast *parse_binary_expr(AstFile *f, bool lhs, i32 prec_in) {
Ast *expr = parse_unary_expr(f, lhs);
for (i32 prec = token_precedence(f, f->curr_token.kind); prec >= prec_in; prec--) {
for (;;) {
Token op = f->curr_token;
i32 op_prec = token_precedence(f, op.kind);
if (op_prec != prec) {
// NOTE(bill): This will also catch operators that are not valid "binary" operators
break;
for (;;) {
Token op = f->curr_token;
i32 op_prec = token_precedence(f, op.kind);
if (op_prec < prec_in) {
// NOTE(bill): This will also catch operators that are not valid "binary" operators
break;
}
Token prev = f->prev_token;
switch (op.kind) {
case Token_if:
case Token_when:
if (prev.pos.line < op.pos.line) {
// NOTE(bill): Check to see if the `if` or `when` is on the same line of the `lhs` condition
goto loop_end;
}
Token prev = f->prev_token;
break;
}
expect_operator(f); // NOTE(bill): error checks too
if (op.kind == Token_Question) {
Ast *cond = expr;
// Token_Question
Ast *x = parse_expr(f, lhs);
Token token_c = expect_token(f, Token_Colon);
Ast *y = parse_expr(f, lhs);
expr = ast_ternary_if_expr(f, x, cond, y);
} else if (op.kind == Token_if || op.kind == Token_when) {
Ast *x = expr;
Ast *cond = parse_expr(f, lhs);
Token tok_else = expect_token(f, Token_else);
Ast *y = parse_expr(f, lhs);
switch (op.kind) {
case Token_if:
expr = ast_ternary_if_expr(f, x, cond, y);
break;
case Token_when:
if (prev.pos.line < op.pos.line) {
// NOTE(bill): Check to see if the `if` or `when` is on the same line of the `lhs` condition
goto loop_end;
}
expr = ast_ternary_when_expr(f, x, cond, y);
break;
}
expect_operator(f); // NOTE(bill): error checks too
if (op.kind == Token_Question) {
Ast *cond = expr;
// Token_Question
Ast *x = parse_expr(f, lhs);
Token token_c = expect_token(f, Token_Colon);
Ast *y = parse_expr(f, lhs);
expr = ast_ternary_if_expr(f, x, cond, y);
} else if (op.kind == Token_if || op.kind == Token_when) {
Ast *x = expr;
Ast *cond = parse_expr(f, lhs);
Token tok_else = expect_token(f, Token_else);
Ast *y = parse_expr(f, lhs);
switch (op.kind) {
case Token_if:
expr = ast_ternary_if_expr(f, x, cond, y);
break;
case Token_when:
expr = ast_ternary_when_expr(f, x, cond, y);
break;
}
} else {
Ast *right = parse_binary_expr(f, false, prec+1);
if (right == nullptr) {
syntax_error(op, "Expected expression on the right-hand side of the binary operator '%.*s'", LIT(op.string));
}
if (op.kind == Token_or_else) {
// NOTE(bill): easier to handle its logic different with its own AST kind
expr = ast_or_else_expr(f, expr, op, right);
} else {
expr = ast_binary_expr(f, op, expr, right);
}
} else {
Ast *right = parse_binary_expr(f, false, op_prec+1);
if (right == nullptr) {
syntax_error(op, "Expected expression on the right-hand side of the binary operator '%.*s'", LIT(op.string));
}
if (op.kind == Token_or_else) {
// NOTE(bill): easier to handle its logic different with its own AST kind
expr = ast_or_else_expr(f, expr, op, right);
} else {
expr = ast_binary_expr(f, op, expr, right);
}
lhs = false;
}
loop_end:;
lhs = false;
}
loop_end:;
return expr;
}
@@ -3510,12 +3515,13 @@ enum FieldPrefixKind : i32 {
FieldPrefix_Unknown = -1,
FieldPrefix_Invalid = 0,
FieldPrefix_using,
FieldPrefix_using, // implies #subtype
FieldPrefix_const,
FieldPrefix_no_alias,
FieldPrefix_c_vararg,
FieldPrefix_auto_cast,
FieldPrefix_any_int,
FieldPrefix_subtype, // does not imply `using` semantics
};
struct ParseFieldPrefixMapping {
@@ -3532,6 +3538,7 @@ gb_global ParseFieldPrefixMapping parse_field_prefix_mappings[] = {
{str_lit("c_vararg"), Token_Hash, FieldPrefix_c_vararg, FieldFlag_c_vararg},
{str_lit("const"), Token_Hash, FieldPrefix_const, FieldFlag_const},
{str_lit("any_int"), Token_Hash, FieldPrefix_any_int, FieldFlag_any_int},
{str_lit("subtype"), Token_Hash, FieldPrefix_subtype, FieldFlag_subtype},
};
@@ -4849,12 +4856,6 @@ ParseFileError init_ast_file(AstFile *f, String fullpath, TokenPos *err_pos) {
f->prev_token = f->tokens[f->prev_token_index];
f->curr_token = f->tokens[f->curr_token_index];
isize const page_size = 4*1024;
isize block_size = 2*f->tokens.count*gb_size_of(Ast);
block_size = ((block_size + page_size-1)/page_size) * page_size;
block_size = gb_clamp(block_size, page_size, DEFAULT_MINIMUM_BLOCK_SIZE);
f->arena.minimum_block_size = block_size;
array_init(&f->comments, heap_allocator(), 0, 0);
array_init(&f->imports, heap_allocator(), 0, 0);
@@ -5719,6 +5720,22 @@ ParseFileError parse_packages(Parser *p, String init_filename) {
error_line("Expected either a directory or a .odin file, got '%.*s'\n", LIT(init_filename));
return ParseFile_WrongExtension;
}
} else if (init_fullpath.len != 0) {
String path = init_fullpath;
if (path[path.len-1] == '/') {
path.len -= 1;
}
if ((build_context.command_kind & Command__does_build) &&
build_context.build_mode == BuildMode_Executable) {
String short_path = filename_from_path(path);
char *cpath = alloc_cstring(heap_allocator(), short_path);
defer (gb_free(heap_allocator(), cpath));
if (gb_file_exists(cpath)) {
error_line("Please specify the executable name with -out:<string> as a directory exists with the same name in the current working directory");
return ParseFile_DirectoryAlreadyExists;
}
}
}

View File

@@ -46,6 +46,7 @@ enum ParseFileError {
ParseFile_InvalidToken,
ParseFile_GeneralError,
ParseFile_FileTooLarge,
ParseFile_DirectoryAlreadyExists,
ParseFile_Count,
};
@@ -97,8 +98,6 @@ struct AstFile {
AstPackage * pkg;
Scope * scope;
Arena arena;
Ast * pkg_decl;
String fullpath;
Tokenizer tokenizer;
@@ -300,6 +299,7 @@ enum FieldFlag : u32 {
FieldFlag_auto_cast = 1<<4,
FieldFlag_const = 1<<5,
FieldFlag_any_int = 1<<6,
FieldFlag_subtype = 1<<7,
// Internal use by the parser only
FieldFlag_Tags = 1<<10,
@@ -307,7 +307,7 @@ enum FieldFlag : u32 {
// Parameter List Restrictions
FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast|FieldFlag_const|FieldFlag_any_int,
FieldFlag_Struct = FieldFlag_using|FieldFlag_Tags,
FieldFlag_Struct = FieldFlag_using|FieldFlag_subtype|FieldFlag_Tags,
};
enum StmtAllowFlag {
@@ -800,10 +800,10 @@ gb_inline bool is_ast_when_stmt(Ast *node) {
return node->kind == Ast_WhenStmt;
}
gb_global gb_thread_local Arena global_ast_arena = {};
gb_global gb_thread_local Arena global_thread_local_ast_arena = {};
gbAllocator ast_allocator(AstFile *f) {
Arena *arena = f ? &f->arena : &global_ast_arena;
Arena *arena = &global_thread_local_ast_arena;
return arena_allocator(arena);
}

View File

@@ -486,7 +486,7 @@ void thread_set_name(Thread *t, char const *name) {
#elif defined(GB_SYSTEM_OSX)
// TODO(bill): Test if this works
pthread_setname_np(name);
#elif defined(GB_SYSTEM_FREEBSD)
#elif defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD)
pthread_set_name_np(t->posix_handle, name);
#else
// TODO(bill): Test if this works

View File

@@ -703,7 +703,7 @@ struct TypePath;
i64 type_size_of (Type *t);
i64 type_align_of (Type *t);
i64 type_offset_of (Type *t, i32 index);
gbString type_to_string (Type *type);
gbString type_to_string (Type *type, bool shorthand=false);
i64 type_size_of_internal(Type *t, TypePath *path);
void init_map_internal_types(Type *type);
Type * bit_set_to_int(Type *t);
@@ -2334,7 +2334,7 @@ String lookup_subtype_polymorphic_field(Type *dst, Type *src) {
GB_ASSERT(is_type_struct(src) || is_type_union(src));
for_array(i, src->Struct.fields) {
Entity *f = src->Struct.fields[i];
if (f->kind == Entity_Variable && f->flags & EntityFlag_Using) {
if (f->kind == Entity_Variable && f->flags & EntityFlags_IsSubtype) {
if (are_types_identical(dst, f->type)) {
return f->token.string;
}
@@ -2343,7 +2343,7 @@ String lookup_subtype_polymorphic_field(Type *dst, Type *src) {
return f->token.string;
}
}
if (is_type_struct(f->type)) {
if ((f->flags & EntityFlag_Using) != 0 && is_type_struct(f->type)) {
String name = lookup_subtype_polymorphic_field(dst, f->type);
if (name.len > 0) {
return name;
@@ -2489,9 +2489,9 @@ bool are_types_identical_internal(Type *x, Type *y, bool check_tuple_names) {
if (xf->token.string != yf->token.string) {
return false;
}
bool xf_is_using = (xf->flags&EntityFlag_Using) != 0;
bool yf_is_using = (yf->flags&EntityFlag_Using) != 0;
if (xf_is_using ^ yf_is_using) {
u64 xf_flags = (xf->flags&EntityFlags_IsSubtype);
u64 yf_flags = (yf->flags&EntityFlags_IsSubtype);
if (xf_flags != yf_flags) {
return false;
}
}
@@ -2623,6 +2623,17 @@ i64 union_tag_size(Type *u) {
// TODO(bill): Is this an okay approach?
i64 max_align = 1;
if (u->Union.variants.count < 1ull<<8) {
max_align = 1;
} else if (u->Union.variants.count < 1ull<<16) {
max_align = 2;
} else if (u->Union.variants.count < 1ull<<32) {
max_align = 4;
} else {
GB_PANIC("how many variants do you have?!");
}
for_array(i, u->Union.variants) {
Type *variant_type = u->Union.variants[i];
i64 align = type_align_of(variant_type);
@@ -3813,7 +3824,7 @@ isize check_is_assignable_to_using_subtype(Type *src, Type *dst, isize level = 0
for_array(i, src->Struct.fields) {
Entity *f = src->Struct.fields[i];
if (f->kind != Entity_Variable || (f->flags&EntityFlag_Using) == 0) {
if (f->kind != Entity_Variable || (f->flags&EntityFlags_IsSubtype) == 0) {
continue;
}
@@ -3925,7 +3936,7 @@ Type *alloc_type_proc_from_types(Type **param_types, unsigned param_count, Type
gbString write_type_to_string(gbString str, Type *type) {
gbString write_type_to_string(gbString str, Type *type, bool shorthand=false) {
if (type == nullptr) {
return gb_string_appendc(str, "<no type>");
}
@@ -4040,15 +4051,21 @@ gbString write_type_to_string(gbString str, Type *type) {
if (type->Struct.is_raw_union) str = gb_string_appendc(str, " #raw_union");
if (type->Struct.custom_align != 0) str = gb_string_append_fmt(str, " #align %d", cast(int)type->Struct.custom_align);
str = gb_string_appendc(str, " {");
for_array(i, type->Struct.fields) {
Entity *f = type->Struct.fields[i];
GB_ASSERT(f->kind == Entity_Variable);
if (i > 0) {
str = gb_string_appendc(str, ", ");
if (shorthand && type->Struct.fields.count > 16) {
str = gb_string_append_fmt(str, "%lld fields...", cast(long long)type->Struct.fields.count);
} else {
for_array(i, type->Struct.fields) {
Entity *f = type->Struct.fields[i];
GB_ASSERT(f->kind == Entity_Variable);
if (i > 0) {
str = gb_string_appendc(str, ", ");
}
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
str = gb_string_appendc(str, ": ");
str = write_type_to_string(str, f->type);
}
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
str = gb_string_appendc(str, ": ");
str = write_type_to_string(str, f->type);
}
str = gb_string_append_rune(str, '}');
} break;
@@ -4223,13 +4240,16 @@ gbString write_type_to_string(gbString str, Type *type) {
}
gbString type_to_string(Type *type, gbAllocator allocator) {
return write_type_to_string(gb_string_make(allocator, ""), type);
gbString type_to_string(Type *type, gbAllocator allocator, bool shorthand=false) {
return write_type_to_string(gb_string_make(allocator, ""), type, shorthand);
}
gbString type_to_string(Type *type) {
return write_type_to_string(gb_string_make(heap_allocator(), ""), type);
gbString type_to_string(Type *type, bool shorthand) {
return write_type_to_string(gb_string_make(heap_allocator(), ""), type, shorthand);
}
gbString type_to_string_shorthand(Type *type) {
return type_to_string(type, true);
}