mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-11 05:41:25 -07:00
Merge remote-tracking branch 'offical/master'
This commit is contained in:
@@ -919,6 +919,9 @@ gb_internal void report_os_info() {
|
||||
{"23F79", {23, 5, 0}, "macOS", {"Sonoma", {14, 5, 0}}},
|
||||
{"23G80", {23, 6, 0}, "macOS", {"Sonoma", {14, 6, 0}}},
|
||||
{"23G93", {23, 6, 0}, "macOS", {"Sonoma", {14, 6, 1}}},
|
||||
{"23H124", {23, 6, 0}, "macOS", {"Sonoma", {14, 7, 0}}},
|
||||
{"24A335", {24, 0, 0}, "macOS", {"Sequoia", {15, 0, 0}}},
|
||||
{"24A348", {24, 0, 0}, "macOS", {"Sequoia", {15, 0, 1}}},
|
||||
};
|
||||
|
||||
|
||||
|
||||
+17
-14
@@ -285,6 +285,7 @@ enum VetFlags : u64 {
|
||||
VetFlag_Deprecated = 1u<<7,
|
||||
VetFlag_Cast = 1u<<8,
|
||||
VetFlag_Tabs = 1u<<9,
|
||||
VetFlag_UnusedProcedures = 1u<<10,
|
||||
|
||||
VetFlag_Unused = VetFlag_UnusedVariables|VetFlag_UnusedImports,
|
||||
|
||||
@@ -316,6 +317,8 @@ u64 get_vet_flag_from_name(String const &name) {
|
||||
return VetFlag_Cast;
|
||||
} else if (name == "tabs") {
|
||||
return VetFlag_Tabs;
|
||||
} else if (name == "unused-procedures") {
|
||||
return VetFlag_UnusedProcedures;
|
||||
}
|
||||
return VetFlag_NONE;
|
||||
}
|
||||
@@ -383,6 +386,7 @@ struct BuildContext {
|
||||
|
||||
u64 vet_flags;
|
||||
u32 sanitizer_flags;
|
||||
StringSet vet_packages;
|
||||
|
||||
bool has_resource;
|
||||
String link_flags;
|
||||
@@ -411,6 +415,7 @@ struct BuildContext {
|
||||
bool no_dynamic_literals;
|
||||
bool no_output_files;
|
||||
bool no_crt;
|
||||
bool no_rpath;
|
||||
bool no_entry_point;
|
||||
bool no_thread_local;
|
||||
bool use_lld;
|
||||
@@ -1461,8 +1466,6 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
|
||||
bc->thread_count = gb_max(bc->affinity.thread_count, 1);
|
||||
}
|
||||
|
||||
string_set_init(&bc->custom_attributes);
|
||||
|
||||
bc->ODIN_VENDOR = str_lit("odin");
|
||||
bc->ODIN_VERSION = ODIN_VERSION;
|
||||
bc->ODIN_ROOT = odin_root_dir();
|
||||
@@ -2046,19 +2049,19 @@ gb_internal bool init_build_paths(String init_filename) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gbFile output_file_test;
|
||||
const char* output_file_name = (const char*)output_file.text;
|
||||
gbFileError output_test_err = gb_file_open_mode(&output_file_test, gbFileMode_Append | gbFileMode_Rw, output_file_name);
|
||||
// gbFile output_file_test;
|
||||
// const char* output_file_name = (const char*)output_file.text;
|
||||
// gbFileError output_test_err = gb_file_open_mode(&output_file_test, gbFileMode_Append | gbFileMode_Rw, output_file_name);
|
||||
|
||||
if (output_test_err == 0) {
|
||||
gb_file_close(&output_file_test);
|
||||
gb_file_remove(output_file_name);
|
||||
} else {
|
||||
String output_file = path_to_string(ha, bc->build_paths[BuildPath_Output]);
|
||||
defer (gb_free(ha, output_file.text));
|
||||
gb_printf_err("No write permissions for output path: %.*s\n", LIT(output_file));
|
||||
return false;
|
||||
}
|
||||
// if (output_test_err == 0) {
|
||||
// gb_file_close(&output_file_test);
|
||||
// gb_file_remove(output_file_name);
|
||||
// } else {
|
||||
// String output_file = path_to_string(ha, bc->build_paths[BuildPath_Output]);
|
||||
// defer (gb_free(ha, output_file.text));
|
||||
// gb_printf_err("No write permissions for output path: %.*s\n", LIT(output_file));
|
||||
// return false;
|
||||
// }
|
||||
|
||||
if (build_context.sanitizer_flags & SanitizerFlag_Address) {
|
||||
switch (build_context.metrics.os) {
|
||||
|
||||
+31
-20
@@ -1632,6 +1632,22 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o
|
||||
|
||||
operand->type = t_source_code_location;
|
||||
operand->mode = Addressing_Value;
|
||||
} else if (name == "caller_expression") {
|
||||
if (ce->args.count > 1) {
|
||||
error(ce->args[0], "'#caller_expression' expects either 0 or 1 arguments, got %td", ce->args.count);
|
||||
}
|
||||
if (ce->args.count > 0) {
|
||||
Ast *arg = ce->args[0];
|
||||
Operand o = {};
|
||||
Entity *e = check_ident(c, &o, arg, nullptr, nullptr, true);
|
||||
if (e == nullptr || (e->flags & EntityFlag_Param) == 0) {
|
||||
error(ce->args[0], "'#caller_expression' expected a valid earlier parameter name");
|
||||
}
|
||||
arg->Ident.entity = e;
|
||||
}
|
||||
|
||||
operand->type = t_string;
|
||||
operand->mode = Addressing_Value;
|
||||
} else if (name == "exists") {
|
||||
if (ce->args.count != 1) {
|
||||
error(ce->close, "'#exists' expects 1 argument, got %td", ce->args.count);
|
||||
@@ -3096,7 +3112,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
// Okay
|
||||
} else if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) {
|
||||
gbString type_str = type_to_string(original_type);
|
||||
error(call, "Expected a ordered numeric type to 'min', got '%s'", type_str);
|
||||
error(call, "Expected an ordered numeric type to 'min', got '%s'", type_str);
|
||||
gb_string_free(type_str);
|
||||
return false;
|
||||
}
|
||||
@@ -3182,7 +3198,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
if (!is_type_ordered(b.type) || !(is_type_numeric(b.type) || is_type_string(b.type))) {
|
||||
gbString type_str = type_to_string(b.type);
|
||||
error(call,
|
||||
"Expected a ordered numeric type to 'min', got '%s'",
|
||||
"Expected an ordered numeric type to 'min', got '%s'",
|
||||
type_str);
|
||||
gb_string_free(type_str);
|
||||
return false;
|
||||
@@ -3265,7 +3281,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
// Okay
|
||||
} else if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) {
|
||||
gbString type_str = type_to_string(original_type);
|
||||
error(call, "Expected a ordered numeric type to 'max', got '%s'", type_str);
|
||||
error(call, "Expected an ordered numeric type to 'max', got '%s'", type_str);
|
||||
gb_string_free(type_str);
|
||||
return false;
|
||||
}
|
||||
@@ -3356,7 +3372,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
if (!is_type_ordered(b.type) || !(is_type_numeric(b.type) || is_type_string(b.type))) {
|
||||
gbString type_str = type_to_string(b.type);
|
||||
error(arg,
|
||||
"Expected a ordered numeric type to 'max', got '%s'",
|
||||
"Expected an ordered numeric type to 'max', got '%s'",
|
||||
type_str);
|
||||
gb_string_free(type_str);
|
||||
return false;
|
||||
@@ -3486,7 +3502,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
Type *type = operand->type;
|
||||
if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) {
|
||||
gbString type_str = type_to_string(operand->type);
|
||||
error(call, "Expected a ordered numeric or string type to 'clamp', got '%s'", type_str);
|
||||
error(call, "Expected an ordered numeric or string type to 'clamp', got '%s'", type_str);
|
||||
gb_string_free(type_str);
|
||||
return false;
|
||||
}
|
||||
@@ -3503,7 +3519,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
}
|
||||
if (!is_type_ordered(y.type) || !(is_type_numeric(y.type) || is_type_string(y.type))) {
|
||||
gbString type_str = type_to_string(y.type);
|
||||
error(call, "Expected a ordered numeric or string type to 'clamp', got '%s'", type_str);
|
||||
error(call, "Expected an ordered numeric or string type to 'clamp', got '%s'", type_str);
|
||||
gb_string_free(type_str);
|
||||
return false;
|
||||
}
|
||||
@@ -3514,7 +3530,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
}
|
||||
if (!is_type_ordered(z.type) || !(is_type_numeric(z.type) || is_type_string(z.type))) {
|
||||
gbString type_str = type_to_string(z.type);
|
||||
error(call, "Expected a ordered numeric or string type to 'clamp', got '%s'", type_str);
|
||||
error(call, "Expected an ordered numeric or string type to 'clamp', got '%s'", type_str);
|
||||
gb_string_free(type_str);
|
||||
return false;
|
||||
}
|
||||
@@ -4967,16 +4983,14 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
check_assignment(c, &x, elem, builtin_name);
|
||||
|
||||
Type *t = type_deref(operand->type);
|
||||
switch (id) {
|
||||
case BuiltinProc_atomic_add:
|
||||
case BuiltinProc_atomic_sub:
|
||||
if (!is_type_numeric(t)) {
|
||||
if (id != BuiltinProc_atomic_exchange) {
|
||||
if (!is_type_integer_like(t)) {
|
||||
gbString str = type_to_string(t);
|
||||
error(operand->expr, "Expected a numeric type for '%.*s', got %s", LIT(builtin_name), str);
|
||||
error(operand->expr, "Expected an integer type for '%.*s', got %s", LIT(builtin_name), str);
|
||||
gb_string_free(str);
|
||||
} else if (is_type_different_to_arch_endianness(t)) {
|
||||
gbString str = type_to_string(t);
|
||||
error(operand->expr, "Expected a numeric type of the same platform endianness for '%.*s', got %s", LIT(builtin_name), str);
|
||||
error(operand->expr, "Expected an integer type of the same platform endianness for '%.*s', got %s", LIT(builtin_name), str);
|
||||
gb_string_free(str);
|
||||
}
|
||||
}
|
||||
@@ -5012,19 +5026,16 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
}
|
||||
|
||||
Type *t = type_deref(operand->type);
|
||||
switch (id) {
|
||||
case BuiltinProc_atomic_add_explicit:
|
||||
case BuiltinProc_atomic_sub_explicit:
|
||||
if (!is_type_numeric(t)) {
|
||||
if (id != BuiltinProc_atomic_exchange_explicit) {
|
||||
if (!is_type_integer_like(t)) {
|
||||
gbString str = type_to_string(t);
|
||||
error(operand->expr, "Expected a numeric type for '%.*s', got %s", LIT(builtin_name), str);
|
||||
error(operand->expr, "Expected an integer type for '%.*s', got %s", LIT(builtin_name), str);
|
||||
gb_string_free(str);
|
||||
} else if (is_type_different_to_arch_endianness(t)) {
|
||||
gbString str = type_to_string(t);
|
||||
error(operand->expr, "Expected a numeric type of the same platform endianness for '%.*s', got %s", LIT(builtin_name), str);
|
||||
error(operand->expr, "Expected an integer type of the same platform endianness for '%.*s', got %s", LIT(builtin_name), str);
|
||||
gb_string_free(str);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
operand->type = elem;
|
||||
|
||||
@@ -232,6 +232,10 @@ gb_internal bool check_override_as_type_due_to_aliasing(CheckerContext *ctx, Ent
|
||||
// until there is a proper delaying system to try declaration again if they
|
||||
// have failed.
|
||||
|
||||
if (e->type != nullptr && is_type_typed(e->type)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
e->kind = Entity_TypeName;
|
||||
check_type_decl(ctx, e, init, named_type);
|
||||
return true;
|
||||
|
||||
+42
-27
@@ -285,7 +285,7 @@ gb_internal void error_operand_no_value(Operand *o) {
|
||||
if (o->mode == Addressing_NoValue) {
|
||||
Ast *x = unparen_expr(o->expr);
|
||||
|
||||
if (x->kind == Ast_CallExpr) {
|
||||
if (x != nullptr && x->kind == Ast_CallExpr) {
|
||||
Ast *p = unparen_expr(x->CallExpr.proc);
|
||||
if (p->kind == Ast_BasicDirective) {
|
||||
String tag = p->BasicDirective.name.string;
|
||||
@@ -297,7 +297,7 @@ gb_internal void error_operand_no_value(Operand *o) {
|
||||
}
|
||||
|
||||
gbString err = expr_to_string(o->expr);
|
||||
if (x->kind == Ast_CallExpr) {
|
||||
if (x != nullptr && x->kind == Ast_CallExpr) {
|
||||
error(o->expr, "'%s' call does not return a value and cannot be used as a value", err);
|
||||
} else {
|
||||
error(o->expr, "'%s' used as a value", err);
|
||||
@@ -3612,10 +3612,11 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type
|
||||
if (are_types_identical(src_bt, dst_bt)) {
|
||||
return true;
|
||||
}
|
||||
if (is_type_integer(src_t) && is_type_integer(dst_t)) {
|
||||
if ((is_type_integer(src_t) && is_type_integer(dst_t)) ||
|
||||
is_type_integer(src_t) && is_type_bit_set(dst_t)) {
|
||||
if (types_have_same_internal_endian(src_t, dst_t)) {
|
||||
ExactValue src_v = exact_value_to_integer(o->value);
|
||||
GB_ASSERT(src_v.kind == ExactValue_Integer);
|
||||
GB_ASSERT(src_v.kind == ExactValue_Integer || src_v.kind == ExactValue_Invalid);
|
||||
BigInt v = src_v.value_integer;
|
||||
|
||||
BigInt smax = {};
|
||||
@@ -3900,6 +3901,12 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ
|
||||
// IMPORTANT NOTE(bill): This uses right-left evaluation in type checking only no in
|
||||
check_expr(c, y, be->right);
|
||||
Type *rhs_type = type_deref(y->type);
|
||||
if (rhs_type == nullptr) {
|
||||
error(y->expr, "Cannot use '%.*s' on an expression with no value", LIT(op.string));
|
||||
x->mode = Addressing_Invalid;
|
||||
x->expr = node;
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_type_bit_set(rhs_type)) {
|
||||
Type *elem = base_type(rhs_type)->BitSet.elem;
|
||||
@@ -4602,7 +4609,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
|
||||
(operand->value.kind == ExactValue_Integer ||
|
||||
operand->value.kind == ExactValue_Float)) {
|
||||
operand->mode = Addressing_Value;
|
||||
target_type = t_untyped_nil;
|
||||
// target_type = t_untyped_nil;
|
||||
operand->value = empty_exact_value;
|
||||
update_untyped_expr_value(c, operand->expr, operand->value);
|
||||
break;
|
||||
@@ -6203,22 +6210,6 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
|
||||
|
||||
Entity *vt = pt->params->Tuple.variables[pt->variadic_index];
|
||||
o.type = vt->type;
|
||||
|
||||
// NOTE(bill, 2024-07-14): minimize the stack usage for variadic parameters with the backing array
|
||||
if (c->decl) {
|
||||
bool found = false;
|
||||
for (auto &vr : c->decl->variadic_reuses) {
|
||||
if (are_types_identical(vt->type, vr.slice_type)) {
|
||||
vr.max_count = gb_max(vr.max_count, variadic_operands.count);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
array_add(&c->decl->variadic_reuses, VariadicReuseData{vt->type, variadic_operands.count});
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
dummy_argument_count += 1;
|
||||
o.type = t_untyped_nil;
|
||||
@@ -6412,6 +6403,23 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
|
||||
}
|
||||
score += eval_param_and_score(c, o, t, err, true, var_entity, show_error);
|
||||
}
|
||||
|
||||
if (!vari_expand && variadic_operands.count != 0) {
|
||||
// NOTE(bill, 2024-07-14): minimize the stack usage for variadic parameters with the backing array
|
||||
if (c->decl) {
|
||||
bool found = false;
|
||||
for (auto &vr : c->decl->variadic_reuses) {
|
||||
if (are_types_identical(slice, vr.slice_type)) {
|
||||
vr.max_count = gb_max(vr.max_count, variadic_operands.count);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
array_add(&c->decl->variadic_reuses, VariadicReuseData{slice, variadic_operands.count});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data) {
|
||||
@@ -7807,7 +7815,8 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
|
||||
name == "load" ||
|
||||
name == "load_directory" ||
|
||||
name == "load_hash" ||
|
||||
name == "hash"
|
||||
name == "hash" ||
|
||||
name == "caller_expression"
|
||||
) {
|
||||
operand->mode = Addressing_Builtin;
|
||||
operand->builtin_id = BuiltinProc_DIRECTIVE;
|
||||
@@ -8087,7 +8096,10 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
|
||||
GB_ASSERT(c->curr_proc_decl->entity->type->kind == Type_Proc);
|
||||
String scope_features = c->curr_proc_decl->entity->type->Proc.enable_target_feature;
|
||||
if (!check_target_feature_is_superset_of(scope_features, pt->Proc.enable_target_feature, &invalid)) {
|
||||
ERROR_BLOCK();
|
||||
error(call, "Inlined procedure enables target feature '%.*s', this requires the calling procedure to at least enable the same feature", LIT(invalid));
|
||||
|
||||
error_line("\tSuggested Example: @(enable_target_feature=\"%.*s\")\n", LIT(invalid));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8722,6 +8734,10 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A
|
||||
error(node, "#caller_location may only be used as a default argument parameter");
|
||||
o->type = t_source_code_location;
|
||||
o->mode = Addressing_Value;
|
||||
} else if (name == "caller_expression") {
|
||||
error(node, "#caller_expression may only be used as a default argument parameter");
|
||||
o->type = t_string;
|
||||
o->mode = Addressing_Value;
|
||||
} else {
|
||||
if (name == "location") {
|
||||
init_core_source_code_location(c->checker);
|
||||
@@ -8787,11 +8803,6 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n
|
||||
return kind;
|
||||
}
|
||||
|
||||
if (x.type == nullptr || x.type == t_invalid ||
|
||||
y.type == nullptr || y.type == t_invalid) {
|
||||
return kind;
|
||||
}
|
||||
|
||||
bool use_type_hint = type_hint != nullptr && (is_operand_nil(x) || is_operand_nil(y));
|
||||
|
||||
convert_to_typed(c, &x, use_type_hint ? type_hint : y.type);
|
||||
@@ -9123,6 +9134,10 @@ gb_internal ExprKind check_or_branch_expr(CheckerContext *c, Operand *o, Ast *no
|
||||
}
|
||||
|
||||
if (label != nullptr) {
|
||||
if (c->in_defer) {
|
||||
error(label, "A labelled '%.*s' cannot be used within a 'defer'", LIT(name));
|
||||
return Expr_Expr;
|
||||
}
|
||||
if (label->kind != Ast_Ident) {
|
||||
error(label, "A branch statement's label name must be an identifier");
|
||||
return Expr_Expr;
|
||||
|
||||
+14
-4
@@ -1641,6 +1641,8 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
|
||||
|
||||
Ast *expr = unparen_expr(rs->expr);
|
||||
|
||||
Operand rhs_operand = {};
|
||||
|
||||
bool is_range = false;
|
||||
bool is_possibly_addressable = true;
|
||||
isize max_val_count = 2;
|
||||
@@ -1698,7 +1700,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
|
||||
}
|
||||
}
|
||||
}
|
||||
bool is_ptr = is_type_pointer(type_deref(operand.type));
|
||||
bool is_ptr = is_type_pointer(operand.type);
|
||||
Type *t = base_type(type_deref(operand.type));
|
||||
|
||||
switch (t->kind) {
|
||||
@@ -1750,16 +1752,19 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
|
||||
break;
|
||||
|
||||
case Type_DynamicArray:
|
||||
is_possibly_addressable = true;
|
||||
array_add(&vals, t->DynamicArray.elem);
|
||||
array_add(&vals, t_int);
|
||||
break;
|
||||
|
||||
case Type_Slice:
|
||||
is_possibly_addressable = true;
|
||||
array_add(&vals, t->Slice.elem);
|
||||
array_add(&vals, t_int);
|
||||
break;
|
||||
|
||||
case Type_Map:
|
||||
is_possibly_addressable = true;
|
||||
is_map = true;
|
||||
array_add(&vals, t->Map.key);
|
||||
array_add(&vals, t->Map.value);
|
||||
@@ -1781,6 +1786,8 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
|
||||
|
||||
case Type_Tuple:
|
||||
{
|
||||
is_possibly_addressable = false;
|
||||
|
||||
isize count = t->Tuple.variables.count;
|
||||
if (count < 1) {
|
||||
ERROR_BLOCK();
|
||||
@@ -1810,8 +1817,6 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
|
||||
array_add(&vals, e->type);
|
||||
}
|
||||
|
||||
is_possibly_addressable = false;
|
||||
|
||||
bool do_break = false;
|
||||
for (isize i = rs->vals.count-1; i >= 0; i--) {
|
||||
if (rs->vals[i] != nullptr && count < i+2) {
|
||||
@@ -1831,6 +1836,11 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
|
||||
|
||||
case Type_Struct:
|
||||
if (t->Struct.soa_kind != StructSoa_None) {
|
||||
if (t->Struct.soa_kind == StructSoa_Fixed) {
|
||||
is_possibly_addressable = operand.mode == Addressing_Variable || is_ptr;
|
||||
} else {
|
||||
is_possibly_addressable = true;
|
||||
}
|
||||
is_soa = true;
|
||||
array_add(&vals, t->Struct.soa_elem);
|
||||
array_add(&vals, t_int);
|
||||
@@ -1907,7 +1917,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
|
||||
if (is_possibly_addressable && i == addressable_index) {
|
||||
entity->flags &= ~EntityFlag_Value;
|
||||
} else {
|
||||
char const *idx_name = is_map ? "key" : is_bit_set ? "element" : "index";
|
||||
char const *idx_name = is_map ? "key" : (is_bit_set || i == 0) ? "element" : "index";
|
||||
error(token, "The %s variable '%.*s' cannot be made addressable", idx_name, LIT(str));
|
||||
}
|
||||
}
|
||||
|
||||
+57
-6
@@ -673,7 +673,7 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *
|
||||
|
||||
#define ST_ALIGN(_name) if (st->_name != nullptr) { \
|
||||
if (st->is_packed) { \
|
||||
syntax_error(st->_name, "'#%s' cannot be applied with '#packed'", #_name); \
|
||||
error(st->_name, "'#%s' cannot be applied with '#packed'", #_name); \
|
||||
return; \
|
||||
} \
|
||||
i64 align = 1; \
|
||||
@@ -682,12 +682,31 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *
|
||||
} \
|
||||
}
|
||||
|
||||
ST_ALIGN(field_align);
|
||||
ST_ALIGN(min_field_align);
|
||||
ST_ALIGN(max_field_align);
|
||||
ST_ALIGN(align);
|
||||
if (struct_type->Struct.custom_align < struct_type->Struct.custom_field_align) {
|
||||
warning(st->align, "#align(%lld) is defined to be less than #field_name(%lld)",
|
||||
cast(long long)struct_type->Struct.custom_align,
|
||||
cast(long long)struct_type->Struct.custom_field_align);
|
||||
if (struct_type->Struct.custom_align < struct_type->Struct.custom_min_field_align) {
|
||||
error(st->align, "#align(%lld) is defined to be less than #min_field_align(%lld)",
|
||||
cast(long long)struct_type->Struct.custom_align,
|
||||
cast(long long)struct_type->Struct.custom_min_field_align);
|
||||
}
|
||||
if (struct_type->Struct.custom_max_field_align != 0 &&
|
||||
struct_type->Struct.custom_align > struct_type->Struct.custom_max_field_align) {
|
||||
error(st->align, "#align(%lld) is defined to be greater than #max_field_align(%lld)",
|
||||
cast(long long)struct_type->Struct.custom_align,
|
||||
cast(long long)struct_type->Struct.custom_max_field_align);
|
||||
}
|
||||
if (struct_type->Struct.custom_max_field_align != 0 &&
|
||||
struct_type->Struct.custom_min_field_align > struct_type->Struct.custom_max_field_align) {
|
||||
error(st->align, "#min_field_align(%lld) is defined to be greater than #max_field_align(%lld)",
|
||||
cast(long long)struct_type->Struct.custom_min_field_align,
|
||||
cast(long long)struct_type->Struct.custom_max_field_align);
|
||||
|
||||
i64 a = gb_min(struct_type->Struct.custom_min_field_align, struct_type->Struct.custom_max_field_align);
|
||||
i64 b = gb_max(struct_type->Struct.custom_min_field_align, struct_type->Struct.custom_max_field_align);
|
||||
// NOTE(bill): sort them to keep code consistent
|
||||
struct_type->Struct.custom_min_field_align = a;
|
||||
struct_type->Struct.custom_max_field_align = b;
|
||||
}
|
||||
|
||||
#undef ST_ALIGN
|
||||
@@ -1605,6 +1624,25 @@ gb_internal bool is_expr_from_a_parameter(CheckerContext *ctx, Ast *expr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gb_internal bool is_caller_expression(Ast *expr) {
|
||||
if (expr->kind == Ast_BasicDirective && expr->BasicDirective.name.string == "caller_expression") {
|
||||
return true;
|
||||
}
|
||||
|
||||
Ast *call = unparen_expr(expr);
|
||||
if (call->kind != Ast_CallExpr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ast_node(ce, CallExpr, call);
|
||||
if (ce->proc->kind != Ast_BasicDirective) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ast_node(bd, BasicDirective, ce->proc);
|
||||
String name = bd->name.string;
|
||||
return name == "caller_expression";
|
||||
}
|
||||
|
||||
gb_internal ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type **out_type_, Ast *expr, bool allow_caller_location) {
|
||||
ParameterValue param_value = {};
|
||||
@@ -1626,7 +1664,19 @@ gb_internal ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_
|
||||
if (in_type) {
|
||||
check_assignment(ctx, &o, in_type, str_lit("parameter value"));
|
||||
}
|
||||
} else if (is_caller_expression(expr)) {
|
||||
if (expr->kind != Ast_BasicDirective) {
|
||||
check_builtin_procedure_directive(ctx, &o, expr, t_string);
|
||||
}
|
||||
|
||||
param_value.kind = ParameterValue_Expression;
|
||||
o.type = t_string;
|
||||
o.mode = Addressing_Value;
|
||||
o.expr = expr;
|
||||
|
||||
if (in_type) {
|
||||
check_assignment(ctx, &o, in_type, str_lit("parameter value"));
|
||||
}
|
||||
} else {
|
||||
if (in_type) {
|
||||
check_expr_with_type_hint(ctx, &o, expr, in_type);
|
||||
@@ -1858,6 +1908,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
|
||||
case ParameterValue_Nil:
|
||||
break;
|
||||
case ParameterValue_Location:
|
||||
case ParameterValue_Expression:
|
||||
case ParameterValue_Value:
|
||||
gbString str = type_to_string(type);
|
||||
error(params[i], "A default value for a parameter must not be a polymorphic constant type, got %s", str);
|
||||
|
||||
+63
-27
@@ -533,18 +533,13 @@ gb_internal u64 check_vet_flags(CheckerContext *c) {
|
||||
c->curr_proc_decl->proc_lit) {
|
||||
file = c->curr_proc_decl->proc_lit->file();
|
||||
}
|
||||
if (file && file->vet_flags_set) {
|
||||
return file->vet_flags;
|
||||
}
|
||||
return build_context.vet_flags;
|
||||
|
||||
return ast_file_vet_flags(file);
|
||||
}
|
||||
|
||||
gb_internal u64 check_vet_flags(Ast *node) {
|
||||
AstFile *file = node->file();
|
||||
if (file && file->vet_flags_set) {
|
||||
return file->vet_flags;
|
||||
}
|
||||
return build_context.vet_flags;
|
||||
return ast_file_vet_flags(file);
|
||||
}
|
||||
|
||||
enum VettedEntityKind {
|
||||
@@ -681,20 +676,48 @@ gb_internal bool check_vet_unused(Checker *c, Entity *e, VettedEntity *ve) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) {
|
||||
bool vet_unused = (vet_flags & VetFlag_Unused) != 0;
|
||||
bool vet_shadowing = (vet_flags & (VetFlag_Shadowing|VetFlag_Using)) != 0;
|
||||
|
||||
gb_internal void check_scope_usage_internal(Checker *c, Scope *scope, u64 vet_flags, bool per_entity) {
|
||||
u64 original_vet_flags = vet_flags;
|
||||
Array<VettedEntity> vetted_entities = {};
|
||||
array_init(&vetted_entities, heap_allocator());
|
||||
defer (array_free(&vetted_entities));
|
||||
|
||||
rw_mutex_shared_lock(&scope->mutex);
|
||||
for (auto const &entry : scope->elements) {
|
||||
Entity *e = entry.value;
|
||||
if (e == nullptr) continue;
|
||||
|
||||
vet_flags = original_vet_flags;
|
||||
if (per_entity) {
|
||||
vet_flags = ast_file_vet_flags(e->file);
|
||||
}
|
||||
|
||||
bool vet_unused = (vet_flags & VetFlag_Unused) != 0;
|
||||
bool vet_shadowing = (vet_flags & (VetFlag_Shadowing|VetFlag_Using)) != 0;
|
||||
bool vet_unused_procedures = (vet_flags & VetFlag_UnusedProcedures) != 0;
|
||||
if (vet_unused_procedures && e->pkg && e->pkg->kind == Package_Runtime) {
|
||||
vet_unused_procedures = false;
|
||||
}
|
||||
|
||||
VettedEntity ve_unused = {};
|
||||
VettedEntity ve_shadowed = {};
|
||||
bool is_unused = vet_unused && check_vet_unused(c, e, &ve_unused);
|
||||
bool is_unused = false;
|
||||
if (vet_unused && check_vet_unused(c, e, &ve_unused)) {
|
||||
is_unused = true;
|
||||
} else if (vet_unused_procedures &&
|
||||
e->kind == Entity_Procedure) {
|
||||
if (e->flags&EntityFlag_Used) {
|
||||
is_unused = false;
|
||||
} else if (e->flags & EntityFlag_Require) {
|
||||
is_unused = false;
|
||||
} else if (e->pkg && e->pkg->kind == Package_Init && e->token.string == "main") {
|
||||
is_unused = false;
|
||||
} else {
|
||||
is_unused = true;
|
||||
ve_unused.kind = VettedEntity_Unused;
|
||||
ve_unused.entity = e;
|
||||
}
|
||||
}
|
||||
bool is_shadowed = vet_shadowing && check_vet_shadowing(c, e, &ve_shadowed);
|
||||
if (is_unused && is_shadowed) {
|
||||
VettedEntity ve_both = ve_shadowed;
|
||||
@@ -717,13 +740,18 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) {
|
||||
}
|
||||
rw_mutex_shared_unlock(&scope->mutex);
|
||||
|
||||
gb_sort(vetted_entities.data, vetted_entities.count, gb_size_of(VettedEntity), vetted_entity_variable_pos_cmp);
|
||||
array_sort(vetted_entities, vetted_entity_variable_pos_cmp);
|
||||
|
||||
for (auto const &ve : vetted_entities) {
|
||||
Entity *e = ve.entity;
|
||||
Entity *other = ve.other;
|
||||
String name = e->token.string;
|
||||
|
||||
vet_flags = original_vet_flags;
|
||||
if (per_entity) {
|
||||
vet_flags = ast_file_vet_flags(e->file);
|
||||
}
|
||||
|
||||
if (ve.kind == VettedEntity_Shadowed_And_Unused) {
|
||||
error(e->token, "'%.*s' declared but not used, possibly shadows declaration at line %d", LIT(name), other->token.pos.line);
|
||||
} else if (vet_flags) {
|
||||
@@ -732,6 +760,9 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) {
|
||||
if (e->kind == Entity_Variable && (vet_flags & VetFlag_UnusedVariables) != 0) {
|
||||
error(e->token, "'%.*s' declared but not used", LIT(name));
|
||||
}
|
||||
if (e->kind == Entity_Procedure && (vet_flags & VetFlag_UnusedProcedures) != 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));
|
||||
}
|
||||
@@ -749,7 +780,11 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) {
|
||||
}
|
||||
}
|
||||
|
||||
array_free(&vetted_entities);
|
||||
}
|
||||
|
||||
|
||||
gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) {
|
||||
check_scope_usage_internal(c, scope, vet_flags, false);
|
||||
|
||||
for (Scope *child = scope->head_child; child != nullptr; child = child->next) {
|
||||
if (child->flags & (ScopeFlag_Proc|ScopeFlag_Type|ScopeFlag_File)) {
|
||||
@@ -6174,7 +6209,7 @@ gb_internal void check_deferred_procedures(Checker *c) {
|
||||
}
|
||||
if ((src_params == nullptr && dst_params != nullptr) ||
|
||||
(src_params != nullptr && dst_params == nullptr)) {
|
||||
error(src->token, "Deferred procedure '%.*s' parameters do not match the inputs of initial procedure '%.*s'", LIT(src->token.string), LIT(dst->token.string));
|
||||
error(src->token, "Deferred procedure '%.*s' parameters do not match the inputs of initial procedure '%.*s'", LIT(dst->token.string), LIT(src->token.string));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -6187,8 +6222,8 @@ gb_internal void check_deferred_procedures(Checker *c) {
|
||||
gbString s = type_to_string(src_params);
|
||||
gbString d = type_to_string(dst_params);
|
||||
error(src->token, "Deferred procedure '%.*s' parameters do not match the inputs of initial procedure '%.*s':\n\t(%s) =/= (%s)",
|
||||
LIT(src->token.string), LIT(dst->token.string),
|
||||
s, d
|
||||
LIT(dst->token.string), LIT(src->token.string),
|
||||
d, s
|
||||
);
|
||||
gb_string_free(d);
|
||||
gb_string_free(s);
|
||||
@@ -6204,7 +6239,7 @@ gb_internal void check_deferred_procedures(Checker *c) {
|
||||
}
|
||||
if ((src_results == nullptr && dst_params != nullptr) ||
|
||||
(src_results != nullptr && dst_params == nullptr)) {
|
||||
error(src->token, "Deferred procedure '%.*s' parameters do not match the results of initial procedure '%.*s'", LIT(src->token.string), LIT(dst->token.string));
|
||||
error(src->token, "Deferred procedure '%.*s' parameters do not match the results of initial procedure '%.*s'", LIT(dst->token.string), LIT(src->token.string));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -6217,8 +6252,8 @@ gb_internal void check_deferred_procedures(Checker *c) {
|
||||
gbString s = type_to_string(src_results);
|
||||
gbString d = type_to_string(dst_params);
|
||||
error(src->token, "Deferred procedure '%.*s' parameters do not match the results of initial procedure '%.*s':\n\t(%s) =/= (%s)",
|
||||
LIT(src->token.string), LIT(dst->token.string),
|
||||
s, d
|
||||
LIT(dst->token.string), LIT(src->token.string),
|
||||
d, s
|
||||
);
|
||||
gb_string_free(d);
|
||||
gb_string_free(s);
|
||||
@@ -6270,8 +6305,8 @@ gb_internal void check_deferred_procedures(Checker *c) {
|
||||
gbString s = type_to_string(tsrc);
|
||||
gbString d = type_to_string(dst_params);
|
||||
error(src->token, "Deferred procedure '%.*s' parameters do not match the results of initial procedure '%.*s':\n\t(%s) =/= (%s)",
|
||||
LIT(src->token.string), LIT(dst->token.string),
|
||||
s, d
|
||||
LIT(dst->token.string), LIT(src->token.string),
|
||||
d, s
|
||||
);
|
||||
gb_string_free(d);
|
||||
gb_string_free(s);
|
||||
@@ -6497,12 +6532,13 @@ gb_internal void check_parsed_files(Checker *c) {
|
||||
TIME_SECTION("check scope usage");
|
||||
for (auto const &entry : c->info.files) {
|
||||
AstFile *f = entry.value;
|
||||
u64 vet_flags = build_context.vet_flags;
|
||||
if (f->vet_flags_set) {
|
||||
vet_flags = f->vet_flags;
|
||||
}
|
||||
u64 vet_flags = ast_file_vet_flags(f);
|
||||
check_scope_usage(c, f->scope, vet_flags);
|
||||
}
|
||||
for (auto const &entry : c->info.packages) {
|
||||
AstPackage *pkg = entry.value;
|
||||
check_scope_usage_internal(c, pkg->scope, 0, true);
|
||||
}
|
||||
|
||||
TIME_SECTION("add basic type information");
|
||||
// Add "Basic" type information
|
||||
|
||||
@@ -104,6 +104,7 @@ enum ParameterValueKind {
|
||||
ParameterValue_Constant,
|
||||
ParameterValue_Nil,
|
||||
ParameterValue_Location,
|
||||
ParameterValue_Expression,
|
||||
ParameterValue_Value,
|
||||
};
|
||||
|
||||
|
||||
+10
-2
@@ -3195,11 +3195,11 @@ void gb_affinity_init(gbAffinity *a) {
|
||||
a->core_count = 1;
|
||||
a->threads_per_core = 1;
|
||||
|
||||
if (sysctlbyname("hw.logicalcpu", &count, &count_size, NULL, 0) == 0) {
|
||||
if (sysctlbyname("kern.smp.cpus", &count, &count_size, NULL, 0) == 0) {
|
||||
if (count > 0) {
|
||||
a->thread_count = count;
|
||||
// Get # of physical cores
|
||||
if (sysctlbyname("hw.physicalcpu", &count, &count_size, NULL, 0) == 0) {
|
||||
if (sysctlbyname("kern.smp.cores", &count, &count_size, NULL, 0) == 0) {
|
||||
if (count > 0) {
|
||||
a->core_count = count;
|
||||
a->threads_per_core = a->thread_count / count;
|
||||
@@ -3210,6 +3210,14 @@ void gb_affinity_init(gbAffinity *a) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (sysctlbyname("hw.ncpu", &count, &count_size, NULL, 0) == 0) {
|
||||
// SMP disabled or unavailable.
|
||||
if (count > 0) {
|
||||
a->is_accurate = true;
|
||||
a->thread_count = count;
|
||||
a->core_count = count;
|
||||
a->threads_per_core = 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+11
-7
@@ -548,14 +548,8 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
||||
// 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")) || 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
|
||||
if (string_ends_with(lib, str_lit(".a")) || string_ends_with(lib, str_lit(".o")) || string_ends_with(lib, str_lit(".so")) || string_contains_string(lib, str_lit(".so."))) {
|
||||
lib_str = gb_string_append_fmt(lib_str, " -l:\"%.*s\" ", LIT(lib));
|
||||
} else if (string_ends_with(lib, str_lit(".so")) || string_contains_string(lib, str_lit(".so."))) {
|
||||
// dynamic lib, relative path to executable
|
||||
// NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible
|
||||
// at runtime to the executable
|
||||
lib_str = gb_string_append_fmt(lib_str, " -l:\"%s/%.*s\" ", cwd, LIT(lib));
|
||||
} else {
|
||||
// dynamic or static system lib, just link regularly searching system library paths
|
||||
lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
|
||||
@@ -643,6 +637,16 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!build_context.no_rpath) {
|
||||
// Set the rpath to the $ORIGIN/@loader_path (the path of the executable),
|
||||
// so that dynamic libraries are looked for at that path.
|
||||
if (build_context.metrics.os == TargetOs_darwin) {
|
||||
link_settings = gb_string_appendc(link_settings, "-Wl,-rpath,@loader_path ");
|
||||
} else {
|
||||
link_settings = gb_string_appendc(link_settings, "-Wl,-rpath,\\$ORIGIN ");
|
||||
}
|
||||
}
|
||||
|
||||
if (!build_context.no_crt) {
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, "-lm ");
|
||||
if (build_context.metrics.os == TargetOs_darwin) {
|
||||
|
||||
+20
-10
@@ -531,6 +531,7 @@ namespace lbAbiAmd64SysV {
|
||||
RegClass_SSEInt16,
|
||||
RegClass_SSEInt32,
|
||||
RegClass_SSEInt64,
|
||||
RegClass_SSEInt128,
|
||||
RegClass_SSEUp,
|
||||
RegClass_X87,
|
||||
RegClass_X87Up,
|
||||
@@ -572,6 +573,15 @@ namespace lbAbiAmd64SysV {
|
||||
gb_internal Array<RegClass> classify(LLVMTypeRef t);
|
||||
gb_internal LLVMTypeRef llreg(LLVMContextRef c, Array<RegClass> const ®_classes, LLVMTypeRef type);
|
||||
|
||||
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type) {
|
||||
if (!return_is_defined) {
|
||||
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
||||
}
|
||||
LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
|
||||
|
||||
return amd64_type(c, return_type, Amd64TypeAttribute_StructRect, ft->calling_convention);
|
||||
}
|
||||
|
||||
gb_internal LB_ABI_INFO(abi_info) {
|
||||
LLVMContextRef c = m->ctx;
|
||||
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
|
||||
@@ -582,12 +592,7 @@ namespace lbAbiAmd64SysV {
|
||||
for (unsigned i = 0; i < arg_count; i++) {
|
||||
ft->args[i] = amd64_type(c, arg_types[i], Amd64TypeAttribute_ByVal, calling_convention);
|
||||
}
|
||||
|
||||
if (return_is_defined) {
|
||||
ft->ret = amd64_type(c, return_type, Amd64TypeAttribute_StructRect, calling_convention);
|
||||
} else {
|
||||
ft->ret = lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
||||
}
|
||||
ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple);
|
||||
|
||||
return ft;
|
||||
}
|
||||
@@ -616,6 +621,10 @@ namespace lbAbiAmd64SysV {
|
||||
}
|
||||
switch (kind) {
|
||||
case LLVMIntegerTypeKind:
|
||||
if (LLVM_VERSION_MAJOR >= 18 && sz >= 16) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case LLVMHalfTypeKind:
|
||||
case LLVMFloatTypeKind:
|
||||
case LLVMDoubleTypeKind:
|
||||
@@ -1257,11 +1266,12 @@ namespace lbAbiWasm {
|
||||
}
|
||||
|
||||
gb_internal lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type, bool is_return) {
|
||||
if (!is_return && type == LLVMIntTypeInContext(c, 128)) {
|
||||
LLVMTypeRef cast_type = LLVMVectorType(LLVMInt64TypeInContext(c), 2);
|
||||
if (type == LLVMIntTypeInContext(c, 128)) {
|
||||
// LLVMTypeRef cast_type = LLVMVectorType(LLVMInt64TypeInContext(c), 2);
|
||||
LLVMTypeRef cast_type = nullptr;
|
||||
return lb_arg_type_direct(type, cast_type, nullptr, nullptr);
|
||||
}
|
||||
|
||||
|
||||
if (!is_return && lb_sizeof(type) > 8) {
|
||||
return lb_arg_type_indirect(type, nullptr);
|
||||
}
|
||||
@@ -1282,7 +1292,7 @@ namespace lbAbiWasm {
|
||||
case LLVMPointerTypeKind:
|
||||
return true;
|
||||
case LLVMIntegerTypeKind:
|
||||
return lb_sizeof(type) <= 8;
|
||||
return lb_sizeof(type) <= 16;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -528,7 +528,7 @@ gb_internal lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValu
|
||||
gb_internal lbValue lb_emit_source_code_location_const(lbProcedure *p, String const &procedure, TokenPos const &pos);
|
||||
gb_internal lbValue lb_const_source_code_location_const(lbModule *m, String const &procedure, TokenPos const &pos);
|
||||
|
||||
gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TokenPos const &pos);
|
||||
gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TypeProc *procedure_type, Ast *call_expression);
|
||||
|
||||
gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type);
|
||||
gb_internal lbValue lb_hasher_proc_for_type(lbModule *m, Type *type);
|
||||
|
||||
@@ -154,7 +154,7 @@ gb_internal LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValue
|
||||
GB_ASSERT(value_count_ == bt->Struct.fields.count);
|
||||
|
||||
auto field_remapping = lb_get_struct_remapping(m, t);
|
||||
unsigned values_with_padding_count = LLVMCountStructElementTypes(struct_type);
|
||||
unsigned values_with_padding_count = elem_count;
|
||||
|
||||
LLVMValueRef *values_with_padding = gb_alloc_array(permanent_allocator(), LLVMValueRef, values_with_padding_count);
|
||||
for (unsigned i = 0; i < value_count; i++) {
|
||||
@@ -722,7 +722,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
|
||||
}
|
||||
|
||||
case ExactValue_Integer:
|
||||
if (is_type_pointer(type) || is_type_multi_pointer(type)) {
|
||||
if (is_type_pointer(type) || is_type_multi_pointer(type) || is_type_proc(type)) {
|
||||
LLVMTypeRef t = lb_type(m, original_type);
|
||||
LLVMValueRef i = lb_big_int_to_llvm(m, t_uintptr, &value.value_integer);
|
||||
res.value = LLVMConstIntToPtr(i, t);
|
||||
|
||||
+44
-36
@@ -552,6 +552,48 @@ gb_internal LLVMMetadataRef lb_debug_bitset(lbModule *m, Type *type, String name
|
||||
return final_decl;
|
||||
}
|
||||
|
||||
gb_internal LLVMMetadataRef lb_debug_bitfield(lbModule *m, Type *type, String name, LLVMMetadataRef scope, LLVMMetadataRef file, unsigned line) {
|
||||
Type *bt = base_type(type);
|
||||
GB_ASSERT(bt->kind == Type_BitField);
|
||||
|
||||
lb_debug_file_line(m, bt->BitField.node, &file, &line);
|
||||
|
||||
u64 size_in_bits = 8*type_size_of(bt);
|
||||
u32 align_in_bits = 8*cast(u32)type_align_of(bt);
|
||||
|
||||
unsigned element_count = cast(unsigned)bt->BitField.fields.count;
|
||||
LLVMMetadataRef *elements = gb_alloc_array(permanent_allocator(), LLVMMetadataRef, element_count);
|
||||
|
||||
u64 offset_in_bits = 0;
|
||||
for (unsigned i = 0; i < element_count; i++) {
|
||||
Entity *f = bt->BitField.fields[i];
|
||||
u8 bit_size = bt->BitField.bit_sizes[i];
|
||||
GB_ASSERT(f->kind == Entity_Variable);
|
||||
String name = f->token.string;
|
||||
elements[i] = LLVMDIBuilderCreateBitFieldMemberType(m->debug_builder, scope, cast(char const *)name.text, name.len, file, line,
|
||||
bit_size, offset_in_bits, 0,
|
||||
LLVMDIFlagZero, lb_debug_type(m, f->type)
|
||||
);
|
||||
|
||||
offset_in_bits += bit_size;
|
||||
}
|
||||
|
||||
LLVMMetadataRef final_decl = LLVMDIBuilderCreateStructType(
|
||||
m->debug_builder, scope,
|
||||
cast(char const *)name.text, cast(size_t)name.len,
|
||||
file, line,
|
||||
size_in_bits, align_in_bits,
|
||||
LLVMDIFlagZero,
|
||||
nullptr,
|
||||
elements, element_count,
|
||||
0,
|
||||
nullptr,
|
||||
"", 0
|
||||
);
|
||||
lb_set_llvm_metadata(m, type, final_decl);
|
||||
return final_decl;
|
||||
}
|
||||
|
||||
gb_internal LLVMMetadataRef lb_debug_enum(lbModule *m, Type *type, String name, LLVMMetadataRef scope, LLVMMetadataRef file, unsigned line) {
|
||||
Type *bt = base_type(type);
|
||||
GB_ASSERT(bt->kind == Type_Enum);
|
||||
@@ -816,6 +858,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
|
||||
case Type_Union: return lb_debug_union( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0);
|
||||
case Type_BitSet: return lb_debug_bitset( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0);
|
||||
case Type_Enum: return lb_debug_enum( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0);
|
||||
case Type_BitField: return lb_debug_bitfield( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0);
|
||||
|
||||
case Type_Tuple:
|
||||
if (type->Tuple.variables.count == 1) {
|
||||
@@ -901,42 +944,6 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
|
||||
lb_debug_type(m, type->Matrix.elem),
|
||||
subscripts, gb_count_of(subscripts));
|
||||
}
|
||||
|
||||
case Type_BitField: {
|
||||
LLVMMetadataRef parent_scope = nullptr;
|
||||
LLVMMetadataRef scope = nullptr;
|
||||
LLVMMetadataRef file = nullptr;
|
||||
unsigned line = 0;
|
||||
u64 size_in_bits = 8*cast(u64)type_size_of(type);
|
||||
u32 align_in_bits = 8*cast(u32)type_align_of(type);
|
||||
LLVMDIFlags flags = LLVMDIFlagZero;
|
||||
|
||||
unsigned element_count = cast(unsigned)type->BitField.fields.count;
|
||||
LLVMMetadataRef *elements = gb_alloc_array(permanent_allocator(), LLVMMetadataRef, element_count);
|
||||
|
||||
u64 offset_in_bits = 0;
|
||||
for (unsigned i = 0; i < element_count; i++) {
|
||||
Entity *f = type->BitField.fields[i];
|
||||
u8 bit_size = type->BitField.bit_sizes[i];
|
||||
GB_ASSERT(f->kind == Entity_Variable);
|
||||
String name = f->token.string;
|
||||
unsigned field_line = 0;
|
||||
LLVMDIFlags field_flags = LLVMDIFlagZero;
|
||||
elements[i] = LLVMDIBuilderCreateBitFieldMemberType(m->debug_builder, scope, cast(char const *)name.text, name.len, file, field_line,
|
||||
bit_size, offset_in_bits, offset_in_bits,
|
||||
field_flags, lb_debug_type(m, f->type)
|
||||
);
|
||||
|
||||
offset_in_bits += bit_size;
|
||||
}
|
||||
|
||||
|
||||
return LLVMDIBuilderCreateStructType(m->debug_builder, parent_scope, "", 0, file, line,
|
||||
size_in_bits, align_in_bits, flags,
|
||||
nullptr, elements, element_count, 0, nullptr,
|
||||
"", 0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
GB_PANIC("Invalid type %s", type_to_string(type));
|
||||
@@ -1022,6 +1029,7 @@ gb_internal LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) {
|
||||
case Type_Union: return lb_debug_union(m, type, name, scope, file, line);
|
||||
case Type_BitSet: return lb_debug_bitset(m, type, name, scope, file, line);
|
||||
case Type_Enum: return lb_debug_enum(m, type, name, scope, file, line);
|
||||
case Type_BitField: return lb_debug_bitfield(m, type, name, scope, file, line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1225,10 +1225,10 @@ gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbV
|
||||
lbValue d3 = lb_emit_struct_ep(p, res.addr, 3);
|
||||
|
||||
if (immediate_type != ft) {
|
||||
d0 = lb_emit_conv(p, d0, ft);
|
||||
d1 = lb_emit_conv(p, d1, ft);
|
||||
d2 = lb_emit_conv(p, d2, ft);
|
||||
d3 = lb_emit_conv(p, d3, ft);
|
||||
z0 = lb_emit_conv(p, z0, ft);
|
||||
z1 = lb_emit_conv(p, z1, ft);
|
||||
z2 = lb_emit_conv(p, z2, ft);
|
||||
z3 = lb_emit_conv(p, z3, ft);
|
||||
}
|
||||
|
||||
lb_emit_store(p, d0, z0);
|
||||
@@ -2555,17 +2555,27 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left
|
||||
|
||||
if (are_types_identical(a, b)) {
|
||||
// NOTE(bill): No need for a conversion
|
||||
} else if (lb_is_const(left) || lb_is_const_nil(left)) {
|
||||
} else if ((lb_is_const(left) && !is_type_array(left.type)) || lb_is_const_nil(left)) {
|
||||
// NOTE(karl): !is_type_array(left.type) is there to avoid lb_emit_conv
|
||||
// trying to convert a constant array into a non-array. In that case we
|
||||
// want the `else` branch to happen, so it can try to convert the
|
||||
// non-array into an array instead.
|
||||
|
||||
if (lb_is_const_nil(left)) {
|
||||
if (internal_check_is_assignable_to(right.type, left.type)) {
|
||||
right = lb_emit_conv(p, right, left.type);
|
||||
}
|
||||
return lb_emit_comp_against_nil(p, op_kind, right);
|
||||
}
|
||||
left = lb_emit_conv(p, left, right.type);
|
||||
} else if (lb_is_const(right) || lb_is_const_nil(right)) {
|
||||
} else if ((lb_is_const(right) && !is_type_array(right.type)) || lb_is_const_nil(right)) {
|
||||
if (lb_is_const_nil(right)) {
|
||||
if (internal_check_is_assignable_to(left.type, right.type)) {
|
||||
left = lb_emit_conv(p, left, right.type);
|
||||
}
|
||||
return lb_emit_comp_against_nil(p, op_kind, left);
|
||||
}
|
||||
right = lb_emit_conv(p, right, left.type);
|
||||
|
||||
} else {
|
||||
Type *lt = left.type;
|
||||
Type *rt = right.type;
|
||||
@@ -3451,8 +3461,14 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
|
||||
switch (expr->kind) {
|
||||
case_ast_node(bl, BasicLit, expr);
|
||||
if (type != nullptr && type->Named.name == "Error") {
|
||||
Entity *e = type->Named.type_name;
|
||||
if (e->pkg && e->pkg->name == "os") {
|
||||
return lb_const_nil(p->module, type);
|
||||
}
|
||||
}
|
||||
TokenPos pos = bl->token.pos;
|
||||
GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(token_strings[bl->token.kind]));
|
||||
GB_PANIC("Non-constant basic literal %s - %.*s (%s)", token_pos_to_string(pos), LIT(token_strings[bl->token.kind]), type_to_string(type));
|
||||
case_end;
|
||||
|
||||
case_ast_node(bd, BasicDirective, expr);
|
||||
|
||||
@@ -699,7 +699,9 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) {
|
||||
}
|
||||
|
||||
if (e->Variable.param_value.kind != ParameterValue_Invalid) {
|
||||
lbValue c = lb_handle_param_value(p, e->type, e->Variable.param_value, e->token.pos);
|
||||
GB_ASSERT(e->Variable.param_value.kind != ParameterValue_Location);
|
||||
GB_ASSERT(e->Variable.param_value.kind != ParameterValue_Expression);
|
||||
lbValue c = lb_handle_param_value(p, e->type, e->Variable.param_value, nullptr, nullptr);
|
||||
lb_addr_store(p, res, c);
|
||||
}
|
||||
|
||||
@@ -3420,7 +3422,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
|
||||
}
|
||||
|
||||
|
||||
gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TokenPos const &pos) {
|
||||
gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TypeProc *procedure_type, Ast* call_expression) {
|
||||
switch (param_value.kind) {
|
||||
case ParameterValue_Constant:
|
||||
if (is_type_constant_type(parameter_type)) {
|
||||
@@ -3446,8 +3448,60 @@ gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type,
|
||||
if (p->entity != nullptr) {
|
||||
proc_name = p->entity->token.string;
|
||||
}
|
||||
|
||||
ast_node(ce, CallExpr, call_expression);
|
||||
TokenPos pos = ast_token(ce->proc).pos;
|
||||
|
||||
return lb_emit_source_code_location_as_global(p, proc_name, pos);
|
||||
}
|
||||
case ParameterValue_Expression:
|
||||
{
|
||||
Ast *orig = param_value.original_ast_expr;
|
||||
if (orig->kind == Ast_BasicDirective) {
|
||||
gbString expr = expr_to_string(call_expression, temporary_allocator());
|
||||
return lb_const_string(p->module, make_string_c(expr));
|
||||
}
|
||||
|
||||
isize param_idx = -1;
|
||||
String param_str = {0};
|
||||
{
|
||||
Ast *call = unparen_expr(orig);
|
||||
GB_ASSERT(call->kind == Ast_CallExpr);
|
||||
ast_node(ce, CallExpr, call);
|
||||
GB_ASSERT(ce->proc->kind == Ast_BasicDirective);
|
||||
GB_ASSERT(ce->args.count == 1);
|
||||
Ast *target = ce->args[0];
|
||||
GB_ASSERT(target->kind == Ast_Ident);
|
||||
String target_str = target->Ident.token.string;
|
||||
|
||||
param_idx = lookup_procedure_parameter(procedure_type, target_str);
|
||||
param_str = target_str;
|
||||
}
|
||||
GB_ASSERT(param_idx >= 0);
|
||||
|
||||
|
||||
Ast *target_expr = nullptr;
|
||||
ast_node(ce, CallExpr, call_expression);
|
||||
|
||||
if (ce->split_args->positional.count > param_idx) {
|
||||
target_expr = ce->split_args->positional[param_idx];
|
||||
}
|
||||
|
||||
for_array(i, ce->split_args->named) {
|
||||
Ast *arg = ce->split_args->named[i];
|
||||
ast_node(fv, FieldValue, arg);
|
||||
GB_ASSERT(fv->field->kind == Ast_Ident);
|
||||
String name = fv->field->Ident.token.string;
|
||||
if (name == param_str) {
|
||||
target_expr = fv->value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gbString expr = expr_to_string(target_expr, temporary_allocator());
|
||||
return lb_const_string(p->module, make_string_c(expr));
|
||||
}
|
||||
|
||||
case ParameterValue_Value:
|
||||
return lb_build_expr(p, param_value.ast_value);
|
||||
}
|
||||
@@ -3739,8 +3793,6 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
}
|
||||
}
|
||||
|
||||
TokenPos pos = ast_token(ce->proc).pos;
|
||||
|
||||
|
||||
if (pt->params != nullptr) {
|
||||
isize min_count = pt->params->Tuple.variables.count;
|
||||
@@ -3764,7 +3816,7 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
args[arg_index] = lb_const_nil(p->module, e->type);
|
||||
break;
|
||||
case Entity_Variable:
|
||||
args[arg_index] = lb_handle_param_value(p, e->type, e->Variable.param_value, pos);
|
||||
args[arg_index] = lb_handle_param_value(p, e->type, e->Variable.param_value, pt, expr);
|
||||
break;
|
||||
|
||||
case Entity_Constant:
|
||||
|
||||
@@ -826,7 +826,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
|
||||
|
||||
|
||||
if (t->Struct.soa_kind != StructSoa_None) {
|
||||
Type *kind_type = get_struct_field_type(tag_type, 10);
|
||||
Type *kind_type = get_struct_field_type(tag_type, 7);
|
||||
|
||||
lbValue soa_kind = lb_const_value(m, kind_type, exact_value_i64(t->Struct.soa_kind));
|
||||
LLVMValueRef soa_type = get_type_info_ptr(m, t->Struct.soa_elem);
|
||||
|
||||
+440
-338
@@ -325,6 +325,7 @@ enum BuildFlagKind {
|
||||
BuildFlag_NoTypeAssert,
|
||||
BuildFlag_NoDynamicLiterals,
|
||||
BuildFlag_NoCRT,
|
||||
BuildFlag_NoRPath,
|
||||
BuildFlag_NoEntryPoint,
|
||||
BuildFlag_UseLLD,
|
||||
BuildFlag_UseSeparateModules,
|
||||
@@ -339,12 +340,14 @@ enum BuildFlagKind {
|
||||
BuildFlag_VetUnused,
|
||||
BuildFlag_VetUnusedImports,
|
||||
BuildFlag_VetUnusedVariables,
|
||||
BuildFlag_VetUnusedProcedures,
|
||||
BuildFlag_VetUsingStmt,
|
||||
BuildFlag_VetUsingParam,
|
||||
BuildFlag_VetStyle,
|
||||
BuildFlag_VetSemicolon,
|
||||
BuildFlag_VetCast,
|
||||
BuildFlag_VetTabs,
|
||||
BuildFlag_VetPackages,
|
||||
|
||||
BuildFlag_CustomAttribute,
|
||||
BuildFlag_IgnoreUnknownAttributes,
|
||||
@@ -508,7 +511,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
auto build_flags = array_make<BuildFlag>(heap_allocator(), 0, BuildFlag_COUNT);
|
||||
add_flag(&build_flags, BuildFlag_Help, str_lit("help"), BuildFlagParam_None, Command_all);
|
||||
add_flag(&build_flags, BuildFlag_SingleFile, str_lit("file"), BuildFlagParam_None, Command__does_build | Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String, Command__does_build | Command_test);
|
||||
add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String, Command__does_build | Command_test | Command_doc);
|
||||
add_flag(&build_flags, BuildFlag_OptimizationMode, str_lit("o"), BuildFlagParam_String, Command__does_build);
|
||||
add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None, Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_ShowMoreTimings, str_lit("show-more-timings"), BuildFlagParam_None, Command__does_check);
|
||||
@@ -533,6 +536,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
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);
|
||||
add_flag(&build_flags, BuildFlag_NoRPath, str_lit("no-rpath"), BuildFlagParam_None, Command__does_build);
|
||||
add_flag(&build_flags, BuildFlag_NoEntryPoint, str_lit("no-entry-point"), BuildFlagParam_None, Command__does_check &~ Command_test);
|
||||
add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None, Command__does_build);
|
||||
add_flag(&build_flags, BuildFlag_UseSeparateModules, str_lit("use-separate-modules"), BuildFlagParam_None, Command__does_build);
|
||||
@@ -545,6 +549,7 @@ 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_VetUnusedProcedures, str_lit("vet-unused-procedures"), 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);
|
||||
@@ -553,6 +558,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
add_flag(&build_flags, BuildFlag_VetSemicolon, str_lit("vet-semicolon"), BuildFlagParam_None, Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_VetCast, str_lit("vet-cast"), BuildFlagParam_None, Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_VetTabs, str_lit("vet-tabs"), BuildFlagParam_None, Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_VetPackages, str_lit("vet-packages"), BuildFlagParam_String, Command__does_check);
|
||||
|
||||
add_flag(&build_flags, BuildFlag_CustomAttribute, str_lit("custom-attribute"), BuildFlagParam_String, Command__does_check, true);
|
||||
add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None, Command__does_check);
|
||||
@@ -1183,6 +1189,9 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
case BuildFlag_NoCRT:
|
||||
build_context.no_crt = true;
|
||||
break;
|
||||
case BuildFlag_NoRPath:
|
||||
build_context.no_rpath = true;
|
||||
break;
|
||||
case BuildFlag_NoEntryPoint:
|
||||
build_context.no_entry_point = true;
|
||||
break;
|
||||
@@ -1215,6 +1224,36 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
case BuildFlag_VetSemicolon: build_context.vet_flags |= VetFlag_Semicolon; break;
|
||||
case BuildFlag_VetCast: build_context.vet_flags |= VetFlag_Cast; break;
|
||||
case BuildFlag_VetTabs: build_context.vet_flags |= VetFlag_Tabs; break;
|
||||
case BuildFlag_VetUnusedProcedures:
|
||||
build_context.vet_flags |= VetFlag_UnusedProcedures;
|
||||
if (!set_flags[BuildFlag_VetPackages]) {
|
||||
gb_printf_err("-%.*s must be used with -vet-packages\n", LIT(name));
|
||||
bad_flags = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case BuildFlag_VetPackages:
|
||||
{
|
||||
GB_ASSERT(value.kind == ExactValue_String);
|
||||
String val = value.value_string;
|
||||
String_Iterator it = {val, 0};
|
||||
for (;;) {
|
||||
String pkg = string_split_iterator(&it, ',');
|
||||
if (pkg.len == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
pkg = string_trim_whitespace(pkg);
|
||||
if (!string_is_valid_identifier(pkg)) {
|
||||
gb_printf_err("-%.*s '%.*s' must be a valid identifier\n", LIT(name), LIT(pkg));
|
||||
bad_flags = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
string_set_add(&build_context.vet_packages, pkg);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BuildFlag_CustomAttribute:
|
||||
{
|
||||
@@ -1229,7 +1268,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
|
||||
attr = string_trim_whitespace(attr);
|
||||
if (!string_is_valid_identifier(attr)) {
|
||||
gb_printf_err("-custom-attribute '%.*s' must be a valid identifier\n", LIT(attr));
|
||||
gb_printf_err("-%.*s '%.*s' must be a valid identifier\n", LIT(name), LIT(attr));
|
||||
bad_flags = true;
|
||||
continue;
|
||||
}
|
||||
@@ -1369,7 +1408,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
build_context.terse_errors = true;
|
||||
break;
|
||||
case BuildFlag_VerboseErrors:
|
||||
gb_printf_err("-verbose-errors is not the default, -terse-errors can now disable it\n");
|
||||
gb_printf_err("-verbose-errors is now the default, -terse-errors can disable it\n");
|
||||
build_context.hide_error_line = false;
|
||||
build_context.terse_errors = false;
|
||||
break;
|
||||
@@ -2140,131 +2179,15 @@ gb_internal void print_show_help(String const arg0, String const &command) {
|
||||
print_usage_line(1, "Flags");
|
||||
print_usage_line(0, "");
|
||||
|
||||
if (check) {
|
||||
print_usage_line(1, "-file");
|
||||
print_usage_line(2, "Tells `%.*s %.*s` to treat the given file as a self-contained package.", LIT(arg0), LIT(command));
|
||||
print_usage_line(2, "This means that `<dir>/a.odin` won't have access to `<dir>/b.odin`'s contents.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (doc) {
|
||||
print_usage_line(1, "-short");
|
||||
print_usage_line(2, "Shows shortened documentation for the packages.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-all-packages");
|
||||
print_usage_line(2, "Generates documentation for all packages used in the current project.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-doc-format");
|
||||
print_usage_line(2, "Generates documentation as the .odin-doc format (useful for external tooling).");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (run_or_build) {
|
||||
print_usage_line(1, "-out:<filepath>");
|
||||
print_usage_line(2, "Sets the file name of the outputted executable.");
|
||||
print_usage_line(2, "Example: -out:foo.exe");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-o:<string>");
|
||||
print_usage_line(2, "Sets the optimization mode for compilation.");
|
||||
print_usage_line(2, "Available options:");
|
||||
print_usage_line(3, "-o:none");
|
||||
print_usage_line(3, "-o:minimal");
|
||||
print_usage_line(3, "-o:size");
|
||||
print_usage_line(3, "-o:speed");
|
||||
if (LB_USE_NEW_PASS_SYSTEM) {
|
||||
print_usage_line(3, "-o:aggressive");
|
||||
}
|
||||
print_usage_line(2, "The default is -o:minimal.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (check) {
|
||||
print_usage_line(1, "-show-timings");
|
||||
print_usage_line(2, "Shows basic overview of the timings of different stages within the compiler in milliseconds.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-show-more-timings");
|
||||
print_usage_line(2, "Shows an advanced overview of the timings of different stages within the compiler in milliseconds.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-show-system-calls");
|
||||
print_usage_line(2, "Prints the whole command and arguments for calls to external tools like linker and assembler.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-export-timings:<format>");
|
||||
print_usage_line(2, "Exports timings to one of a few formats. Requires `-show-timings` or `-show-more-timings`.");
|
||||
print_usage_line(2, "Available options:");
|
||||
print_usage_line(3, "-export-timings:json Exports compile time stats to JSON.");
|
||||
print_usage_line(3, "-export-timings:csv Exports compile time stats to CSV.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-export-timings-file:<filename>");
|
||||
print_usage_line(2, "Specifies the filename for `-export-timings`.");
|
||||
print_usage_line(2, "Example: -export-timings-file:timings.json");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-export-dependencies:<format>");
|
||||
print_usage_line(2, "Exports dependencies to one of a few formats. Requires `-export-dependencies-file`.");
|
||||
print_usage_line(2, "Available options:");
|
||||
print_usage_line(3, "-export-dependencies:make Exports in Makefile format");
|
||||
print_usage_line(3, "-export-dependencies:json Exports in JSON format");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-export-dependencies-file:<filename>");
|
||||
print_usage_line(2, "Specifies the filename for `-export-dependencies`.");
|
||||
print_usage_line(2, "Example: -export-dependencies-file:dependencies.d");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-thread-count:<integer>");
|
||||
print_usage_line(2, "Overrides the number of threads the compiler will use to compile with.");
|
||||
print_usage_line(2, "Example: -thread-count:2");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (check_only) {
|
||||
print_usage_line(1, "-show-unused");
|
||||
print_usage_line(2, "Shows unused package declarations within the current project.");
|
||||
print_usage_line(0, "");
|
||||
print_usage_line(1, "-show-unused-with-location");
|
||||
print_usage_line(2, "Shows unused package declarations within the current project with the declarations source location.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (run_or_build) {
|
||||
print_usage_line(1, "-keep-temp-files");
|
||||
print_usage_line(2, "Keeps the temporary files generated during compilation.");
|
||||
print_usage_line(0, "");
|
||||
} else if (strip_semicolon) {
|
||||
print_usage_line(1, "-keep-temp-files");
|
||||
print_usage_line(2, "Keeps the temporary files generated during stripping the unneeded semicolons from files.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (check) {
|
||||
print_usage_line(1, "-collection:<name>=<filepath>");
|
||||
print_usage_line(2, "Defines a library collection used for imports.");
|
||||
print_usage_line(2, "Example: -collection:shared=dir/to/shared");
|
||||
print_usage_line(2, "Usage in Code:");
|
||||
print_usage_line(3, "import \"shared:foo\"");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-define:<name>=<value>");
|
||||
print_usage_line(2, "Defines a scalar boolean, integer or string as global constant.");
|
||||
print_usage_line(2, "Example: -define:SPAM=123");
|
||||
print_usage_line(2, "Usage in code:");
|
||||
print_usage_line(3, "#config(SPAM, default_value)");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-show-defineables");
|
||||
print_usage_line(2, "Shows an overview of all the #config/#defined usages in the project.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-export-defineables:<filename>");
|
||||
print_usage_line(2, "Exports an overview of all the #config/#defined usages in CSV format to the given file path.");
|
||||
print_usage_line(2, "Example: -export-defineables:defineables.csv");
|
||||
if (test_only) {
|
||||
print_usage_line(1, "-all-packages");
|
||||
print_usage_line(2, "Tests all packages imported into the given initial package.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
@@ -2289,8 +2212,20 @@ gb_internal void print_show_help(String const arg0, String const &command) {
|
||||
}
|
||||
|
||||
if (check) {
|
||||
print_usage_line(1, "-target:<string>");
|
||||
print_usage_line(2, "Sets the target for the executable to be built in.");
|
||||
print_usage_line(1, "-collection:<name>=<filepath>");
|
||||
print_usage_line(2, "Defines a library collection used for imports.");
|
||||
print_usage_line(2, "Example: -collection:shared=dir/to/shared");
|
||||
print_usage_line(2, "Usage in Code:");
|
||||
print_usage_line(3, "import \"shared:foo\"");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-custom-attribute:<string>");
|
||||
print_usage_line(2, "Add a custom attribute which will be ignored if it is unknown.");
|
||||
print_usage_line(2, "This can be used with metaprogramming tools.");
|
||||
print_usage_line(2, "Examples:");
|
||||
print_usage_line(3, "-custom-attribute:my_tag");
|
||||
print_usage_line(3, "-custom-attribute:my_tag,the_other_thing");
|
||||
print_usage_line(3, "-custom-attribute:my_tag -custom-attribute:the_other_thing");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
@@ -2298,31 +2233,378 @@ gb_internal void print_show_help(String const arg0, String const &command) {
|
||||
print_usage_line(1, "-debug");
|
||||
print_usage_line(2, "Enables debug information, and defines the global constant ODIN_DEBUG to be 'true'.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (check) {
|
||||
print_usage_line(1, "-default-to-nil-allocator");
|
||||
print_usage_line(2, "Sets the default allocator to be the nil_allocator, an allocator which does nothing.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-define:<name>=<value>");
|
||||
print_usage_line(2, "Defines a scalar boolean, integer or string as global constant.");
|
||||
print_usage_line(2, "Example: -define:SPAM=123");
|
||||
print_usage_line(2, "Usage in code:");
|
||||
print_usage_line(3, "#config(SPAM, default_value)");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (run_or_build) {
|
||||
print_usage_line(1, "-disable-assert");
|
||||
print_usage_line(2, "Disables the code generation of the built-in run-time 'assert' procedure, and defines the global constant ODIN_DISABLE_ASSERT to be 'true'.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-disable-red-zone");
|
||||
print_usage_line(2, "Disables red zone on a supported freestanding target.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (check) {
|
||||
print_usage_line(1, "-disallow-do");
|
||||
print_usage_line(2, "Disallows the 'do' keyword in the project.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (doc) {
|
||||
print_usage_line(1, "-doc-format");
|
||||
print_usage_line(2, "Generates documentation as the .odin-doc format (useful for external tooling).");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (run_or_build) {
|
||||
print_usage_line(1, "-dynamic-map-calls");
|
||||
print_usage_line(2, "Uses dynamic map calls to minimize code generation at the cost of runtime execution.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (check) {
|
||||
print_usage_line(1, "-error-pos-style:<string>");
|
||||
print_usage_line(2, "Available options:");
|
||||
print_usage_line(3, "-error-pos-style:unix file/path:45:3:");
|
||||
print_usage_line(3, "-error-pos-style:odin file/path(45:3)");
|
||||
print_usage_line(3, "-error-pos-style:default (Defaults to 'odin'.)");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-export-defineables:<filename>");
|
||||
print_usage_line(2, "Exports an overview of all the #config/#defined usages in CSV format to the given file path.");
|
||||
print_usage_line(2, "Example: -export-defineables:defineables.csv");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-export-dependencies:<format>");
|
||||
print_usage_line(2, "Exports dependencies to one of a few formats. Requires `-export-dependencies-file`.");
|
||||
print_usage_line(2, "Available options:");
|
||||
print_usage_line(3, "-export-dependencies:make Exports in Makefile format");
|
||||
print_usage_line(3, "-export-dependencies:json Exports in JSON format");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-export-dependencies-file:<filename>");
|
||||
print_usage_line(2, "Specifies the filename for `-export-dependencies`.");
|
||||
print_usage_line(2, "Example: -export-dependencies-file:dependencies.d");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-export-timings:<format>");
|
||||
print_usage_line(2, "Exports timings to one of a few formats. Requires `-show-timings` or `-show-more-timings`.");
|
||||
print_usage_line(2, "Available options:");
|
||||
print_usage_line(3, "-export-timings:json Exports compile time stats to JSON.");
|
||||
print_usage_line(3, "-export-timings:csv Exports compile time stats to CSV.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-export-timings-file:<filename>");
|
||||
print_usage_line(2, "Specifies the filename for `-export-timings`.");
|
||||
print_usage_line(2, "Example: -export-timings-file:timings.json");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (run_or_build) {
|
||||
print_usage_line(1, "-extra-assembler-flags:<string>");
|
||||
print_usage_line(2, "Adds extra assembler specific flags in a string.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-extra-linker-flags:<string>");
|
||||
print_usage_line(2, "Adds extra linker specific flags in a string.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (check) {
|
||||
print_usage_line(1, "-file");
|
||||
print_usage_line(2, "Tells `%.*s %.*s` to treat the given file as a self-contained package.", LIT(arg0), LIT(command));
|
||||
print_usage_line(2, "This means that `<dir>/a.odin` won't have access to `<dir>/b.odin`'s contents.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-foreign-error-procedures");
|
||||
print_usage_line(2, "States that the error procedures used in the runtime are defined in a separate translation unit.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-ignore-unknown-attributes");
|
||||
print_usage_line(2, "Ignores unknown attributes.");
|
||||
print_usage_line(2, "This can be used with metaprogramming tools.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (run_or_build) {
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
print_usage_line(1, "-ignore-vs-search");
|
||||
print_usage_line(2, "[Windows only]");
|
||||
print_usage_line(2, "Ignores the Visual Studio search for library paths.");
|
||||
print_usage_line(0, "");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (check) {
|
||||
print_usage_line(1, "-ignore-warnings");
|
||||
print_usage_line(2, "Ignores warning messages.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-json-errors");
|
||||
print_usage_line(2, "Prints the error messages as json to stderr.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (run_or_build) {
|
||||
print_usage_line(1, "-keep-temp-files");
|
||||
print_usage_line(2, "Keeps the temporary files generated during compilation.");
|
||||
print_usage_line(0, "");
|
||||
} else if (strip_semicolon) {
|
||||
print_usage_line(1, "-keep-temp-files");
|
||||
print_usage_line(2, "Keeps the temporary files generated during stripping the unneeded semicolons from files.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (run_or_build) {
|
||||
print_usage_line(1, "-lld");
|
||||
print_usage_line(2, "Uses the LLD linker rather than the default.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (check) {
|
||||
print_usage_line(1, "-max-error-count:<integer>");
|
||||
print_usage_line(2, "Sets the maximum number of errors that can be displayed before the compiler terminates.");
|
||||
print_usage_line(2, "Must be an integer >0.");
|
||||
print_usage_line(2, "If not set, the default max error count is %d.", DEFAULT_MAX_ERROR_COLLECTOR_COUNT);
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (run_or_build) {
|
||||
print_usage_line(1, "-microarch:<string>");
|
||||
print_usage_line(2, "Specifies the specific micro-architecture for the build in a string.");
|
||||
print_usage_line(2, "Examples:");
|
||||
print_usage_line(3, "-microarch:sandybridge");
|
||||
print_usage_line(3, "-microarch:native");
|
||||
print_usage_line(3, "-microarch:\"?\" for a list");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (check) {
|
||||
print_usage_line(1, "-min-link-libs");
|
||||
print_usage_line(2, "If set, the number of linked libraries will be minimized to prevent duplications.");
|
||||
print_usage_line(2, "This is useful for so called \"dumb\" linkers compared to \"smart\" linkers.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (run_or_build) {
|
||||
print_usage_line(1, "-minimum-os-version:<string>");
|
||||
print_usage_line(2, "Sets the minimum OS version targeted by the application.");
|
||||
print_usage_line(2, "Default: -minimum-os-version:11.0.0");
|
||||
print_usage_line(2, "Only used when target is Darwin, if given, linking mismatched versions will emit a warning.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-no-bounds-check");
|
||||
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, "");
|
||||
}
|
||||
|
||||
if (check && command != "test") {
|
||||
print_usage_line(1, "-no-entry-point");
|
||||
print_usage_line(2, "Removes default requirement of an entry point (e.g. main procedure).");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (run_or_build) {
|
||||
print_usage_line(1, "-no-rpath");
|
||||
print_usage_line(2, "Disables automatic addition of an rpath linked to the executable directory.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-no-thread-local");
|
||||
print_usage_line(2, "Ignores @thread_local attribute, effectively treating the program as if it is single-threaded.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-lld");
|
||||
print_usage_line(2, "Uses the LLD linker rather than the default.");
|
||||
print_usage_line(1, "-no-threaded-checker");
|
||||
print_usage_line(2, "Disables multithreading in the semantic checker stage.");
|
||||
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, "");
|
||||
}
|
||||
|
||||
if (run_or_build) {
|
||||
print_usage_line(1, "-o:<string>");
|
||||
print_usage_line(2, "Sets the optimization mode for compilation.");
|
||||
print_usage_line(2, "Available options:");
|
||||
print_usage_line(3, "-o:none");
|
||||
print_usage_line(3, "-o:minimal");
|
||||
print_usage_line(3, "-o:size");
|
||||
print_usage_line(3, "-o:speed");
|
||||
if (LB_USE_NEW_PASS_SYSTEM) {
|
||||
print_usage_line(3, "-o:aggressive (use this with caution)");
|
||||
}
|
||||
print_usage_line(2, "The default is -o:minimal.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
|
||||
print_usage_line(1, "-obfuscate-source-code-locations");
|
||||
print_usage_line(2, "Obfuscate the file and procedure strings, and line and column numbers, stored with a 'runtime.Source_Code_Location' value.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
|
||||
print_usage_line(1, "-out:<filepath>");
|
||||
print_usage_line(2, "Sets the file name of the outputted executable.");
|
||||
print_usage_line(2, "Example: -out:foo.exe");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (doc) {
|
||||
print_usage_line(1, "-out:<filepath>");
|
||||
print_usage_line(2, "Sets the base name of the resultig .odin-doc file.");
|
||||
print_usage_line(2, "The extension can be optionally included; the resulting file will always have an extension of '.odin-doc'.");
|
||||
print_usage_line(2, "Example: -out:foo");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (run_or_build) {
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
print_usage_line(1, "-pdb-name:<filepath>");
|
||||
print_usage_line(2, "[Windows only]");
|
||||
print_usage_line(2, "Defines the generated PDB name when -debug is enabled.");
|
||||
print_usage_line(2, "Example: -pdb-name:different.pdb");
|
||||
print_usage_line(0, "");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (build) {
|
||||
print_usage_line(1, "-print-linker-flags");
|
||||
print_usage_line(2, "Prints the all of the flags/arguments that will be passed to the linker.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (run_or_build) {
|
||||
print_usage_line(1, "-reloc-mode:<string>");
|
||||
print_usage_line(2, "Specifies the reloc mode.");
|
||||
print_usage_line(2, "Available options:");
|
||||
print_usage_line(3, "-reloc-mode:default");
|
||||
print_usage_line(3, "-reloc-mode:static");
|
||||
print_usage_line(3, "-reloc-mode:pic");
|
||||
print_usage_line(3, "-reloc-mode:dynamic-no-pic");
|
||||
print_usage_line(0, "");
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
print_usage_line(1, "-resource:<filepath>");
|
||||
print_usage_line(2, "[Windows only]");
|
||||
print_usage_line(2, "Defines the resource file for the executable.");
|
||||
print_usage_line(2, "Example: -resource:path/to/file.rc");
|
||||
print_usage_line(2, "or: -resource:path/to/file.res for a precompiled one.");
|
||||
print_usage_line(0, "");
|
||||
#endif
|
||||
|
||||
print_usage_line(1, "-sanitize:<string>");
|
||||
print_usage_line(2, "Enables sanitization analysis.");
|
||||
print_usage_line(2, "Available options:");
|
||||
print_usage_line(3, "-sanitize:address");
|
||||
print_usage_line(3, "-sanitize:memory");
|
||||
print_usage_line(3, "-sanitize:thread");
|
||||
print_usage_line(2, "NOTE: This flag can be used multiple times.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (doc) {
|
||||
print_usage_line(1, "-short");
|
||||
print_usage_line(2, "Shows shortened documentation for the packages.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (check) {
|
||||
print_usage_line(1, "-show-defineables");
|
||||
print_usage_line(2, "Shows an overview of all the #config/#defined usages in the project.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-show-system-calls");
|
||||
print_usage_line(2, "Prints the whole command and arguments for calls to external tools like linker and assembler.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-show-timings");
|
||||
print_usage_line(2, "Shows basic overview of the timings of different stages within the compiler in milliseconds.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-show-more-timings");
|
||||
print_usage_line(2, "Shows an advanced overview of the timings of different stages within the compiler in milliseconds.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (check_only) {
|
||||
print_usage_line(1, "-show-unused");
|
||||
print_usage_line(2, "Shows unused package declarations within the current project.");
|
||||
print_usage_line(0, "");
|
||||
print_usage_line(1, "-show-unused-with-location");
|
||||
print_usage_line(2, "Shows unused package declarations within the current project with the declarations source location.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (check) {
|
||||
print_usage_line(1, "-strict-style");
|
||||
print_usage_line(2, "This enforces parts of same style as the Odin compiler, prefer '-vet-style -vet-semicolon' if you do not want to match it exactly.");
|
||||
print_usage_line(2, "");
|
||||
print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons.");
|
||||
print_usage_line(2, "Errs on missing trailing commas followed by a newline.");
|
||||
print_usage_line(2, "Errs on deprecated syntax.");
|
||||
print_usage_line(2, "Errs when the attached-brace style in not adhered to (also known as 1TBS).");
|
||||
print_usage_line(2, "Errs when 'case' labels are not in the same column as the associated 'switch' token.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (run_or_build) {
|
||||
print_usage_line(1, "-strict-target-features");
|
||||
print_usage_line(2, "Makes @(enable_target_features=\"...\") behave the same way as @(require_target_features=\"...\").");
|
||||
print_usage_line(2, "This enforces that all generated code uses features supported by the combination of -target, -microarch, and -target-features.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
print_usage_line(1, "-subsystem:<option>");
|
||||
print_usage_line(2, "[Windows only]");
|
||||
print_usage_line(2, "Defines the subsystem for the application.");
|
||||
print_usage_line(2, "Available options:");
|
||||
print_usage_line(3, "-subsystem:console");
|
||||
print_usage_line(3, "-subsystem:windows");
|
||||
print_usage_line(0, "");
|
||||
#endif
|
||||
|
||||
print_usage_line(1, "-target-features:<string>");
|
||||
print_usage_line(2, "Specifies CPU features to enable on top of the enabled features implied by -microarch.");
|
||||
print_usage_line(2, "Examples:");
|
||||
print_usage_line(3, "-target-features:atomics");
|
||||
print_usage_line(3, "-target-features:\"sse2,aes\"");
|
||||
print_usage_line(3, "-target-features:\"?\" for a list");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (check) {
|
||||
print_usage_line(1, "-target:<string>");
|
||||
print_usage_line(2, "Sets the target for the executable to be built in.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-terse-errors");
|
||||
print_usage_line(2, "Prints a terse error message without showing the code on that line and the location in that line.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-thread-count:<integer>");
|
||||
print_usage_line(2, "Overrides the number of threads the compiler will use to compile with.");
|
||||
print_usage_line(2, "Example: -thread-count:2");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (run_or_build) {
|
||||
print_usage_line(1, "-use-separate-modules");
|
||||
print_usage_line(2, "The backend generates multiple build units which are then linked together.");
|
||||
print_usage_line(2, "Normally, a single build unit is generated for a standard project.");
|
||||
@@ -2331,11 +2613,6 @@ gb_internal void print_show_help(String const arg0, String const &command) {
|
||||
|
||||
}
|
||||
|
||||
if (check) {
|
||||
print_usage_line(1, "-no-threaded-checker");
|
||||
print_usage_line(2, "Disables multithreading in the semantic checker stage.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (check) {
|
||||
print_usage_line(1, "-vet");
|
||||
@@ -2348,243 +2625,69 @@ gb_internal void print_show_help(String const arg0, String const &command) {
|
||||
print_usage_line(3, "-vet-using-stmt");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-vet-unused");
|
||||
print_usage_line(2, "Checks for unused declarations.");
|
||||
print_usage_line(1, "-vet-cast");
|
||||
print_usage_line(2, "Errs on casting a value to its own type or using `transmute` rather than `cast`.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-vet-unused-variables");
|
||||
print_usage_line(2, "Checks for unused variable declarations.");
|
||||
print_usage_line(1, "-vet-packages:<comma-separated-strings>");
|
||||
print_usage_line(2, "Sets which packages by name will be vetted.");
|
||||
print_usage_line(2, "Files with specific +vet tags will not be ignored if they are not in the packages set.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-vet-unused-imports");
|
||||
print_usage_line(2, "Checks for unused import declarations.");
|
||||
print_usage_line(1, "-vet-semicolon");
|
||||
print_usage_line(2, "Errs on unneeded semicolons.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
|
||||
print_usage_line(1, "-vet-shadowing");
|
||||
print_usage_line(2, "Checks for variable shadowing within procedures.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-vet-using-stmt");
|
||||
print_usage_line(2, "Checks for the use of 'using' as a statement.");
|
||||
print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-vet-using-param");
|
||||
print_usage_line(2, "Checks for the use of 'using' on procedure parameters.");
|
||||
print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-vet-style");
|
||||
print_usage_line(2, "Errs on missing trailing commas followed by a newline.");
|
||||
print_usage_line(2, "Errs on deprecated syntax.");
|
||||
print_usage_line(2, "Does not err on unneeded tokens (unlike -strict-style).");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-vet-semicolon");
|
||||
print_usage_line(2, "Errs on unneeded semicolons.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-vet-cast");
|
||||
print_usage_line(2, "Errs on casting a value to its own type or using `transmute` rather than `cast`.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-vet-tabs");
|
||||
print_usage_line(2, "Errs when the use of tabs has not been used for indentation.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (check) {
|
||||
print_usage_line(1, "-custom-attribute:<string>");
|
||||
print_usage_line(2, "Add a custom attribute which will be ignored if it is unknown.");
|
||||
print_usage_line(2, "This can be used with metaprogramming tools.");
|
||||
print_usage_line(2, "Examples:");
|
||||
print_usage_line(3, "-custom-attribute:my_tag");
|
||||
print_usage_line(3, "-custom-attribute:my_tag,the_other_thing");
|
||||
print_usage_line(3, "-custom-attribute:my_tag -custom-attribute:the_other_thing");
|
||||
|
||||
print_usage_line(1, "-vet-unused");
|
||||
print_usage_line(2, "Checks for unused declarations (variables and imports).");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-ignore-unknown-attributes");
|
||||
print_usage_line(2, "Ignores unknown attributes.");
|
||||
print_usage_line(2, "This can be used with metaprogramming tools.");
|
||||
print_usage_line(1, "-vet-unused-imports");
|
||||
print_usage_line(2, "Checks for unused import declarations.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
if (command != "test") {
|
||||
print_usage_line(1, "-no-entry-point");
|
||||
print_usage_line(2, "Removes default requirement of an entry point (e.g. main procedure).");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
}
|
||||
|
||||
if (test_only) {
|
||||
print_usage_line(1, "-all-packages");
|
||||
print_usage_line(2, "Tests all packages imported into the given initial package.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (run_or_build) {
|
||||
print_usage_line(1, "-minimum-os-version:<string>");
|
||||
print_usage_line(2, "Sets the minimum OS version targeted by the application.");
|
||||
print_usage_line(2, "Default: -minimum-os-version:11.0.0");
|
||||
print_usage_line(2, "Only used when target is Darwin, if given, linking mismatched versions will emit a warning.");
|
||||
print_usage_line(1, "-vet-unused-procedures");
|
||||
print_usage_line(2, "Checks for unused procedures.");
|
||||
print_usage_line(2, "Must be used with -vet-packages or specified on a per file with +vet tags.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-extra-linker-flags:<string>");
|
||||
print_usage_line(2, "Adds extra linker specific flags in a string.");
|
||||
print_usage_line(1, "-vet-unused-variables");
|
||||
print_usage_line(2, "Checks for unused variable declarations.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-extra-assembler-flags:<string>");
|
||||
print_usage_line(2, "Adds extra assembler specific flags in a string.");
|
||||
|
||||
print_usage_line(1, "-vet-using-param");
|
||||
print_usage_line(2, "Checks for the use of 'using' on procedure parameters.");
|
||||
print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-microarch:<string>");
|
||||
print_usage_line(2, "Specifies the specific micro-architecture for the build in a string.");
|
||||
print_usage_line(2, "Examples:");
|
||||
print_usage_line(3, "-microarch:sandybridge");
|
||||
print_usage_line(3, "-microarch:native");
|
||||
print_usage_line(3, "-microarch:\"?\" for a list");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-target-features:<string>");
|
||||
print_usage_line(2, "Specifies CPU features to enable on top of the enabled features implied by -microarch.");
|
||||
print_usage_line(2, "Examples:");
|
||||
print_usage_line(3, "-target-features:atomics");
|
||||
print_usage_line(3, "-target-features:\"sse2,aes\"");
|
||||
print_usage_line(3, "-target-features:\"?\" for a list");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-strict-target-features");
|
||||
print_usage_line(2, "Makes @(enable_target_features=\"...\") behave the same way as @(require_target_features=\"...\").");
|
||||
print_usage_line(2, "This enforces that all generated code uses features supported by the combination of -target, -microarch, and -target-features.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-reloc-mode:<string>");
|
||||
print_usage_line(2, "Specifies the reloc mode.");
|
||||
print_usage_line(2, "Available options:");
|
||||
print_usage_line(3, "-reloc-mode:default");
|
||||
print_usage_line(3, "-reloc-mode:static");
|
||||
print_usage_line(3, "-reloc-mode:pic");
|
||||
print_usage_line(3, "-reloc-mode:dynamic-no-pic");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-disable-red-zone");
|
||||
print_usage_line(2, "Disables red zone on a supported freestanding target.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-dynamic-map-calls");
|
||||
print_usage_line(2, "Uses dynamic map calls to minimize code generation at the cost of runtime execution.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (build) {
|
||||
print_usage_line(1, "-print-linker-flags");
|
||||
print_usage_line(2, "Prints the all of the flags/arguments that will be passed to the linker.");
|
||||
print_usage_line(1, "-vet-using-stmt");
|
||||
print_usage_line(2, "Checks for the use of 'using' as a statement.");
|
||||
print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring.");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (check) {
|
||||
print_usage_line(1, "-disallow-do");
|
||||
print_usage_line(2, "Disallows the 'do' keyword in the project.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-default-to-nil-allocator");
|
||||
print_usage_line(2, "Sets the default allocator to be the nil_allocator, an allocator which does nothing.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-strict-style");
|
||||
print_usage_line(2, "This enforces parts of same style as the Odin compiler, prefer '-vet-style -vet-semicolon' if you do not want to match it exactly.");
|
||||
print_usage_line(2, "");
|
||||
print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons.");
|
||||
print_usage_line(2, "Errs on missing trailing commas followed by a newline.");
|
||||
print_usage_line(2, "Errs on deprecated syntax.");
|
||||
print_usage_line(2, "Errs when the attached-brace style in not adhered to (also known as 1TBS).");
|
||||
print_usage_line(2, "Errs when 'case' labels are not in the same column as the associated 'switch' token.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-ignore-warnings");
|
||||
print_usage_line(2, "Ignores warning messages.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-warnings-as-errors");
|
||||
print_usage_line(2, "Treats warning messages as error messages.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-terse-errors");
|
||||
print_usage_line(2, "Prints a terse error message without showing the code on that line and the location in that line.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-json-errors");
|
||||
print_usage_line(2, "Prints the error messages as json to stderr.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-error-pos-style:<string>");
|
||||
print_usage_line(2, "Available options:");
|
||||
print_usage_line(3, "-error-pos-style:unix file/path:45:3:");
|
||||
print_usage_line(3, "-error-pos-style:odin file/path(45:3)");
|
||||
print_usage_line(3, "-error-pos-style:default (Defaults to 'odin'.)");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-max-error-count:<integer>");
|
||||
print_usage_line(2, "Sets the maximum number of errors that can be displayed before the compiler terminates.");
|
||||
print_usage_line(2, "Must be an integer >0.");
|
||||
print_usage_line(2, "If not set, the default max error count is %d.", DEFAULT_MAX_ERROR_COLLECTOR_COUNT);
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-min-link-libs");
|
||||
print_usage_line(2, "If set, the number of linked libraries will be minimized to prevent duplications.");
|
||||
print_usage_line(2, "This is useful for so called \"dumb\" linkers compared to \"smart\" linkers.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-foreign-error-procedures");
|
||||
print_usage_line(2, "States that the error procedures used in the runtime are defined in a separate translation unit.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
}
|
||||
|
||||
if (run_or_build) {
|
||||
print_usage_line(1, "-obfuscate-source-code-locations");
|
||||
print_usage_line(2, "Obfuscate the file and procedure strings, and line and column numbers, stored with a 'runtime.Source_Code_Location' value.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-sanitize:<string>");
|
||||
print_usage_line(2, "Enables sanitization analysis.");
|
||||
print_usage_line(2, "Available options:");
|
||||
print_usage_line(3, "-sanitize:address");
|
||||
print_usage_line(3, "-sanitize:memory");
|
||||
print_usage_line(3, "-sanitize:thread");
|
||||
print_usage_line(2, "NOTE: This flag can be used multiple times.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
}
|
||||
|
||||
if (run_or_build) {
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
print_usage_line(1, "-ignore-vs-search");
|
||||
print_usage_line(2, "[Windows only]");
|
||||
print_usage_line(2, "Ignores the Visual Studio search for library paths.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-resource:<filepath>");
|
||||
print_usage_line(2, "[Windows only]");
|
||||
print_usage_line(2, "Defines the resource file for the executable.");
|
||||
print_usage_line(2, "Example: -resource:path/to/file.rc");
|
||||
print_usage_line(2, "or: -resource:path/to/file.res for a precompiled one.");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-pdb-name:<filepath>");
|
||||
print_usage_line(2, "[Windows only]");
|
||||
print_usage_line(2, "Defines the generated PDB name when -debug is enabled.");
|
||||
print_usage_line(2, "Example: -pdb-name:different.pdb");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-subsystem:<option>");
|
||||
print_usage_line(2, "[Windows only]");
|
||||
print_usage_line(2, "Defines the subsystem for the application.");
|
||||
print_usage_line(2, "Available options:");
|
||||
print_usage_line(3, "-subsystem:console");
|
||||
print_usage_line(3, "-subsystem:windows");
|
||||
print_usage_line(0, "");
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3135,6 +3238,9 @@ int main(int arg_count, char const **arg_ptr) {
|
||||
|
||||
build_context.command = command;
|
||||
|
||||
string_set_init(&build_context.custom_attributes);
|
||||
string_set_init(&build_context.vet_packages);
|
||||
|
||||
if (!parse_build_flags(args)) {
|
||||
return 1;
|
||||
}
|
||||
@@ -3304,10 +3410,6 @@ int main(int arg_count, char const **arg_ptr) {
|
||||
print_all_errors();
|
||||
return 1;
|
||||
}
|
||||
if (any_warnings()) {
|
||||
print_all_errors();
|
||||
}
|
||||
|
||||
|
||||
checker->parser = parser;
|
||||
init_checker(checker);
|
||||
|
||||
+193
-91
@@ -1,10 +1,28 @@
|
||||
#include "parser_pos.cpp"
|
||||
|
||||
gb_internal bool in_vet_packages(AstFile *file) {
|
||||
if (file == nullptr) {
|
||||
return true;
|
||||
}
|
||||
if (file->pkg == nullptr) {
|
||||
return true;
|
||||
}
|
||||
if (build_context.vet_packages.entries.count == 0) {
|
||||
return true;
|
||||
}
|
||||
return string_set_exists(&build_context.vet_packages, file->pkg->name);
|
||||
}
|
||||
|
||||
gb_internal u64 ast_file_vet_flags(AstFile *f) {
|
||||
if (f != nullptr && f->vet_flags_set) {
|
||||
return f->vet_flags;
|
||||
}
|
||||
return build_context.vet_flags;
|
||||
|
||||
bool found = in_vet_packages(f);
|
||||
if (found) {
|
||||
return build_context.vet_flags;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
gb_internal bool ast_file_vet_style(AstFile *f) {
|
||||
@@ -430,7 +448,8 @@ gb_internal Ast *clone_ast(Ast *node, AstFile *f) {
|
||||
n->StructType.fields = clone_ast_array(n->StructType.fields, f);
|
||||
n->StructType.polymorphic_params = clone_ast(n->StructType.polymorphic_params, f);
|
||||
n->StructType.align = clone_ast(n->StructType.align, f);
|
||||
n->StructType.field_align = clone_ast(n->StructType.field_align, f);
|
||||
n->StructType.min_field_align = clone_ast(n->StructType.min_field_align, f);
|
||||
n->StructType.max_field_align = clone_ast(n->StructType.max_field_align, f);
|
||||
n->StructType.where_clauses = clone_ast_array(n->StructType.where_clauses, f);
|
||||
break;
|
||||
case Ast_UnionType:
|
||||
@@ -1199,7 +1218,7 @@ gb_internal Ast *ast_dynamic_array_type(AstFile *f, Token token, Ast *elem) {
|
||||
|
||||
gb_internal Ast *ast_struct_type(AstFile *f, Token token, Slice<Ast *> fields, isize field_count,
|
||||
Ast *polymorphic_params, bool is_packed, bool is_raw_union, bool is_no_copy,
|
||||
Ast *align, Ast *field_align,
|
||||
Ast *align, Ast *min_field_align, Ast *max_field_align,
|
||||
Token where_token, Array<Ast *> const &where_clauses) {
|
||||
Ast *result = alloc_ast_node(f, Ast_StructType);
|
||||
result->StructType.token = token;
|
||||
@@ -1210,7 +1229,8 @@ gb_internal Ast *ast_struct_type(AstFile *f, Token token, Slice<Ast *> fields, i
|
||||
result->StructType.is_raw_union = is_raw_union;
|
||||
result->StructType.is_no_copy = is_no_copy;
|
||||
result->StructType.align = align;
|
||||
result->StructType.field_align = field_align;
|
||||
result->StructType.min_field_align = min_field_align;
|
||||
result->StructType.max_field_align = max_field_align;
|
||||
result->StructType.where_token = where_token;
|
||||
result->StructType.where_clauses = slice_from_array(where_clauses);
|
||||
return result;
|
||||
@@ -2739,7 +2759,8 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
bool is_raw_union = false;
|
||||
bool no_copy = false;
|
||||
Ast *align = nullptr;
|
||||
Ast *field_align = nullptr;
|
||||
Ast *min_field_align = nullptr;
|
||||
Ast *max_field_align = nullptr;
|
||||
|
||||
if (allow_token(f, Token_OpenParen)) {
|
||||
isize param_count = 0;
|
||||
@@ -2777,18 +2798,43 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
gb_string_free(s);
|
||||
}
|
||||
} else if (tag.string == "field_align") {
|
||||
if (field_align) {
|
||||
if (min_field_align) {
|
||||
syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string));
|
||||
}
|
||||
field_align = parse_expr(f, true);
|
||||
if (field_align && field_align->kind != Ast_ParenExpr) {
|
||||
syntax_warning(tag, "#field_align has been deprecated in favour of #min_field_align");
|
||||
min_field_align = parse_expr(f, true);
|
||||
if (min_field_align && min_field_align->kind != Ast_ParenExpr) {
|
||||
ERROR_BLOCK();
|
||||
gbString s = expr_to_string(field_align);
|
||||
gbString s = expr_to_string(min_field_align);
|
||||
syntax_warning(tag, "#field_align requires parentheses around the expression");
|
||||
error_line("\tSuggestion: #field_align(%s)", s);
|
||||
error_line("\tSuggestion: #min_field_align(%s)", s);
|
||||
gb_string_free(s);
|
||||
}
|
||||
} else if (tag.string == "raw_union") {
|
||||
} else if (tag.string == "min_field_align") {
|
||||
if (min_field_align) {
|
||||
syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string));
|
||||
}
|
||||
min_field_align = parse_expr(f, true);
|
||||
if (min_field_align && min_field_align->kind != Ast_ParenExpr) {
|
||||
ERROR_BLOCK();
|
||||
gbString s = expr_to_string(min_field_align);
|
||||
syntax_warning(tag, "#min_field_align requires parentheses around the expression");
|
||||
error_line("\tSuggestion: #min_field_align(%s)", s);
|
||||
gb_string_free(s);
|
||||
}
|
||||
} else if (tag.string == "max_field_align") {
|
||||
if (max_field_align) {
|
||||
syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string));
|
||||
}
|
||||
max_field_align = parse_expr(f, true);
|
||||
if (max_field_align && max_field_align->kind != Ast_ParenExpr) {
|
||||
ERROR_BLOCK();
|
||||
gbString s = expr_to_string(max_field_align);
|
||||
syntax_warning(tag, "#max_field_align requires parentheses around the expression");
|
||||
error_line("\tSuggestion: #max_field_align(%s)", s);
|
||||
gb_string_free(s);
|
||||
}
|
||||
}else if (tag.string == "raw_union") {
|
||||
if (is_raw_union) {
|
||||
syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string));
|
||||
}
|
||||
@@ -2838,7 +2884,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
|
||||
parser_check_polymorphic_record_parameters(f, polymorphic_params);
|
||||
|
||||
return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_raw_union, no_copy, align, field_align, where_token, where_clauses);
|
||||
return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_raw_union, no_copy, align, min_field_align, max_field_align, where_token, where_clauses);
|
||||
} break;
|
||||
|
||||
case Token_union: {
|
||||
@@ -4359,10 +4405,14 @@ gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_fl
|
||||
}
|
||||
}
|
||||
|
||||
allow_field_separator(f);
|
||||
bool more_fields = allow_field_separator(f);
|
||||
Ast *param = ast_field(f, names, type, default_value, set_flags, tag, docs, f->line_comment);
|
||||
array_add(¶ms, param);
|
||||
|
||||
if (!more_fields) {
|
||||
if (name_count_) *name_count_ = total_name_count;
|
||||
return ast_field_list(f, start_token, params);
|
||||
}
|
||||
|
||||
while (f->curr_token.kind != follow &&
|
||||
f->curr_token.kind != Token_EOF &&
|
||||
@@ -4949,7 +4999,7 @@ gb_internal Ast *parse_import_decl(AstFile *f, ImportDeclKind kind) {
|
||||
}
|
||||
|
||||
if (f->in_when_statement) {
|
||||
syntax_error(import_name, "Cannot use 'import' within a 'when' statement. Prefer using the file suffixes (e.g. foo_windows.odin) or '//+build' tags");
|
||||
syntax_error(import_name, "Cannot use 'import' within a 'when' statement. Prefer using the file suffixes (e.g. foo_windows.odin) or '#+build' tags");
|
||||
}
|
||||
|
||||
if (kind != ImportDecl_Standard) {
|
||||
@@ -5337,6 +5387,12 @@ gb_internal Ast *parse_stmt(AstFile *f) {
|
||||
s = ast_empty_stmt(f, token);
|
||||
expect_semicolon(f);
|
||||
return s;
|
||||
|
||||
case Token_FileTag:
|
||||
// This is always an error because all valid file tags will have been processed in `parse_file` already.
|
||||
// Any remaining file tags must be past the package line and thus invalid.
|
||||
syntax_error(token, "Lines starting with #+ (file tags) are only allowed before the package line.");
|
||||
return ast_bad_stmt(f, token, f->curr_token);
|
||||
}
|
||||
|
||||
// Error correction statements
|
||||
@@ -5372,18 +5428,9 @@ gb_internal Ast *parse_stmt(AstFile *f) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
gb_internal u64 check_vet_flags(AstFile *file) {
|
||||
if (file && file->vet_flags_set) {
|
||||
return file->vet_flags;
|
||||
}
|
||||
return build_context.vet_flags;
|
||||
}
|
||||
|
||||
|
||||
gb_internal void parse_enforce_tabs(AstFile *f) {
|
||||
// Checks to see if tabs have been used for indentation
|
||||
if ((check_vet_flags(f) & VetFlag_Tabs) == 0) {
|
||||
if ((ast_file_vet_flags(f) & VetFlag_Tabs) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5969,20 +6016,6 @@ gb_internal bool determine_path_from_string(BlockingMutex *file_mutex, Ast *node
|
||||
do_error(node, "Unknown library collection: '%.*s'", LIT(collection_name));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
#if !defined(GB_SYSTEM_WINDOWS)
|
||||
// @NOTE(vassvik): foreign imports of shared libraries that are not in the system collection on
|
||||
// linux/mac have to be local to the executable for consistency with shared libraries.
|
||||
// Unix does not have a concept of "import library" for shared/dynamic libraries,
|
||||
// so we need to pass the relative path to the linker, and add the current
|
||||
// working directory of the exe to the library search paths.
|
||||
// Static libraries can be linked directly with the full pathname
|
||||
//
|
||||
if (node->kind == Ast_ForeignImportDecl && (string_ends_with(file_str, str_lit(".so")) || string_contains_string(file_str, str_lit(".so.")))) {
|
||||
*path = file_str;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (is_package_name_reserved(file_str)) {
|
||||
@@ -6128,7 +6161,7 @@ gb_internal String build_tag_get_token(String s, String *out) {
|
||||
}
|
||||
|
||||
gb_internal bool parse_build_tag(Token token_for_pos, String s) {
|
||||
String const prefix = str_lit("+build");
|
||||
String const prefix = str_lit("build");
|
||||
GB_ASSERT(string_starts_with(s, prefix));
|
||||
s = string_trim_whitespace(substring(s, prefix.len, s.len));
|
||||
|
||||
@@ -6141,6 +6174,10 @@ gb_internal bool parse_build_tag(Token token_for_pos, String s) {
|
||||
while (s.len > 0) {
|
||||
bool this_kind_correct = true;
|
||||
|
||||
bool this_kind_os_seen = false;
|
||||
bool this_kind_arch_seen = false;
|
||||
int num_tokens = 0;
|
||||
|
||||
do {
|
||||
String p = string_trim_whitespace(build_tag_get_token(s, &s));
|
||||
if (p.len == 0) break;
|
||||
@@ -6166,7 +6203,18 @@ gb_internal bool parse_build_tag(Token token_for_pos, String s) {
|
||||
|
||||
TargetOsKind os = get_target_os_from_string(p);
|
||||
TargetArchKind arch = get_target_arch_from_string(p);
|
||||
num_tokens += 1;
|
||||
|
||||
// Catches 'windows linux', which is an impossible combination.
|
||||
// Also catches usage of more than two things within a comma separated group.
|
||||
if (num_tokens > 2 || (this_kind_os_seen && os != TargetOs_Invalid) || (this_kind_arch_seen && arch != TargetArch_Invalid)) {
|
||||
syntax_error(token_for_pos, "Invalid build tag: Missing ',' before '%.*s'. Format: '#+build linux, windows amd64, darwin'", LIT(p));
|
||||
break;
|
||||
}
|
||||
|
||||
if (os != TargetOs_Invalid) {
|
||||
this_kind_os_seen = true;
|
||||
|
||||
GB_ASSERT(arch == TargetArch_Invalid);
|
||||
if (is_notted) {
|
||||
this_kind_correct = this_kind_correct && (os != build_context.metrics.os);
|
||||
@@ -6174,6 +6222,8 @@ gb_internal bool parse_build_tag(Token token_for_pos, String s) {
|
||||
this_kind_correct = this_kind_correct && (os == build_context.metrics.os);
|
||||
}
|
||||
} else if (arch != TargetArch_Invalid) {
|
||||
this_kind_arch_seen = true;
|
||||
|
||||
if (is_notted) {
|
||||
this_kind_correct = this_kind_correct && (arch != build_context.metrics.arch);
|
||||
} else {
|
||||
@@ -6213,7 +6263,7 @@ gb_internal String vet_tag_get_token(String s, String *out) {
|
||||
|
||||
|
||||
gb_internal u64 parse_vet_tag(Token token_for_pos, String s) {
|
||||
String const prefix = str_lit("+vet");
|
||||
String const prefix = str_lit("vet");
|
||||
GB_ASSERT(string_starts_with(s, prefix));
|
||||
s = string_trim_whitespace(substring(s, prefix.len, s.len));
|
||||
|
||||
@@ -6318,7 +6368,7 @@ gb_internal isize calc_decl_count(Ast *decl) {
|
||||
}
|
||||
|
||||
gb_internal bool parse_build_project_directory_tag(Token token_for_pos, String s) {
|
||||
String const prefix = str_lit("+build-project-name");
|
||||
String const prefix = str_lit("build-project-name");
|
||||
GB_ASSERT(string_starts_with(s, prefix));
|
||||
s = string_trim_whitespace(substring(s, prefix.len, s.len));
|
||||
if (s.len == 0) {
|
||||
@@ -6362,6 +6412,48 @@ gb_internal bool parse_build_project_directory_tag(Token token_for_pos, String s
|
||||
return any_correct;
|
||||
}
|
||||
|
||||
gb_internal bool parse_file_tag(const String &lc, const Token &tok, AstFile *f) {
|
||||
if (string_starts_with(lc, str_lit("build-project-name"))) {
|
||||
if (!parse_build_project_directory_tag(tok, lc)) {
|
||||
return false;
|
||||
}
|
||||
} else if (string_starts_with(lc, str_lit("build"))) {
|
||||
if (!parse_build_tag(tok, lc)) {
|
||||
return false;
|
||||
}
|
||||
} else if (string_starts_with(lc, str_lit("vet"))) {
|
||||
f->vet_flags = parse_vet_tag(tok, lc);
|
||||
f->vet_flags_set = true;
|
||||
} else if (string_starts_with(lc, str_lit("ignore"))) {
|
||||
return false;
|
||||
} else if (string_starts_with(lc, str_lit("private"))) {
|
||||
f->flags |= AstFile_IsPrivatePkg;
|
||||
String command = string_trim_starts_with(lc, str_lit("private "));
|
||||
command = string_trim_whitespace(command);
|
||||
if (lc == "private") {
|
||||
f->flags |= AstFile_IsPrivatePkg;
|
||||
} else if (command == "package") {
|
||||
f->flags |= AstFile_IsPrivatePkg;
|
||||
} else if (command == "file") {
|
||||
f->flags |= AstFile_IsPrivateFile;
|
||||
}
|
||||
} else if (lc == "lazy") {
|
||||
if (build_context.ignore_lazy) {
|
||||
// Ignore
|
||||
} else if (f->pkg->kind == Package_Init && build_context.command_kind == Command_doc) {
|
||||
// Ignore
|
||||
} else {
|
||||
f->flags |= AstFile_IsLazy;
|
||||
}
|
||||
} else if (lc == "no-instrumentation") {
|
||||
f->flags |= AstFile_NoInstrumentation;
|
||||
} else {
|
||||
error(tok, "Unknown tag '%.*s'", LIT(lc));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
gb_internal bool parse_file(Parser *p, AstFile *f) {
|
||||
if (f->tokens.count == 0) {
|
||||
return true;
|
||||
@@ -6380,9 +6472,34 @@ gb_internal bool parse_file(Parser *p, AstFile *f) {
|
||||
|
||||
CommentGroup *docs = f->lead_comment;
|
||||
|
||||
Array<Token> tags = array_make<Token>(temporary_allocator());
|
||||
bool first_invalid_token_set = false;
|
||||
Token first_invalid_token = {};
|
||||
|
||||
while (f->curr_token.kind != Token_package && f->curr_token.kind != Token_EOF) {
|
||||
if (f->curr_token.kind == Token_Comment) {
|
||||
consume_comment_groups(f, f->prev_token);
|
||||
} else if (f->curr_token.kind == Token_FileTag) {
|
||||
array_add(&tags, f->curr_token);
|
||||
advance_token(f);
|
||||
} else {
|
||||
if (!first_invalid_token_set) {
|
||||
first_invalid_token_set = true;
|
||||
first_invalid_token = f->curr_token;
|
||||
}
|
||||
|
||||
advance_token(f);
|
||||
}
|
||||
}
|
||||
|
||||
if (f->curr_token.kind != Token_package) {
|
||||
ERROR_BLOCK();
|
||||
syntax_error(f->curr_token, "Expected a package declaration at the beginning of the file");
|
||||
|
||||
// The while loop above scanned until it found the package token. If we never
|
||||
// found one, then make this error appear on the first invalid token line.
|
||||
Token t = first_invalid_token_set ? first_invalid_token : f->curr_token;
|
||||
syntax_error(t, "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 != "") {
|
||||
@@ -6391,18 +6508,16 @@ gb_internal bool parse_file(Parser *p, AstFile *f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// There was an OK package declaration. But there some invalid token was hit before the package declaration.
|
||||
if (first_invalid_token_set) {
|
||||
syntax_error(first_invalid_token, "Expected only comments or lines starting with '#+' before the package declaration");
|
||||
return false;
|
||||
}
|
||||
|
||||
f->package_token = expect_token(f, Token_package);
|
||||
if (f->package_token.kind != Token_package) {
|
||||
return false;
|
||||
}
|
||||
if (docs != nullptr) {
|
||||
TokenPos end = token_pos_end(docs->list[docs->list.count-1]);
|
||||
if (end.line == f->package_token.pos.line || end.line+1 == f->package_token.pos.line) {
|
||||
// Okay
|
||||
} else {
|
||||
docs = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Token package_name = expect_token_after(f, Token_Ident, "package");
|
||||
if (package_name.kind == Token_Ident) {
|
||||
@@ -6416,53 +6531,40 @@ gb_internal bool parse_file(Parser *p, AstFile *f) {
|
||||
}
|
||||
f->package_name = package_name.string;
|
||||
|
||||
if (!f->pkg->is_single_file && docs != nullptr && docs->list.count > 0) {
|
||||
for (Token const &tok : docs->list) {
|
||||
GB_ASSERT(tok.kind == Token_Comment);
|
||||
String str = tok.string;
|
||||
if (string_starts_with(str, str_lit("//"))) {
|
||||
// TODO: Shouldn't single file only matter for build tags? no-instrumentation for example
|
||||
// should be respected even when in single file mode.
|
||||
if (!f->pkg->is_single_file) {
|
||||
if (docs != nullptr && docs->list.count > 0) {
|
||||
for (Token const &tok : docs->list) {
|
||||
GB_ASSERT(tok.kind == Token_Comment);
|
||||
String str = tok.string;
|
||||
|
||||
if (!string_starts_with(str, str_lit("//"))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String lc = string_trim_whitespace(substring(str, 2, str.len));
|
||||
if (lc.len > 0 && lc[0] == '+') {
|
||||
if (string_starts_with(lc, str_lit("+build-project-name"))) {
|
||||
if (!parse_build_project_directory_tag(tok, lc)) {
|
||||
return false;
|
||||
}
|
||||
} else if (string_starts_with(lc, str_lit("+build"))) {
|
||||
if (!parse_build_tag(tok, lc)) {
|
||||
return false;
|
||||
}
|
||||
} else if (string_starts_with(lc, str_lit("+vet"))) {
|
||||
f->vet_flags = parse_vet_tag(tok, lc);
|
||||
f->vet_flags_set = true;
|
||||
} else if (string_starts_with(lc, str_lit("+ignore"))) {
|
||||
if (string_starts_with(lc, str_lit("+"))) {
|
||||
syntax_warning(tok, "'//+' is deprecated: Use '#+' instead");
|
||||
String lt = substring(lc, 1, lc.len);
|
||||
if (parse_file_tag(lt, tok, f) == false) {
|
||||
return false;
|
||||
} else if (string_starts_with(lc, str_lit("+private"))) {
|
||||
f->flags |= AstFile_IsPrivatePkg;
|
||||
String command = string_trim_starts_with(lc, str_lit("+private "));
|
||||
command = string_trim_whitespace(command);
|
||||
if (lc == "+private") {
|
||||
f->flags |= AstFile_IsPrivatePkg;
|
||||
} else if (command == "package") {
|
||||
f->flags |= AstFile_IsPrivatePkg;
|
||||
} else if (command == "file") {
|
||||
f->flags |= AstFile_IsPrivateFile;
|
||||
}
|
||||
} else if (lc == "+lazy") {
|
||||
if (build_context.ignore_lazy) {
|
||||
// Ignore
|
||||
} else if (f->pkg->kind == Package_Init && build_context.command_kind == Command_doc) {
|
||||
// Ignore
|
||||
} else {
|
||||
f->flags |= AstFile_IsLazy;
|
||||
}
|
||||
} else if (lc == "+no-instrumentation") {
|
||||
f->flags |= AstFile_NoInstrumentation;
|
||||
} else {
|
||||
warning(tok, "Ignoring unknown tag '%.*s'", LIT(lc));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Token const &tok : tags) {
|
||||
GB_ASSERT(tok.kind == Token_FileTag);
|
||||
String str = tok.string;
|
||||
|
||||
if (string_starts_with(str, str_lit("#+"))) {
|
||||
String lt = string_trim_whitespace(substring(str, 2, str.len));
|
||||
if (parse_file_tag(lt, tok, f) == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ast *pd = ast_package_decl(f, f->package_token, package_name, docs, f->line_comment);
|
||||
|
||||
+2
-1
@@ -736,7 +736,8 @@ AST_KIND(_TypeBegin, "", bool) \
|
||||
isize field_count; \
|
||||
Ast *polymorphic_params; \
|
||||
Ast *align; \
|
||||
Ast *field_align; \
|
||||
Ast *min_field_align; \
|
||||
Ast *max_field_align; \
|
||||
Token where_token; \
|
||||
Slice<Ast *> where_clauses; \
|
||||
bool is_packed; \
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
TOKEN_KIND(Token_Invalid, "Invalid"), \
|
||||
TOKEN_KIND(Token_EOF, "EOF"), \
|
||||
TOKEN_KIND(Token_Comment, "Comment"), \
|
||||
TOKEN_KIND(Token_FileTag, "FileTag"), \
|
||||
\
|
||||
TOKEN_KIND(Token__LiteralBegin, ""), \
|
||||
TOKEN_KIND(Token_Ident, "identifier"), \
|
||||
@@ -939,6 +940,20 @@ gb_internal void tokenizer_get_token(Tokenizer *t, Token *token, int repeat=0) {
|
||||
if (t->curr_rune == '!') {
|
||||
token->kind = Token_Comment;
|
||||
tokenizer_skip_line(t);
|
||||
} else if (t->curr_rune == '+') {
|
||||
token->kind = Token_FileTag;
|
||||
|
||||
// Skip until end of line or until we hit what is probably a comment.
|
||||
// The parsing of tags happens in `parse_file`.
|
||||
while (t->curr_rune != GB_RUNE_EOF) {
|
||||
if (t->curr_rune == '\n') {
|
||||
break;
|
||||
}
|
||||
if (t->curr_rune == '/') {
|
||||
break;
|
||||
}
|
||||
advance_to_next_rune(t);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '/':
|
||||
|
||||
+16
-4
@@ -137,7 +137,8 @@ struct TypeStruct {
|
||||
Scope * scope;
|
||||
|
||||
i64 custom_align;
|
||||
i64 custom_field_align;
|
||||
i64 custom_min_field_align;
|
||||
i64 custom_max_field_align;
|
||||
Type * polymorphic_params; // Type_Tuple
|
||||
Type * polymorphic_parent;
|
||||
Wait_Signal polymorphic_wait_signal;
|
||||
@@ -3912,6 +3913,14 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) {
|
||||
max = align;
|
||||
}
|
||||
}
|
||||
|
||||
if (t->Struct.custom_min_field_align > 0) {
|
||||
max = gb_max(max, t->Struct.custom_min_field_align);
|
||||
}
|
||||
if (t->Struct.custom_max_field_align != 0 &&
|
||||
t->Struct.custom_max_field_align > t->Struct.custom_min_field_align) {
|
||||
max = gb_min(max, t->Struct.custom_max_field_align);
|
||||
}
|
||||
return max;
|
||||
} break;
|
||||
|
||||
@@ -3950,7 +3959,7 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) {
|
||||
return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.max_align);
|
||||
}
|
||||
|
||||
gb_internal i64 *type_set_offsets_of(Slice<Entity *> const &fields, bool is_packed, bool is_raw_union, i64 min_field_align) {
|
||||
gb_internal i64 *type_set_offsets_of(Slice<Entity *> const &fields, bool is_packed, bool is_raw_union, i64 min_field_align, i64 max_field_align) {
|
||||
gbAllocator a = permanent_allocator();
|
||||
auto offsets = gb_alloc_array(a, i64, fields.count);
|
||||
i64 curr_offset = 0;
|
||||
@@ -3980,6 +3989,9 @@ gb_internal i64 *type_set_offsets_of(Slice<Entity *> const &fields, bool is_pack
|
||||
} else {
|
||||
Type *t = fields[i]->type;
|
||||
i64 align = gb_max(type_align_of(t), min_field_align);
|
||||
if (max_field_align > min_field_align) {
|
||||
align = gb_min(align, max_field_align);
|
||||
}
|
||||
i64 size = gb_max(type_size_of( t), 0);
|
||||
curr_offset = align_formula(curr_offset, align);
|
||||
offsets[i] = curr_offset;
|
||||
@@ -3996,7 +4008,7 @@ gb_internal bool type_set_offsets(Type *t) {
|
||||
MUTEX_GUARD(&t->Struct.offset_mutex);
|
||||
if (!t->Struct.are_offsets_set) {
|
||||
t->Struct.are_offsets_being_processed = true;
|
||||
t->Struct.offsets = type_set_offsets_of(t->Struct.fields, t->Struct.is_packed, t->Struct.is_raw_union, t->Struct.custom_field_align);
|
||||
t->Struct.offsets = type_set_offsets_of(t->Struct.fields, t->Struct.is_packed, t->Struct.is_raw_union, t->Struct.custom_min_field_align, t->Struct.custom_max_field_align);
|
||||
t->Struct.are_offsets_being_processed = false;
|
||||
t->Struct.are_offsets_set = true;
|
||||
return true;
|
||||
@@ -4005,7 +4017,7 @@ gb_internal bool type_set_offsets(Type *t) {
|
||||
MUTEX_GUARD(&t->Tuple.mutex);
|
||||
if (!t->Tuple.are_offsets_set) {
|
||||
t->Tuple.are_offsets_being_processed = true;
|
||||
t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, t->Tuple.is_packed, false, 1);
|
||||
t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, t->Tuple.is_packed, false, 1, 0);
|
||||
t->Tuple.are_offsets_being_processed = false;
|
||||
t->Tuple.are_offsets_set = true;
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user