Merge branch 'odin-lang:master' into master

This commit is contained in:
Maurice Elliott
2026-06-27 23:13:23 +01:00
committed by GitHub
80 changed files with 2064 additions and 918 deletions

View File

@@ -449,6 +449,20 @@ gb_internal void array_unordered_remove(Array<T> *array, isize index) {
array_pop(array);
}
template <typename T>
gb_internal void array_inject_at(Array<T> *array, isize index, T value) {
GB_ASSERT(0 <= index);
isize n = gb_max(array->count, index);
isize new_size = n+1;
array_resize(array, new_size);
gb_memmove(array->data+index+1, array->data+index, gb_size_of(T)*(array->count-index-1));
array->data[index] = value;
}
template <typename T>

View File

@@ -432,6 +432,14 @@ gb_internal void big_int_rem(BigInt *z, BigInt const *x, BigInt const *y) {
big_int_quo_rem(x, y, &q, z);
big_int_dealloc(&q);
}
gb_internal void big_int_mod_mod(BigInt *z, BigInt const *x, BigInt const *y) {
BigInt q = {};
big_int_rem(&q, x, y);
big_int_add(&q, &q, y);
big_int_rem(z, &q, y);
big_int_dealloc(&q);
}
gb_internal void big_int_euclidean_mod(BigInt *z, BigInt const *x, BigInt const *y) {
BigInt y0 = {};

View File

@@ -617,6 +617,10 @@ struct BuildContext {
isize max_error_count;
bool bedrock;
bool disable_non_constant_globals;
bool disable_init_fini;
u32 cmd_doc_flags;
Array<String> extra_packages;
@@ -1858,8 +1862,10 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
bc->no_entry_point = true;
} else {
if (bc->no_rtti) {
gb_printf_err("-no-rtti is only allowed on freestanding targets\n");
gb_exit(1);
if (!bc->bedrock) {
gb_printf_err("-no-rtti is only allowed on freestanding targets or '-bedrock'\n");
gb_exit(1);
}
}
}

View File

@@ -7789,6 +7789,28 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
break;
case BuiltinProc_type_proc_calling_convention:
if (operand->mode != Addressing_Type || !is_type_proc(operand->type)) {
error(operand->expr, "Expected a procedure type for '%.*s'", LIT(builtin_name));
return false;
} else {
if (is_type_polymorphic(operand->type)) {
error(operand->expr, "Expected a non-polymorphic procedure type for '%.*s'", LIT(builtin_name));
return false;
}
Type *pt = base_type(operand->type);
GB_ASSERT(pt->kind == Type_Proc);
ProcCallingConvention cc = pt->Proc.calling_convention;
operand->mode = Addressing_Constant;
operand->type = t_odin_calling_convention;
operand->value = exact_value_i64(cc);
}
break;
case BuiltinProc_type_polymorphic_record_parameter_count:
operand->value = exact_value_i64(0);
if (operand->mode != Addressing_Type) {
@@ -8249,7 +8271,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
Ast *call_expr = unparen_expr(ce->args[0]);
Operand op = {};
check_expr_base(c, &op, ce->args[0], nullptr);
if (op.mode != Addressing_Value && !(call_expr && call_expr->kind == Ast_CallExpr)) {
if (op.mode != Addressing_Value || call_expr == nullptr || call_expr->kind != Ast_CallExpr) {
error(ce->args[0], "Expected a call expression for '%.*s'", LIT(builtin_name));
return false;
}

View File

@@ -1334,6 +1334,10 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
e->flags |= EntityFlag_Fini;
}
if (build_context.disable_init_fini && (e->flags & (EntityFlag_Init|EntityFlag_Fini))) {
error(e->token, "@(init) and @(fini) have been disabled with '-disable-init-fini'");
}
if (ac.set_cold) {
e->flags |= EntityFlag_Cold;
}
@@ -1530,10 +1534,26 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
error(e->token, "Procedure type of 'main' was expected to be 'proc()', got %s", str);
gb_string_free(str);
}
if (pt->calling_convention != default_calling_convention()) {
error(e->token, "Procedure 'main' cannot have a custom calling convention");
if (build_context.bedrock) {
switch (pt->calling_convention) {
case ProcCC_Odin:
case ProcCC_Contextless:
// Okay
break;
default:
error(e->token, "Procedure 'main' cannot have a custom calling convention beyond \"odin\" and \"contextless\" with '-bedrock'");
pt->calling_convention = ProcCC_Odin;
break;
}
} else {
if (pt->calling_convention != default_calling_convention()) {
error(e->token, "Procedure 'main' cannot have a custom calling convention");
}
pt->calling_convention = default_calling_convention();
}
pt->calling_convention = default_calling_convention();
if (e->pkg->kind == Package_Init) {
if (ctx->info->entry_point != nullptr) {
error(e->token, "Redeclaration of the entry pointer procedure 'main'");
@@ -1829,9 +1849,25 @@ gb_internal void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, D
PtrSet<Entity *> entity_set = {};
ptr_set_init(&entity_set, 2*pg->args.count);
for (Ast *arg : pg->args) {
for (Ast *arg_ : pg->args) {
Ast *arg = arg_;
Entity *e = nullptr;
Operand o = {};
if (arg->kind == Ast_BinaryExpr && arg->BinaryExpr.op.kind == Token_where) {
Ast *cond_expr = arg->BinaryExpr.right;
Operand cond = {};
check_expr(ctx, &cond, cond_expr);
if (cond.mode != Addressing_Invalid) {
if (cond.mode != Addressing_Constant || !is_type_boolean(cond.type) || cond.value.kind != ExactValue_Bool) {
error(arg, "Expected a constant binary expression for the 'where' clause");
} else if (!cond.value.value_bool) {
continue;
}
}
arg = arg->BinaryExpr.left;
}
if (arg->kind == Ast_Ident) {
e = check_ident(ctx, &o, arg, nullptr, nullptr, true);
} else if (arg->kind == Ast_SelectorExpr) {

View File

@@ -6595,11 +6595,16 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
positional_operand_count = gb_min(positional_operands.count, pt->variadic_index);
} else if (positional_operand_count > pt->param_count) {
err = CallArgumentError_TooManyArguments;
char const *err_fmt = "Too many arguments for '%s', expected %td arguments, got %td";
if (show_error) {
gbString proc_str = expr_to_string(ce->proc);
defer (gb_string_free(proc_str));
error(call, err_fmt, proc_str, param_count_excluding_defaults, positional_operands.count);
if (param_count_excluding_defaults != pt->param_count) {
char const *err_fmt = "Too many arguments for '%s', expected %td..=%td arguments, got %td";
error(call, err_fmt, proc_str, param_count_excluding_defaults, pt->param_count, positional_operands.count);
} else {
char const *err_fmt = "Too many arguments for '%s', expected %td arguments, got %td";
error(call, err_fmt, proc_str, pt->param_count, positional_operands.count);
}
}
return err;
}
@@ -7835,7 +7840,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
break;
}
}
if (all_the_same) {
if (all_the_same && first_results != nullptr) {
GB_ASSERT_MSG(is_type_tuple(first_results), "%s", type_to_string(first_results));
data.result_type = first_results;
}

View File

@@ -1476,6 +1476,14 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_
return;
}
if (switch_kind == TypeSwitch_Union) {
if (is_addressed) {
if (x.mode != Addressing_Variable && !is_type_pointer(x.type)) {
error(lhs->Ident.token, "The element variable '%.*s' cannot be made addressable", LIT(lhs->Ident.token.string));
}
}
}
Ast *nil_seen = nullptr;
TypeSet seen = {};

View File

@@ -3068,6 +3068,10 @@ gb_internal void check_map_type(CheckerContext *ctx, Type *type, Ast *node) {
init_core_map_type(ctx->checker);
init_map_internal_types(type);
if (build_context.bedrock) {
error(node, "'map' is not a valid type when using '-bedrock'");
}
}
gb_internal void check_matrix_type(CheckerContext *ctx, Type **type, Ast *node) {
@@ -3807,6 +3811,7 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
*type = alloc_type_dynamic_array(elem);
}
set_base_type(named_type, *type);
return true;
case_end;

View File

@@ -1121,6 +1121,14 @@ gb_internal void init_universal(void) {
// Types
for (isize i = 0; i < gb_count_of(basic_types); i++) {
String const &name = basic_types[i].Basic.name;
if (build_context.bedrock) {
if ((basic_types[i].Basic.flags & BasicFlag_Integer) != 0 &&
basic_types[i].Basic.size == 16) {
// disallow 128-bit integers
continue;
}
}
add_global_type_entity(name, &basic_types[i]);
}
add_global_type_entity(str_lit("byte"), &basic_types[Basic_u8]);
@@ -1147,6 +1155,8 @@ gb_internal void init_universal(void) {
add_global_string_constant("ODIN_ROOT", bc->ODIN_ROOT);
add_global_string_constant("ODIN_BUILD_PROJECT_NAME", bc->ODIN_BUILD_PROJECT_NAME);
add_global_bool_constant("ODIN_BEDROCK", bc->bedrock);
{
GlobalEnumValue values[Windows_Subsystem_COUNT] = {
{"Unknown", Windows_Subsystem_UNKNOWN},
@@ -1303,6 +1313,32 @@ gb_internal void init_universal(void) {
scope_insert(intrinsics_pkg->scope, t_atomic_memory_order->Named.type_name);
}
{
GlobalEnumValue values[ProcCC_MAX] = {
{"Invalid", ProcCC_Invalid},
{"Odin", ProcCC_Odin},
{"Contextless", ProcCC_Contextless},
{"CDecl", ProcCC_CDecl},
{"Std_Call", ProcCC_StdCall},
{"Fast_Call", ProcCC_FastCall},
{"None", ProcCC_None},
{"Naked", ProcCC_Naked},
{"_", ProcCC_InlineAsm},
{"Win64", ProcCC_Win64},
{"SysV", ProcCC_SysV},
{"PreserveNone", ProcCC_PreserveNone},
{"PreserveMost", ProcCC_PreserveMost},
{"PreserveAll", ProcCC_PreserveAll},
};
auto fields = add_global_enum_type(str_lit("Odin_Calling_Convention"), values, gb_count_of(values), &t_odin_calling_convention, t_u8);
add_global_enum_constant(fields, "ODIN_DEFAULT_CALLING_CONVENTION", default_calling_convention());
}
{
int minimum_os_version = 0;
if (build_context.minimum_os_version_string != "") {
@@ -7670,6 +7706,14 @@ gb_internal void check_parsed_files(Checker *c) {
Type *t = &basic_types[i];
if (t->Basic.size > 0 &&
(t->Basic.flags & BasicFlag_LLVM) == 0) {
if (build_context.bedrock) {
if ((t->Basic.flags & BasicFlag_Integer) != 0 &&
t->Basic.size == 16) {
// disallow 128-bit integers
continue;
}
}
add_type_info_type(&c->builtin_ctx, t);
}
}

View File

@@ -353,6 +353,8 @@ BuiltinProc__type_simple_boolean_end,
BuiltinProc_type_proc_parameter_type,
BuiltinProc_type_proc_return_type,
BuiltinProc_type_proc_calling_convention,
BuiltinProc_type_polymorphic_record_parameter_count,
BuiltinProc_type_polymorphic_record_parameter_value,
@@ -754,6 +756,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("type_proc_parameter_type"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_proc_return_type"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_proc_calling_convention"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_polymorphic_record_parameter_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_polymorphic_record_parameter_value"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},

View File

@@ -780,7 +780,7 @@ gb_internal ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, E
case Token_Quo: return exact_value_float(fmod(big_int_to_f64(a), big_int_to_f64(b)));
case Token_QuoEq: big_int_quo(&c, a, b); break; // NOTE(bill): Integer division
case Token_Mod: big_int_rem(&c, a, b); break;
case Token_ModMod: big_int_euclidean_mod(&c, a, b); break;
case Token_ModMod: big_int_mod_mod(&c, a, b); break;
case Token_And: big_int_and(&c, a, b); break;
case Token_Or: big_int_or(&c, a, b); break;
case Token_Xor: big_int_xor(&c, a, b); break;

View File

@@ -2493,7 +2493,13 @@ extern "C" {
#pragma warning(disable:4127) // Conditional expression is constant
#endif
gb_internal void print_all_errors(void);
gb_internal bool any_errors(void);
gb_internal bool any_warnings(void);
void gb_assert_handler(char const *prefix, char const *condition, char const *file, i32 line, char const *msg, ...) {
if (any_errors() || any_warnings()) {
print_all_errors();
}
gb_printf_err("%s(%d): %s: ", file, line, prefix);
if (condition)
gb_printf_err( "`%s` ", condition);

View File

@@ -1346,12 +1346,12 @@ String lb_get_objc_type_encoding(Type *t, isize pointer_depth = 0) {
s = gb_string_append_length(s, "=", 1);
if (!is_union) {
for( auto& f : base->Struct.fields ) {
for (auto &f : base->Struct.fields) {
String field_type = lb_get_objc_type_encoding(f->type, pointer_depth);
s = gb_string_append_length(s, field_type.text, field_type.len);
}
} else {
for( auto& v : base->Union.variants ) {
for (auto &v : base->Union.variants) {
String variant_type = lb_get_objc_type_encoding(v, pointer_depth);
s = gb_string_append_length(s, variant_type.text, variant_type.len);
}
@@ -1518,7 +1518,7 @@ gb_internal void lb_register_objc_thing(
auto &tn = g.class_impl_type->Named.type_name->TypeName;
Type *superclass = tn.objc_superclass;
if (superclass != nullptr) {
auto& superclass_global = string_map_must_get(&class_map, superclass->Named.type_name->TypeName.objc_class_name);
auto &superclass_global = string_map_must_get(&class_map, superclass->Named.type_name->TypeName.objc_class_name);
lb_register_objc_thing(handled, m, args, class_impls, class_map, p, superclass_global.g, call);
GB_ASSERT(superclass_global.class_global.addr.value);
}
@@ -1571,6 +1571,7 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
for (Entity *e = {}; mpsc_dequeue(&gen->info->objc_class_implementations, &e); /**/) {
GB_ASSERT(e->kind == Entity_TypeName && e->TypeName.objc_is_implementation);
lb_handle_objc_find_or_register_class(p, e->TypeName.objc_class_name, e->type);
error(e->token, "Objective-C related things are not allowed with '-bedrock'");
}
// Ensure classes that have been implicitly referenced through
@@ -1595,12 +1596,18 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
}
for (auto pair : class_set) {
auto& tn = pair.type->Named.type_name->TypeName;
Entity *e = pair.type->Named.type_name;
GB_ASSERT(e->kind == Entity_TypeName);
auto &tn = e->TypeName;
Type *class_impl = !tn.objc_is_implementation ? nullptr : pair.type;
lb_handle_objc_find_or_register_class(p, tn.objc_class_name, class_impl);
if (build_context.bedrock) {
error(e->token, "Objective-C related things are not allowed with '-bedrock'");
}
}
for (lbObjCGlobal g = {}; mpsc_dequeue(&gen->objc_classes, &g); /**/) {
array_add( &referenced_classes, g );
array_add(&referenced_classes, g);
}
// Add all class globals to a map so that we can look them up dynamically
@@ -1618,21 +1625,21 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
lb_begin_procedure_body(p);
// Register class globals, gathering classes that must be implemented
for (auto& kv : global_class_map) {
for (auto &kv : global_class_map) {
lb_register_objc_thing(handled, m, args, class_impls, global_class_map, p, kv.value.g, "objc_lookUpClass");
}
// Prefetch selectors for implemented methods so that they can also be registered.
for (const auto& cd : class_impls) {
auto& g = cd.g;
for (auto const &cd : class_impls) {
auto &g = cd.g;
Type *class_type = g.class_impl_type;
Array<ObjcMethodData>* methods = map_get(&m->info->objc_method_implementations, class_type);
Array<ObjcMethodData> *methods = map_get(&m->info->objc_method_implementations, class_type);
if (!methods) {
continue;
}
for (const ObjcMethodData& md : *methods) {
for (ObjcMethodData const &md : *methods) {
lb_handle_objc_find_or_register_selector(p, md.ac.objc_selector);
}
}
@@ -1655,11 +1662,17 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
map_set(&ivar_map, g.class_impl_type, g);
}
for (const auto &cd : class_impls) {
for (auto const &cd : class_impls) {
auto &g = cd.g;
Type *class_type = g.class_impl_type;
Type *class_ptr_type = alloc_type_pointer(class_type);
Entity *e = class_type->Named.type_name;
GB_ASSERT(e->kind == Entity_TypeName);
if (build_context.bedrock) {
error(e->token, "Objective-C related things are not allowed with '-bedrock'");
}
// Begin class registration: create class pair and update global reference
lbValue class_value = {};
@@ -1667,11 +1680,11 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
{
lbValue superclass_value = lb_const_nil(m, t_objc_Class);
auto& tn = class_type->Named.type_name->TypeName;
auto &tn = e->TypeName;
Type *superclass = tn.objc_superclass;
if (superclass != nullptr) {
auto& superclass_global = string_map_must_get(&global_class_map, superclass->Named.type_name->TypeName.objc_class_name);
auto& superclass_global = string_map_must_get(&global_class_map, tn.objc_class_name);
superclass_value = superclass_global.class_value;
}
@@ -1727,13 +1740,13 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
}
for (const ObjcMethodData &md : *methods) {
GB_ASSERT( md.proc_entity->kind == Entity_Procedure);
GB_ASSERT(md.proc_entity->kind == Entity_Procedure);
Type *method_type = md.proc_entity->type;
String proc_name = make_string_c("__$objc_method::");
proc_name = concatenate_strings(temporary_allocator(), proc_name, g.name);
proc_name = concatenate_strings(temporary_allocator(), proc_name, str_lit("::"));
proc_name = concatenate_strings( permanent_allocator(), proc_name, md.ac.objc_name);
proc_name = concatenate_strings(permanent_allocator(), proc_name, md.ac.objc_name);
wrapper_args.count = 2;
wrapper_args[0] = md.ac.objc_is_class_method ? t_objc_Class : class_ptr_type;
@@ -1934,7 +1947,10 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
ivar_addr = lb_addr(global);
}
String class_name = g.class_impl_type->Named.type_name->TypeName.objc_class_name;
Entity *e = g.class_impl_type->Named.type_name;
GB_ASSERT(e->kind == Entity_TypeName);
String class_name = e->TypeName.objc_class_name;
lbValue class_value = string_map_must_get(&global_class_map, class_name).class_value;
args.count = 2;
@@ -1948,6 +1964,10 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
lbValue ivar_offset_int = lb_emit_conv(p, ivar_offset, t_int);
lb_addr_store(p, ivar_addr, ivar_offset_int);
if (build_context.bedrock) {
error(e->token, "Objective-C related things are not allowed with '-bedrock'");
}
}
lb_end_procedure_body(p);
@@ -2072,6 +2092,10 @@ gb_internal bool lb_init_global_var(lbModule *m, lbProcedure *p, Entity *e, Ast
}
var.is_initialized = true;
if (build_context.disable_non_constant_globals) {
error(e->token, "Non-constant initialization of a global variable is disallowed with '-disable_non_constant_globals'");
}
}
return false;
}

View File

@@ -1609,7 +1609,17 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
if (elem_count == 0 || !elem_type_can_be_constant(elem_type)) {
return lb_const_nil(m, original_type);
}
if (cl->elems[0]->kind == Ast_FieldValue) {
if (are_types_identical(value.value_compound->tav.type, elem_type)) {
// Compound is of array item type; expand its value to all items in array.
LLVMValueRef* values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count);
for (isize i = 0; i < type->Array.count; i++) {
values[i] = lb_const_value(m, elem_type, value, elem_type, cc).value;
}
res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc);
return res;
} else if (cl->elems[0]->kind == Ast_FieldValue) {
// TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand
LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count);
@@ -1663,16 +1673,6 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
}
}
res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc);
return res;
} else if (are_types_identical(value.value_compound->tav.type, elem_type)) {
// Compound is of array item type; expand its value to all items in array.
LLVMValueRef* values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count);
for (isize i = 0; i < type->Array.count; i++) {
values[i] = lb_const_value(m, elem_type, value, elem_type, cc).value;
}
res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc);
return res;
} else {

View File

@@ -6571,11 +6571,12 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
} else {
item = lb_emit_ptr_offset(p, lb_emit_load(p, arr), index);
}
// make sure it's ^T and not [^]T
item.type = alloc_type_multi_pointer_to_pointer(item.type);
if (sub_sel.index.count > 0) {
item = lb_emit_deep_field_gep(p, item, sub_sel);
}
// make sure it's ^T and not [^]T
item.type = alloc_type_multi_pointer_to_pointer(item.type);
return lb_addr(item);
} else if (addr.kind == lbAddr_Swizzle) {

View File

@@ -429,6 +429,10 @@ enum BuildFlagKind {
BuildFlag_BuildDiagnostics,
BuildFlag_Bedrock,
BuildFlag_DisableNonConstantGlobals,
BuildFlag_DisableInitFini,
// internal use only
BuildFlag_InternalFastISel,
BuildFlag_InternalIgnoreLazy,
@@ -664,6 +668,10 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_BuildDiagnostics, str_lit("build-diagnostics"), BuildFlagParam_None, Command__does_build);
add_flag(&build_flags, BuildFlag_Bedrock, str_lit("bedrock"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_DisableNonConstantGlobals, str_lit("disable-non-constant-globals"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_DisableInitFini, str_lit("disable-init-fini"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_InternalFastISel, str_lit("internal-fast-isel"), BuildFlagParam_None, Command_all);
add_flag(&build_flags, BuildFlag_InternalIgnoreLazy, str_lit("internal-ignore-lazy"), BuildFlagParam_None, Command_all);
add_flag(&build_flags, BuildFlag_InternalIgnoreLLVMBuild, str_lit("internal-ignore-llvm-build"),BuildFlagParam_None, Command_all);
@@ -1659,6 +1667,20 @@ gb_internal bool parse_build_flags(Array<String> args) {
build_context.build_diagnostics = true;
break;
case BuildFlag_Bedrock:
build_context.bedrock = true;
build_context.no_rtti = true;
build_context.disable_non_constant_globals = true;
build_context.disable_init_fini = true;
break;
case BuildFlag_DisableNonConstantGlobals:
build_context.disable_non_constant_globals = true;
break;
case BuildFlag_DisableInitFini:
build_context.disable_init_fini = true;
break;
case BuildFlag_InternalFastISel:
build_context.fast_isel = true;
break;
@@ -2685,6 +2707,19 @@ gb_internal int print_show_help(String const arg0, String command, String option
}
}
if (check) {
if (print_flag("-bedrock")) {
print_usage_line(2, "Disables numerous features. List of disabled features:");
print_usage_line(3, "`map` types");
print_usage_line(3, "128-bit integer types");
print_usage_line(3, "runtime type information (-no-rtti)");
print_usage_line(3, "non-constant global variables (-disable-non-constant-globals)");
print_usage_line(3, "@(init) @(fini) (-disable-init-fini)");
print_usage_line(3, "Anything Objective-C related");
print_usage_line(3, "The default paths to the library collections 'core' and 'vendor'");
}
}
if (build) {
if (print_flag("-build-mode:<mode>")) {
print_usage_line(2, "Sets the build mode.");
@@ -2751,7 +2786,15 @@ gb_internal int print_show_help(String const arg0, String command, String option
if (print_flag("-disable-assert")) {
print_usage_line(2, "Disables the code generation of the built-in run-time 'assert' procedure, and defines the global constant ODIN_DISABLE_ASSERT to be 'true'.");
}
}
if (check) {
if (print_flag("-disable-init-fini")) {
print_usage_line(2, "Disables the ability to use @(init) and @(fini) procedures");
}
}
if (run_or_build) {
if (print_flag("-disable-red-zone")) {
print_usage_line(2, "Disables red zone on a supported freestanding target.");
}
@@ -2761,8 +2804,13 @@ gb_internal int print_show_help(String const arg0, String command, String option
if (print_flag("-disallow-do")) {
print_usage_line(2, "Disallows the 'do' keyword in the project.");
}
if (print_flag("-disable-non-constant-globals")) {
print_usage_line(2, "Disables any global variables which are not initialized with global constants");
}
}
if (doc) {
if (print_flag("-doc-format")) {
print_usage_line(2, "Generates documentation as the .odin-doc format (useful for external tooling).");
@@ -3595,6 +3643,32 @@ gb_internal int strip_semicolons(Parser *parser) {
return cast(int)failed;
}
gb_internal void setup_bedrock_mode(void) {
if (!build_context.bedrock) {
return;
}
bool seen_core = false;
bool seen_vendor = false;
for (isize i = 0; i < library_collections.count; /**/) {
if (!seen_core && library_collections[i].name == "core") {
array_ordered_remove(&library_collections, i);
seen_core = true;
continue;
}
if (!seen_vendor && library_collections[i].name == "vendor") {
array_ordered_remove(&library_collections, i);
seen_vendor = true;
continue;
}
i += 1;
}
build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR = true;
}
gb_internal void init_terminal(void) {
TIME_SECTION("init terminal");
build_context.has_ansi_terminal_colours = false;
@@ -3693,16 +3767,41 @@ int main(int arg_count, char const **arg_ptr) {
String init_filename = {};
isize last_non_run_arg = args.count;
isize double_dash_pos = -1;
for_array(i, args) {
if (args[i] == "--") {
double_dash_pos = i;
break;
}
if (args[i] == "-help" || args[i] == "--help") {
build_context.show_help = true;
return print_show_help(args[0], command);
}
}
if (args.count > 2) {
// NOTE(bill): Allow for both `odin command path -flags` and `odin command -flags path`
// To do this, if the first argument after the command and last argument is NOT a flag,
// then put that last parameter first
isize end_arg = double_dash_pos >= 0 ? double_dash_pos : args.count-1;
if (args[1] == "bundle" && args.count > 4) {
if (string_starts_with(args[3], str_lit("-")) &&
!string_starts_with(args[end_arg], str_lit("-"))) {
String possible_path = args[end_arg];
array_ordered_remove(&args, end_arg);
array_inject_at(&args, 3, possible_path);
}
} else if (args.count > 3) {
if (string_starts_with(args[2], str_lit("-")) &&
!string_starts_with(args[end_arg], str_lit("-"))) {
String possible_path = args[end_arg];
array_ordered_remove(&args, end_arg);
array_inject_at(&args, 2, possible_path);
}
}
}
bool run_output = false;
if (command == "run" || command == "test") {
if (args.count < 3) {
@@ -3874,6 +3973,10 @@ int main(int arg_count, char const **arg_ptr) {
return print_show_help(args[0], command);
}
if (build_context.bedrock) {
setup_bedrock_mode();
}
if (init_filename.len > 0 && !build_context.show_help) {
// The command must be build, run, test, check, or another that takes a directory or filename.
if (!path_is_directory(init_filename)) {

View File

@@ -2528,8 +2528,14 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
while (f->curr_token.kind != Token_CloseBrace &&
f->curr_token.kind != Token_EOF) {
Ast *elem = parse_expr(f, false);
array_add(&args, elem);
if (f->curr_token.kind == Token_where) {
Token where = expect_token(f, Token_where);
Ast *cond = parse_expr(f, false);
elem = ast_binary_expr(f, where, elem, cond);
}
array_add(&args, elem);
if (!allow_field_separator(f)) {
break;
}
@@ -4214,18 +4220,33 @@ gb_internal FieldFlag is_token_field_prefix(AstFile *f) {
return FieldFlag_using;
case Token_Hash:
advance_token(f);
switch (f->curr_token.kind) {
case Token_Ident:
for (i32 i = 0; i < gb_count_of(parse_field_prefix_mappings); i++) {
auto const &mapping = parse_field_prefix_mappings[i];
if (mapping.token_kind == Token_Hash) {
if (f->curr_token.string == mapping.name) {
return mapping.flag;
}
{
// Check for types first before fields
Token tok = peek_token(f);
if (tok.kind == Token_Ident) {
if (tok.string == "simd" ||
tok.string == "type" ||
tok.string == "row_major" ||
tok.string == "column_major" ||
tok.string == "sparse" ||
tok.string == "soa") {
return FieldFlag_Invalid;
}
}
break;
advance_token(f);
switch (f->curr_token.kind) {
case Token_Ident:
for (i32 i = 0; i < gb_count_of(parse_field_prefix_mappings); i++) {
auto const &mapping = parse_field_prefix_mappings[i];
if (mapping.token_kind == Token_Hash) {
if (f->curr_token.string == mapping.name) {
return mapping.flag;
}
}
}
break;
}
}
return FieldFlag_Unknown;
}
@@ -6389,6 +6410,11 @@ gb_internal bool parse_build_tag(Token token_for_pos, String s) {
continue;
}
if (p == "bedrock") {
this_kind_correct = build_context.bedrock == !is_notted;
continue;
}
Subtarget subtarget = Subtarget_Invalid;
String subtarget_str = {};

View File

@@ -329,6 +329,9 @@ gb_global char const *proc_calling_convention_strings[ProcCC_MAX] = {
};
gb_internal ProcCallingConvention default_calling_convention(void) {
if (build_context.bedrock) {
// return ProcCC_Contextless;
}
return ProcCC_Odin;
}

View File

@@ -781,6 +781,9 @@ gb_global Type *t_c_va_list = nullptr;
gb_global Type *t_c_va_list_ptr = nullptr;
gb_global Type *t_odin_calling_convention = nullptr;
enum OdinAtomicMemoryOrder : i32 {
OdinAtomicMemoryOrder_relaxed = 0, // unordered
OdinAtomicMemoryOrder_consume = 1, // monotonic