mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-31 05:20:09 +00:00
Merge tag 'dev-2025-07'
This commit is contained in:
@@ -540,6 +540,7 @@ gb_internal void report_os_info() {
|
||||
}
|
||||
|
||||
switch (major) {
|
||||
case 26: gb_printf("macOS Tahoe"); break;
|
||||
case 15: gb_printf("macOS Sequoia"); break;
|
||||
case 14: gb_printf("macOS Sonoma"); break;
|
||||
case 13: gb_printf("macOS Ventura"); break;
|
||||
|
||||
@@ -385,6 +385,13 @@ enum LinkerChoice : i32 {
|
||||
Linker_COUNT,
|
||||
};
|
||||
|
||||
enum SourceCodeLocationInfo : u8 {
|
||||
SourceCodeLocationInfo_Normal = 0,
|
||||
SourceCodeLocationInfo_Obfuscated = 1,
|
||||
SourceCodeLocationInfo_Filename = 2,
|
||||
SourceCodeLocationInfo_None = 3,
|
||||
};
|
||||
|
||||
String linker_choices[Linker_COUNT] = {
|
||||
str_lit("default"),
|
||||
str_lit("lld"),
|
||||
@@ -512,7 +519,7 @@ struct BuildContext {
|
||||
|
||||
bool dynamic_map_calls;
|
||||
|
||||
bool obfuscate_source_code_locations;
|
||||
SourceCodeLocationInfo source_code_location_info;
|
||||
|
||||
bool min_link_libs;
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ gb_global BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_bool
|
||||
is_type_enum,
|
||||
is_type_proc,
|
||||
is_type_bit_set,
|
||||
is_type_bit_field,
|
||||
is_type_simd_vector,
|
||||
is_type_matrix,
|
||||
|
||||
@@ -147,6 +148,11 @@ gb_internal bool does_require_msgSend_stret(Type *return_type) {
|
||||
if (return_type == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (build_context.metrics.os != TargetOs_darwin) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (build_context.metrics.arch == TargetArch_i386 || build_context.metrics.arch == TargetArch_amd64) {
|
||||
i64 struct_limit = type_size_of(t_uintptr) << 1;
|
||||
return type_size_of(return_type) > struct_limit;
|
||||
@@ -5593,7 +5599,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
}
|
||||
|
||||
if (sz >= 64) {
|
||||
if (is_type_unsigned(x.type)) {
|
||||
if (is_type_unsigned(x.type) || is_type_unsigned(y.type)) {
|
||||
add_package_dependency(c, "runtime", "umodti3", true);
|
||||
add_package_dependency(c, "runtime", "udivti3", true);
|
||||
} else {
|
||||
@@ -6082,6 +6088,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
case BuiltinProc_type_is_enum:
|
||||
case BuiltinProc_type_is_proc:
|
||||
case BuiltinProc_type_is_bit_set:
|
||||
case BuiltinProc_type_is_bit_field:
|
||||
case BuiltinProc_type_is_simd_vector:
|
||||
case BuiltinProc_type_is_matrix:
|
||||
case BuiltinProc_type_is_specialized_polymorphic_record:
|
||||
|
||||
@@ -1334,12 +1334,16 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
||||
has_instrumentation = false;
|
||||
e->flags |= EntityFlag_Require;
|
||||
} else if (ac.instrumentation_enter) {
|
||||
init_core_source_code_location(ctx->checker);
|
||||
if (!is_valid_instrumentation_call(e->type)) {
|
||||
init_core_source_code_location(ctx->checker);
|
||||
gbString s = type_to_string(e->type);
|
||||
error(e->token, "@(instrumentation_enter) procedures must have the type '%s', got %s", instrumentation_proc_type_str, s);
|
||||
gb_string_free(s);
|
||||
}
|
||||
if ((e->scope->flags & (ScopeFlag_File|ScopeFlag_Pkg)) == 0) {
|
||||
error(e->token, "@(instrumentation_enter) procedures must be declared at the file scope");
|
||||
}
|
||||
MUTEX_GUARD(&ctx->info->instrumentation_mutex);
|
||||
if (ctx->info->instrumentation_enter_entity != nullptr) {
|
||||
error(e->token, "@(instrumentation_enter) has already been set");
|
||||
@@ -1356,6 +1360,9 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
||||
error(e->token, "@(instrumentation_exit) procedures must have the type '%s', got %s", instrumentation_proc_type_str, s);
|
||||
gb_string_free(s);
|
||||
}
|
||||
if ((e->scope->flags & (ScopeFlag_File|ScopeFlag_Pkg)) == 0) {
|
||||
error(e->token, "@(instrumentation_exit) procedures must be declared at the file scope");
|
||||
}
|
||||
MUTEX_GUARD(&ctx->info->instrumentation_mutex);
|
||||
if (ctx->info->instrumentation_exit_entity != nullptr) {
|
||||
error(e->token, "@(instrumentation_exit) has already been set");
|
||||
@@ -1370,6 +1377,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
||||
e->Procedure.has_instrumentation = has_instrumentation;
|
||||
|
||||
e->Procedure.no_sanitize_address = ac.no_sanitize_address;
|
||||
e->Procedure.no_sanitize_memory = ac.no_sanitize_memory;
|
||||
|
||||
e->deprecated_message = ac.deprecated_message;
|
||||
e->warning_message = ac.warning_message;
|
||||
|
||||
+371
-315
@@ -263,6 +263,9 @@ gb_internal void check_did_you_mean_scope(String const &name, Scope *scope, char
|
||||
|
||||
gb_internal Entity *entity_from_expr(Ast *expr) {
|
||||
expr = unparen_expr(expr);
|
||||
if (expr == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
switch (expr->kind) {
|
||||
case Ast_Ident:
|
||||
return expr->Ident.entity;
|
||||
@@ -2421,27 +2424,27 @@ gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o
|
||||
Type *s = src->Array.elem;
|
||||
Type *d = dst->Slice.elem;
|
||||
if (are_types_identical(s, d)) {
|
||||
error_line("\tSuggestion: the array expression may be sliced with %s[:]\n", a);
|
||||
error_line("\tSuggestion: The array expression may be sliced with %s[:]\n", a);
|
||||
}
|
||||
} else if (is_type_dynamic_array(src) && is_type_slice(dst)) {
|
||||
Type *s = src->DynamicArray.elem;
|
||||
Type *d = dst->Slice.elem;
|
||||
if (are_types_identical(s, d)) {
|
||||
error_line("\tSuggestion: the dynamic array expression may be sliced with %s[:]\n", a);
|
||||
error_line("\tSuggestion: The dynamic array expression may be sliced with %s[:]\n", a);
|
||||
}
|
||||
}else if (are_types_identical(src, dst) && !are_types_identical(o->type, type)) {
|
||||
error_line("\tSuggestion: the expression may be directly casted to type %s\n", b);
|
||||
error_line("\tSuggestion: The expression may be directly casted to type %s\n", b);
|
||||
} else if (are_types_identical(src, t_string) && is_type_u8_slice(dst)) {
|
||||
error_line("\tSuggestion: a string may be transmuted to %s\n", b);
|
||||
error_line("\t This is an UNSAFE operation as string data is assumed to be immutable, \n");
|
||||
error_line("\tSuggestion: A string may be transmuted to %s\n", b);
|
||||
error_line("\t This is an UNSAFE operation as string data is assumed to be immutable,\n");
|
||||
error_line("\t whereas slices in general are assumed to be mutable.\n");
|
||||
} else if (is_type_u8_slice(src) && are_types_identical(dst, t_string) && o->mode != Addressing_Constant) {
|
||||
error_line("\tSuggestion: the expression may be casted to %s\n", b);
|
||||
error_line("\tSuggestion: The expression may be casted to %s\n", b);
|
||||
} else if (check_integer_exceed_suggestion(c, o, type, max_bit_size)) {
|
||||
return;
|
||||
} else if (is_expr_inferred_fixed_array(c->type_hint_expr) && is_type_array_like(type) && is_type_array_like(o->type)) {
|
||||
gbString s = expr_to_string(c->type_hint_expr);
|
||||
error_line("\tSuggestion: make sure that `%s` is attached to the compound literal directly\n", s);
|
||||
error_line("\tSuggestion: Make sure that `%s` is attached to the compound literal directly\n", s);
|
||||
gb_string_free(s);
|
||||
} else if (is_type_pointer(type) &&
|
||||
o->mode == Addressing_Variable &&
|
||||
@@ -3083,126 +3086,106 @@ gb_internal void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *nod
|
||||
GB_ASSERT(node->kind == Ast_BinaryExpr);
|
||||
ast_node(be, BinaryExpr, node);
|
||||
|
||||
ExactValue x_val = {};
|
||||
if (x->mode == Addressing_Constant) {
|
||||
x_val = exact_value_to_integer(x->value);
|
||||
}
|
||||
|
||||
bool x_is_untyped = is_type_untyped(x->type);
|
||||
if (!(is_type_integer(x->type) || (x_is_untyped && x_val.kind == ExactValue_Integer))) {
|
||||
gbString err_str = expr_to_string(x->expr);
|
||||
error(node, "Shifted operand '%s' must be an integer", err_str);
|
||||
gb_string_free(err_str);
|
||||
x->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_type_unsigned(y->type)) {
|
||||
|
||||
} else if (is_type_untyped(y->type)) {
|
||||
bool y_is_untyped = is_type_untyped(y->type);
|
||||
if (y_is_untyped) {
|
||||
convert_to_typed(c, y, t_untyped_integer);
|
||||
if (y->mode == Addressing_Invalid) {
|
||||
x->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
gbString err_str = expr_to_string(y->expr);
|
||||
error(node, "Shift amount '%s' must be an unsigned integer", err_str);
|
||||
gb_string_free(err_str);
|
||||
} else if (!is_type_unsigned(y->type)) {
|
||||
gbString y_str = expr_to_string(y->expr);
|
||||
error(y->expr, "Shift amount '%s' must be an unsigned integer", y_str);
|
||||
gb_string_free(y_str);
|
||||
x->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
bool x_is_untyped = is_type_untyped(x->type);
|
||||
if (!(x_is_untyped || is_type_integer(x->type))) {
|
||||
gbString x_str = expr_to_string(x->expr);
|
||||
error(x->expr, "Shifted operand '%s' must be an integer", x_str);
|
||||
gb_string_free(x_str);
|
||||
x->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
if (y->mode == Addressing_Constant) {
|
||||
if (big_int_is_neg(&y->value.value_integer)) {
|
||||
gbString y_str = expr_to_string(y->expr);
|
||||
error(y->expr, "Shift amount '%s' cannot be negative", y_str);
|
||||
gb_string_free(y_str);
|
||||
x->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
BigInt max_shift = {};
|
||||
big_int_from_u64(&max_shift, MAX_BIG_INT_SHIFT);
|
||||
|
||||
if (big_int_cmp(&y->value.value_integer, &max_shift) > 0) {
|
||||
gbString y_str = expr_to_string(y->expr);
|
||||
error(y->expr, "Shift amount '%s' must be <= %u", y_str, MAX_BIG_INT_SHIFT);
|
||||
gb_string_free(y_str);
|
||||
x->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
if (x->mode == Addressing_Constant) {
|
||||
if (x_is_untyped) {
|
||||
convert_to_typed(c, x, t_untyped_integer);
|
||||
if (x->mode == Addressing_Invalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
x->expr = node;
|
||||
x->value = exact_value_shift(be->op.kind, exact_value_to_integer(x->value), exact_value_to_integer(y->value));
|
||||
|
||||
if (x->mode == Addressing_Constant) {
|
||||
if (y->mode == Addressing_Constant) {
|
||||
ExactValue y_val = exact_value_to_integer(y->value);
|
||||
if (y_val.kind != ExactValue_Integer) {
|
||||
gbString err_str = expr_to_string(y->expr);
|
||||
error(node, "Shift amount '%s' must be an unsigned integer", err_str);
|
||||
gb_string_free(err_str);
|
||||
x->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
BigInt max_shift = {};
|
||||
big_int_from_u64(&max_shift, MAX_BIG_INT_SHIFT);
|
||||
|
||||
if (big_int_cmp(&y_val.value_integer, &max_shift) > 0) {
|
||||
gbString err_str = expr_to_string(y->expr);
|
||||
error(node, "Shift amount too large: '%s'", err_str);
|
||||
gb_string_free(err_str);
|
||||
x->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_type_integer(x->type)) {
|
||||
// NOTE(bill): It could be an untyped float but still representable
|
||||
// as an integer
|
||||
x->type = t_untyped_integer;
|
||||
}
|
||||
|
||||
x->expr = node;
|
||||
x->value = exact_value_shift(be->op.kind, x_val, y_val);
|
||||
x->value = exact_value_shift(be->op.kind, x->value, y->value);
|
||||
|
||||
check_is_expressible(c, x, x->type);
|
||||
|
||||
if (is_type_typed(x->type)) {
|
||||
check_is_expressible(c, x, x->type);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
TokenPos pos = ast_token(x->expr).pos;
|
||||
if (x_is_untyped) {
|
||||
if (x->expr != nullptr) {
|
||||
x->expr->tav.is_lhs = true;
|
||||
}
|
||||
x->mode = Addressing_Value;
|
||||
if (type_hint) {
|
||||
if (is_type_integer(type_hint)) {
|
||||
convert_to_typed(c, x, type_hint);
|
||||
} else {
|
||||
gbString x_str = expr_to_string(x->expr);
|
||||
gbString to_type = type_to_string(type_hint);
|
||||
error(node, "Conversion of shifted operand '%s' to '%s' is not allowed", x_str, to_type);
|
||||
gb_string_free(x_str);
|
||||
gb_string_free(to_type);
|
||||
x->mode = Addressing_Invalid;
|
||||
}
|
||||
} else if (!is_type_integer(x->type)) {
|
||||
gbString x_str = expr_to_string(x->expr);
|
||||
error(node, "Non-integer shifted operand '%s' is not allowed", x_str);
|
||||
gb_string_free(x_str);
|
||||
x->mode = Addressing_Invalid;
|
||||
}
|
||||
// x->value = x_val;
|
||||
return;
|
||||
if (y_is_untyped) {
|
||||
convert_to_typed(c, y, t_uint);
|
||||
}
|
||||
}
|
||||
|
||||
if (y->mode == Addressing_Constant && big_int_is_neg(&y->value.value_integer)) {
|
||||
gbString err_str = expr_to_string(y->expr);
|
||||
error(node, "Shift amount cannot be negative: '%s'", err_str);
|
||||
gb_string_free(err_str);
|
||||
}
|
||||
|
||||
if (!is_type_integer(x->type)) {
|
||||
gbString err_str = expr_to_string(x->expr);
|
||||
error(node, "Shift operand '%s' must be an integer", err_str);
|
||||
gb_string_free(err_str);
|
||||
x->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_type_untyped(y->type)) {
|
||||
convert_to_typed(c, y, t_uint);
|
||||
if (x->mode == Addressing_Constant) {
|
||||
if (x_is_untyped) {
|
||||
if (type_hint) {
|
||||
if (is_type_integer(type_hint)) {
|
||||
convert_to_typed(c, x, type_hint);
|
||||
} else if (is_type_any(type_hint)) {
|
||||
convert_to_typed(c, x, default_type(t_untyped_integer));
|
||||
} else {
|
||||
gbString x_str = expr_to_string(x->expr);
|
||||
gbString type_str = type_to_string(type_hint);
|
||||
error(x->expr, "Shifted operand '%s' cannot convert to non-integer type '%s'", x_str, type_str);
|
||||
gb_string_free(x_str);
|
||||
gb_string_free(type_str);
|
||||
x->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
check_is_expressible(c, x, default_type(t_untyped_integer));
|
||||
}
|
||||
if (x->mode == Addressing_Invalid) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
x->mode = Addressing_Value;
|
||||
}
|
||||
|
||||
x->mode = Addressing_Value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) {
|
||||
if (check_is_assignable_to(c, operand, y)) {
|
||||
return true;
|
||||
@@ -3884,6 +3867,59 @@ matrix_error:
|
||||
|
||||
}
|
||||
|
||||
gb_internal void check_binary_expr_dependency(CheckerContext *c, Token op, Type *bt, bool REQUIRE) {
|
||||
if (op.kind == Token_Mod || op.kind == Token_ModEq ||
|
||||
op.kind == Token_ModMod || op.kind == Token_ModModEq) {
|
||||
if (bt->kind == Type_Basic) switch (bt->Basic.kind) {
|
||||
case Basic_u128: add_package_dependency(c, "runtime", "umodti3", REQUIRE); break;
|
||||
case Basic_i128: add_package_dependency(c, "runtime", "modti3", REQUIRE); break;
|
||||
}
|
||||
} else if (op.kind == Token_Quo || op.kind == Token_QuoEq) {
|
||||
if (bt->kind == Type_Basic) switch (bt->Basic.kind) {
|
||||
case Basic_complex32: add_package_dependency(c, "runtime", "quo_complex32"); break;
|
||||
case Basic_complex64: add_package_dependency(c, "runtime", "quo_complex64"); break;
|
||||
case Basic_complex128: add_package_dependency(c, "runtime", "quo_complex128"); break;
|
||||
case Basic_quaternion64: add_package_dependency(c, "runtime", "quo_quaternion64"); break;
|
||||
case Basic_quaternion128: add_package_dependency(c, "runtime", "quo_quaternion128"); break;
|
||||
case Basic_quaternion256: add_package_dependency(c, "runtime", "quo_quaternion256"); break;
|
||||
|
||||
case Basic_u128: add_package_dependency(c, "runtime", "udivti3", REQUIRE); break;
|
||||
case Basic_i128: add_package_dependency(c, "runtime", "divti3", REQUIRE); break;
|
||||
}
|
||||
} else if (op.kind == Token_Mul || op.kind == Token_MulEq) {
|
||||
if (bt->kind == Type_Basic) switch (bt->Basic.kind) {
|
||||
case Basic_quaternion64: add_package_dependency(c, "runtime", "mul_quaternion64"); break;
|
||||
case Basic_quaternion128: add_package_dependency(c, "runtime", "mul_quaternion128"); break;
|
||||
case Basic_quaternion256: add_package_dependency(c, "runtime", "mul_quaternion256"); break;
|
||||
|
||||
|
||||
case Basic_u128:
|
||||
case Basic_i128:
|
||||
if (is_arch_wasm()) {
|
||||
add_package_dependency(c, "runtime", "__multi3", REQUIRE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (op.kind == Token_Shl || op.kind == Token_ShlEq) {
|
||||
if (bt->kind == Type_Basic) switch (bt->Basic.kind) {
|
||||
case Basic_u128:
|
||||
case Basic_i128:
|
||||
if (is_arch_wasm()) {
|
||||
add_package_dependency(c, "runtime", "__ashlti3", REQUIRE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (op.kind == Token_Shr || op.kind == Token_ShrEq) {
|
||||
if (bt->kind == Type_Basic) switch (bt->Basic.kind) {
|
||||
case Basic_u128:
|
||||
case Basic_i128:
|
||||
if (is_arch_wasm()) {
|
||||
add_package_dependency(c, "runtime", "__lshrti3", REQUIRE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Type *type_hint, bool use_lhs_as_type_hint=false) {
|
||||
GB_ASSERT(node->kind == Ast_BinaryExpr);
|
||||
@@ -4081,58 +4117,10 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ
|
||||
}
|
||||
|
||||
bool REQUIRE = true;
|
||||
Type *bt = base_type(x->type);
|
||||
if (op.kind == Token_Mod || op.kind == Token_ModEq ||
|
||||
op.kind == Token_ModMod || op.kind == Token_ModModEq) {
|
||||
if (bt->kind == Type_Basic) switch (bt->Basic.kind) {
|
||||
case Basic_u128: add_package_dependency(c, "runtime", "umodti3", REQUIRE); break;
|
||||
case Basic_i128: add_package_dependency(c, "runtime", "modti3", REQUIRE); break;
|
||||
}
|
||||
} else if (op.kind == Token_Quo || op.kind == Token_QuoEq) {
|
||||
if (bt->kind == Type_Basic) switch (bt->Basic.kind) {
|
||||
case Basic_complex32: add_package_dependency(c, "runtime", "quo_complex32"); break;
|
||||
case Basic_complex64: add_package_dependency(c, "runtime", "quo_complex64"); break;
|
||||
case Basic_complex128: add_package_dependency(c, "runtime", "quo_complex128"); break;
|
||||
case Basic_quaternion64: add_package_dependency(c, "runtime", "quo_quaternion64"); break;
|
||||
case Basic_quaternion128: add_package_dependency(c, "runtime", "quo_quaternion128"); break;
|
||||
case Basic_quaternion256: add_package_dependency(c, "runtime", "quo_quaternion256"); break;
|
||||
|
||||
case Basic_u128: add_package_dependency(c, "runtime", "udivti3", REQUIRE); break;
|
||||
case Basic_i128: add_package_dependency(c, "runtime", "divti3", REQUIRE); break;
|
||||
}
|
||||
} else if (op.kind == Token_Mul || op.kind == Token_MulEq) {
|
||||
if (bt->kind == Type_Basic) switch (bt->Basic.kind) {
|
||||
case Basic_quaternion64: add_package_dependency(c, "runtime", "mul_quaternion64"); break;
|
||||
case Basic_quaternion128: add_package_dependency(c, "runtime", "mul_quaternion128"); break;
|
||||
case Basic_quaternion256: add_package_dependency(c, "runtime", "mul_quaternion256"); break;
|
||||
|
||||
|
||||
case Basic_u128:
|
||||
case Basic_i128:
|
||||
if (is_arch_wasm()) {
|
||||
add_package_dependency(c, "runtime", "__multi3", REQUIRE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (op.kind == Token_Shl || op.kind == Token_ShlEq) {
|
||||
if (bt->kind == Type_Basic) switch (bt->Basic.kind) {
|
||||
case Basic_u128:
|
||||
case Basic_i128:
|
||||
if (is_arch_wasm()) {
|
||||
add_package_dependency(c, "runtime", "__ashlti3", REQUIRE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (op.kind == Token_Shr || op.kind == Token_ShrEq) {
|
||||
if (bt->kind == Type_Basic) switch (bt->Basic.kind) {
|
||||
case Basic_u128:
|
||||
case Basic_i128:
|
||||
if (is_arch_wasm()) {
|
||||
add_package_dependency(c, "runtime", "__lshrti3", REQUIRE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
Type *btx = base_type(x->type);
|
||||
Type *bty = base_type(y->type);
|
||||
check_binary_expr_dependency(c, op, btx, REQUIRE);
|
||||
check_binary_expr_dependency(c, op, bty, REQUIRE);
|
||||
|
||||
if (token_is_shift(op.kind)) {
|
||||
check_shift(c, x, y, node, type_hint);
|
||||
@@ -5373,16 +5361,6 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
check_entity_decl(c, entity, nullptr, nullptr);
|
||||
if (entity->kind == Entity_ProcGroup) {
|
||||
operand->mode = Addressing_ProcGroup;
|
||||
operand->proc_group = entity;
|
||||
|
||||
add_type_and_value(c, operand->expr, operand->mode, operand->type, operand->value);
|
||||
return entity;
|
||||
}
|
||||
GB_ASSERT_MSG(entity->type != nullptr, "%.*s (%.*s)", LIT(entity->token.string), LIT(entity_strings[entity->kind]));
|
||||
|
||||
if (!is_entity_exported(entity, allow_builtin)) {
|
||||
gbString sel_str = expr_to_string(selector);
|
||||
error(node, "'%s' is not exported by '%.*s'", sel_str, LIT(import_name));
|
||||
@@ -5393,36 +5371,15 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
|
||||
// return nullptr;
|
||||
}
|
||||
|
||||
check_entity_decl(c, entity, nullptr, nullptr);
|
||||
if (entity->kind == Entity_ProcGroup) {
|
||||
Array<Entity *> procs = entity->ProcGroup.entities;
|
||||
bool skip = false;
|
||||
for (Entity *p : procs) {
|
||||
Type *t = base_type(p->type);
|
||||
if (t == t_invalid) {
|
||||
continue;
|
||||
}
|
||||
operand->mode = Addressing_ProcGroup;
|
||||
operand->proc_group = entity;
|
||||
|
||||
Operand x = {};
|
||||
x.mode = Addressing_Value;
|
||||
x.type = t;
|
||||
if (type_hint != nullptr) {
|
||||
if (check_is_assignable_to(c, &x, type_hint)) {
|
||||
entity = p;
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!skip) {
|
||||
GB_ASSERT(entity != nullptr);
|
||||
operand->mode = Addressing_ProcGroup;
|
||||
operand->type = t_invalid;
|
||||
operand->expr = node;
|
||||
operand->proc_group = entity;
|
||||
return entity;
|
||||
}
|
||||
add_type_and_value(c, operand->expr, operand->mode, operand->type, operand->value);
|
||||
return entity;
|
||||
}
|
||||
GB_ASSERT_MSG(entity->type != nullptr, "%.*s (%.*s)", LIT(entity->token.string), LIT(entity_strings[entity->kind]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5907,12 +5864,12 @@ typedef u32 UnpackFlags;
|
||||
enum UnpackFlag : u32 {
|
||||
UnpackFlag_None = 0,
|
||||
UnpackFlag_AllowOk = 1<<0,
|
||||
UnpackFlag_IsVariadic = 1<<1,
|
||||
UnpackFlag_AllowUndef = 1<<2,
|
||||
UnpackFlag_AllowUndef = 1<<1,
|
||||
};
|
||||
|
||||
|
||||
gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array<Operand> *operands, Slice<Ast *> const &rhs_arguments, UnpackFlags flags) {
|
||||
gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array<Operand> *operands, Slice<Ast *> const &rhs_arguments, UnpackFlags flags,
|
||||
isize variadic_index = -1) {
|
||||
auto const &add_dependencies_from_unpacking = [](CheckerContext *c, Entity **lhs, isize lhs_count, isize tuple_index, isize tuple_count) -> isize {
|
||||
if (lhs == nullptr || c->decl == nullptr) {
|
||||
return tuple_count;
|
||||
@@ -5937,11 +5894,14 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize
|
||||
return tuple_count;
|
||||
};
|
||||
|
||||
|
||||
bool allow_ok = (flags & UnpackFlag_AllowOk) != 0;
|
||||
bool is_variadic = (flags & UnpackFlag_IsVariadic) != 0;
|
||||
bool allow_undef = (flags & UnpackFlag_AllowUndef) != 0;
|
||||
|
||||
bool is_variadic = variadic_index > -1;
|
||||
if (!is_variadic) {
|
||||
variadic_index = lhs_count;
|
||||
}
|
||||
|
||||
bool optional_ok = false;
|
||||
isize tuple_index = 0;
|
||||
for (Ast *rhs : rhs_arguments) {
|
||||
@@ -5957,26 +5917,18 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize
|
||||
|
||||
Type *type_hint = nullptr;
|
||||
|
||||
|
||||
if (lhs != nullptr && tuple_index < lhs_count) {
|
||||
// NOTE(bill): override DeclInfo for dependency
|
||||
Entity *e = lhs[tuple_index];
|
||||
if (e != nullptr) {
|
||||
type_hint = e->type;
|
||||
if (e->flags & EntityFlag_Ellipsis) {
|
||||
GB_ASSERT(is_type_slice(e->type));
|
||||
GB_ASSERT(e->type->kind == Type_Slice);
|
||||
type_hint = e->type->Slice.elem;
|
||||
if (lhs != nullptr) {
|
||||
if (tuple_index < variadic_index) {
|
||||
// NOTE(bill): override DeclInfo for dependency
|
||||
Entity *e = lhs[tuple_index];
|
||||
if (e != nullptr) {
|
||||
type_hint = e->type;
|
||||
}
|
||||
}
|
||||
} else if (lhs != nullptr && tuple_index >= lhs_count && is_variadic) {
|
||||
// NOTE(bill): override DeclInfo for dependency
|
||||
Entity *e = lhs[lhs_count-1];
|
||||
if (e != nullptr) {
|
||||
type_hint = e->type;
|
||||
if (e->flags & EntityFlag_Ellipsis) {
|
||||
} else if (is_variadic) {
|
||||
Entity *e = lhs[variadic_index];
|
||||
if (e != nullptr) {
|
||||
GB_ASSERT(e->flags & EntityFlag_Ellipsis);
|
||||
GB_ASSERT(is_type_slice(e->type));
|
||||
GB_ASSERT(e->type->kind == Type_Slice);
|
||||
type_hint = e->type->Slice.elem;
|
||||
}
|
||||
}
|
||||
@@ -6516,17 +6468,16 @@ gb_internal bool is_call_expr_field_value(AstCallExpr *ce) {
|
||||
return ce->args[0]->kind == Ast_FieldValue;
|
||||
}
|
||||
|
||||
gb_internal Entity **populate_proc_parameter_list(CheckerContext *c, Type *proc_type, isize *lhs_count_, bool *is_variadic) {
|
||||
gb_internal Entity **populate_proc_parameter_list(CheckerContext *c, Type *proc_type, isize *lhs_count_) {
|
||||
Entity **lhs = nullptr;
|
||||
isize lhs_count = -1;
|
||||
|
||||
if (proc_type == nullptr) {
|
||||
if (proc_type == nullptr || proc_type == t_invalid) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GB_ASSERT(is_type_proc(proc_type));
|
||||
TypeProc *pt = &base_type(proc_type)->Proc;
|
||||
*is_variadic = pt->variadic;
|
||||
|
||||
if (!pt->is_polymorphic || pt->is_poly_specialized) {
|
||||
if (pt->params != nullptr) {
|
||||
@@ -6720,6 +6671,9 @@ gb_internal bool check_call_arguments_single(CheckerContext *c, Ast *call, Opera
|
||||
|
||||
GB_ASSERT(proc_type != nullptr);
|
||||
proc_type = base_type(proc_type);
|
||||
if (proc_type == t_invalid) {
|
||||
return false;
|
||||
}
|
||||
GB_ASSERT(proc_type->kind == Type_Proc);
|
||||
|
||||
CallArgumentError err = check_call_arguments_internal(c, call, e, proc_type, positional_operands, named_operands, show_error_mode, data);
|
||||
@@ -6853,7 +6807,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
|
||||
|
||||
Entity **lhs = nullptr;
|
||||
isize lhs_count = -1;
|
||||
bool is_variadic = false;
|
||||
i32 variadic_index = -1;
|
||||
|
||||
auto positional_operands = array_make<Operand>(heap_allocator(), 0, 0);
|
||||
auto named_operands = array_make<Operand>(heap_allocator(), 0, 0);
|
||||
@@ -6862,9 +6816,14 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
|
||||
|
||||
if (procs.count == 1) {
|
||||
Entity *e = procs[0];
|
||||
|
||||
lhs = populate_proc_parameter_list(c, e->type, &lhs_count, &is_variadic);
|
||||
check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None);
|
||||
Type *pt = base_type(e->type);
|
||||
if (pt != nullptr && is_type_proc(pt)) {
|
||||
lhs = populate_proc_parameter_list(c, pt, &lhs_count);
|
||||
if (pt->Proc.variadic) {
|
||||
variadic_index = pt->Proc.variadic_index;
|
||||
}
|
||||
}
|
||||
check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, UnpackFlag_None, variadic_index);
|
||||
|
||||
if (check_named_arguments(c, e->type, named_args, &named_operands, true)) {
|
||||
check_call_arguments_single(c, call, operand,
|
||||
@@ -6924,11 +6883,30 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
|
||||
}
|
||||
lhs[param_index] = e;
|
||||
}
|
||||
|
||||
for (Entity *p : procs) {
|
||||
Type *pt = base_type(p->type);
|
||||
if (!(pt != nullptr && is_type_proc(pt))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pt->Proc.is_polymorphic) {
|
||||
if (variadic_index == -1) {
|
||||
variadic_index = pt->Proc.variadic_index;
|
||||
} else if (variadic_index != pt->Proc.variadic_index) {
|
||||
variadic_index = -1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
variadic_index = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None);
|
||||
check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, UnpackFlag_None, variadic_index);
|
||||
|
||||
for_array(i, named_args) {
|
||||
Ast *arg = named_args[i];
|
||||
@@ -7366,13 +7344,16 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op
|
||||
defer (array_free(&named_operands));
|
||||
|
||||
if (positional_args.count > 0) {
|
||||
isize lhs_count = -1;
|
||||
bool is_variadic = false;
|
||||
Entity **lhs = nullptr;
|
||||
isize lhs_count = -1;
|
||||
i32 variadic_index = -1;
|
||||
if (pt != nullptr) {
|
||||
lhs = populate_proc_parameter_list(c, proc_type, &lhs_count, &is_variadic);
|
||||
lhs = populate_proc_parameter_list(c, proc_type, &lhs_count);
|
||||
if (pt->variadic) {
|
||||
variadic_index = pt->variadic_index;
|
||||
}
|
||||
}
|
||||
check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None);
|
||||
check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, UnpackFlag_None, variadic_index);
|
||||
}
|
||||
|
||||
if (named_args.count > 0) {
|
||||
@@ -8779,23 +8760,52 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A
|
||||
String name = bd->name.string;
|
||||
if (name == "file") {
|
||||
String file = get_file_path_string(bd->token.pos.file_id);
|
||||
if (build_context.obfuscate_source_code_locations) {
|
||||
switch (build_context.source_code_location_info) {
|
||||
case SourceCodeLocationInfo_Normal:
|
||||
break;
|
||||
case SourceCodeLocationInfo_Obfuscated:
|
||||
file = obfuscate_string(file, "F");
|
||||
break;
|
||||
case SourceCodeLocationInfo_Filename:
|
||||
file = last_path_element(file);
|
||||
break;
|
||||
case SourceCodeLocationInfo_None:
|
||||
file = str_lit("");
|
||||
break;
|
||||
}
|
||||
o->type = t_untyped_string;
|
||||
o->value = exact_value_string(file);
|
||||
} else if (name == "directory") {
|
||||
String file = get_file_path_string(bd->token.pos.file_id);
|
||||
String path = dir_from_path(file);
|
||||
if (build_context.obfuscate_source_code_locations) {
|
||||
switch (build_context.source_code_location_info) {
|
||||
case SourceCodeLocationInfo_Normal:
|
||||
break;
|
||||
case SourceCodeLocationInfo_Obfuscated:
|
||||
path = obfuscate_string(path, "D");
|
||||
break;
|
||||
case SourceCodeLocationInfo_Filename:
|
||||
path = last_path_element(path);
|
||||
break;
|
||||
case SourceCodeLocationInfo_None:
|
||||
path = str_lit("");
|
||||
break;
|
||||
}
|
||||
o->type = t_untyped_string;
|
||||
o->value = exact_value_string(path);
|
||||
} else if (name == "line") {
|
||||
i32 line = bd->token.pos.line;
|
||||
if (build_context.obfuscate_source_code_locations) {
|
||||
switch (build_context.source_code_location_info) {
|
||||
case SourceCodeLocationInfo_Normal:
|
||||
break;
|
||||
case SourceCodeLocationInfo_Obfuscated:
|
||||
line = obfuscate_i32(line);
|
||||
break;
|
||||
case SourceCodeLocationInfo_Filename:
|
||||
break;
|
||||
case SourceCodeLocationInfo_None:
|
||||
line = 0;
|
||||
break;
|
||||
}
|
||||
o->type = t_untyped_integer;
|
||||
o->value = exact_value_i64(line);
|
||||
@@ -8806,8 +8816,17 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A
|
||||
o->value = exact_value_string(str_lit(""));
|
||||
} else {
|
||||
String p = c->proc_name;
|
||||
if (build_context.obfuscate_source_code_locations) {
|
||||
switch (build_context.source_code_location_info) {
|
||||
case SourceCodeLocationInfo_Normal:
|
||||
break;
|
||||
case SourceCodeLocationInfo_Obfuscated:
|
||||
p = obfuscate_string(p, "P");
|
||||
break;
|
||||
case SourceCodeLocationInfo_Filename:
|
||||
break;
|
||||
case SourceCodeLocationInfo_None:
|
||||
p = str_lit("");
|
||||
break;
|
||||
}
|
||||
o->type = t_untyped_string;
|
||||
o->value = exact_value_string(p);
|
||||
@@ -9487,6 +9506,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
||||
}
|
||||
bool is_to_be_determined_array_count = false;
|
||||
bool is_constant = true;
|
||||
bool is_soa = false;
|
||||
|
||||
Ast *type_expr = cl->type;
|
||||
|
||||
@@ -9519,8 +9539,14 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
||||
GB_ASSERT(tag->kind == Ast_BasicDirective);
|
||||
String name = tag->BasicDirective.name.string;
|
||||
if (name == "soa") {
|
||||
error(node, "#soa arrays are not supported for compound literals");
|
||||
return kind;
|
||||
is_soa = true;
|
||||
if (count == nullptr) {
|
||||
error(node, "#soa slices are not supported for compound literals");
|
||||
return kind;
|
||||
} else if (count->kind == Ast_UnaryExpr &&
|
||||
count->UnaryExpr.op.kind == Token_Question) {
|
||||
error(node, "#soa fixed length arrays must specify their length and cannot use ?");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9530,7 +9556,8 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
||||
GB_ASSERT(tag->kind == Ast_BasicDirective);
|
||||
String name = tag->BasicDirective.name.string;
|
||||
if (name == "soa") {
|
||||
error(node, "#soa arrays are not supported for compound literals");
|
||||
is_soa = true;
|
||||
error(node, "#soa dynamic arrays are not supported for compound literals");
|
||||
return kind;
|
||||
}
|
||||
}
|
||||
@@ -9559,101 +9586,101 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
||||
|
||||
|
||||
switch (t->kind) {
|
||||
case Type_Struct: {
|
||||
case Type_Struct:
|
||||
if (cl->elems.count == 0) {
|
||||
break; // NOTE(bill): No need to init
|
||||
}
|
||||
|
||||
if (t->Struct.soa_kind != StructSoa_None) {
|
||||
error(node, "#soa arrays are not supported for compound literals");
|
||||
break;
|
||||
}
|
||||
if (t->Struct.soa_kind == StructSoa_None) {
|
||||
if (t->Struct.is_raw_union) {
|
||||
if (cl->elems.count > 0) {
|
||||
// NOTE: unions cannot be constant
|
||||
is_constant = false;
|
||||
|
||||
if (t->Struct.is_raw_union) {
|
||||
if (cl->elems.count > 0) {
|
||||
// NOTE: unions cannot be constant
|
||||
is_constant = false;
|
||||
|
||||
if (cl->elems[0]->kind != Ast_FieldValue) {
|
||||
gbString type_str = type_to_string(type);
|
||||
error(node, "%s ('struct #raw_union') compound literals are only allowed to contain 'field = value' elements", type_str);
|
||||
gb_string_free(type_str);
|
||||
} else {
|
||||
if (cl->elems.count != 1) {
|
||||
if (cl->elems[0]->kind != Ast_FieldValue) {
|
||||
gbString type_str = type_to_string(type);
|
||||
error(node, "%s ('struct #raw_union') compound literals are only allowed to contain up to 1 'field = value' element, got %td", type_str, cl->elems.count);
|
||||
error(node, "%s ('struct #raw_union') compound literals are only allowed to contain 'field = value' elements", type_str);
|
||||
gb_string_free(type_str);
|
||||
} else {
|
||||
check_compound_literal_field_values(c, cl->elems, o, type, is_constant);
|
||||
if (cl->elems.count != 1) {
|
||||
gbString type_str = type_to_string(type);
|
||||
error(node, "%s ('struct #raw_union') compound literals are only allowed to contain up to 1 'field = value' element, got %td", type_str, cl->elems.count);
|
||||
gb_string_free(type_str);
|
||||
} else {
|
||||
check_compound_literal_field_values(c, cl->elems, o, type, is_constant);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
wait_signal_until_available(&t->Struct.fields_wait_signal);
|
||||
isize field_count = t->Struct.fields.count;
|
||||
isize min_field_count = t->Struct.fields.count;
|
||||
for (isize i = min_field_count-1; i >= 0; i--) {
|
||||
Entity *e = t->Struct.fields[i];
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
if (e->Variable.param_value.kind != ParameterValue_Invalid) {
|
||||
min_field_count--;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cl->elems[0]->kind == Ast_FieldValue) {
|
||||
check_compound_literal_field_values(c, cl->elems, o, type, is_constant);
|
||||
} else {
|
||||
bool seen_field_value = false;
|
||||
|
||||
for_array(index, cl->elems) {
|
||||
Entity *field = nullptr;
|
||||
Ast *elem = cl->elems[index];
|
||||
if (elem->kind == Ast_FieldValue) {
|
||||
seen_field_value = true;
|
||||
error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed");
|
||||
continue;
|
||||
} else if (seen_field_value) {
|
||||
error(elem, "Value elements cannot be used after a 'field = value'");
|
||||
continue;
|
||||
}
|
||||
if (index >= field_count) {
|
||||
error(elem, "Too many values in structure literal, expected %td, got %td", field_count, cl->elems.count);
|
||||
break;
|
||||
}
|
||||
|
||||
if (field == nullptr) {
|
||||
field = t->Struct.fields[index];
|
||||
}
|
||||
|
||||
Operand o = {};
|
||||
check_expr_or_type(c, &o, elem, field->type);
|
||||
|
||||
if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) {
|
||||
is_constant = false;
|
||||
}
|
||||
if (is_constant) {
|
||||
is_constant = check_is_operand_compound_lit_constant(c, &o);
|
||||
}
|
||||
|
||||
check_assignment(c, &o, field->type, str_lit("structure literal"));
|
||||
}
|
||||
if (cl->elems.count < field_count) {
|
||||
if (min_field_count < field_count) {
|
||||
if (cl->elems.count < min_field_count) {
|
||||
error(cl->close, "Too few values in structure literal, expected at least %td, got %td", min_field_count, cl->elems.count);
|
||||
}
|
||||
} else {
|
||||
error(cl->close, "Too few values in structure literal, expected %td, got %td", field_count, cl->elems.count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
} else if (t->Struct.soa_kind != StructSoa_Fixed) {
|
||||
error(node, "#soa slices and dynamic arrays are not supported for compound literals");
|
||||
break;
|
||||
}
|
||||
|
||||
wait_signal_until_available(&t->Struct.fields_wait_signal);
|
||||
isize field_count = t->Struct.fields.count;
|
||||
isize min_field_count = t->Struct.fields.count;
|
||||
for (isize i = min_field_count-1; i >= 0; i--) {
|
||||
Entity *e = t->Struct.fields[i];
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
if (e->Variable.param_value.kind != ParameterValue_Invalid) {
|
||||
min_field_count--;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cl->elems[0]->kind == Ast_FieldValue) {
|
||||
check_compound_literal_field_values(c, cl->elems, o, type, is_constant);
|
||||
} else {
|
||||
bool seen_field_value = false;
|
||||
|
||||
for_array(index, cl->elems) {
|
||||
Entity *field = nullptr;
|
||||
Ast *elem = cl->elems[index];
|
||||
if (elem->kind == Ast_FieldValue) {
|
||||
seen_field_value = true;
|
||||
error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed");
|
||||
continue;
|
||||
} else if (seen_field_value) {
|
||||
error(elem, "Value elements cannot be used after a 'field = value'");
|
||||
continue;
|
||||
}
|
||||
if (index >= field_count) {
|
||||
error(elem, "Too many values in structure literal, expected %td, got %td", field_count, cl->elems.count);
|
||||
break;
|
||||
}
|
||||
|
||||
if (field == nullptr) {
|
||||
field = t->Struct.fields[index];
|
||||
}
|
||||
|
||||
Operand o = {};
|
||||
check_expr_or_type(c, &o, elem, field->type);
|
||||
|
||||
if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) {
|
||||
is_constant = false;
|
||||
}
|
||||
if (is_constant) {
|
||||
is_constant = check_is_operand_compound_lit_constant(c, &o);
|
||||
}
|
||||
|
||||
check_assignment(c, &o, field->type, str_lit("structure literal"));
|
||||
}
|
||||
if (cl->elems.count < field_count) {
|
||||
if (min_field_count < field_count) {
|
||||
if (cl->elems.count < min_field_count) {
|
||||
error(cl->close, "Too few values in structure literal, expected at least %td, got %td", min_field_count, cl->elems.count);
|
||||
}
|
||||
} else {
|
||||
error(cl->close, "Too few values in structure literal, expected %td, got %td", field_count, cl->elems.count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
/*fallthrough*/
|
||||
|
||||
case Type_Slice:
|
||||
case Type_Array:
|
||||
@@ -9664,7 +9691,14 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
||||
Type *elem_type = nullptr;
|
||||
String context_name = {};
|
||||
i64 max_type_count = -1;
|
||||
if (t->kind == Type_Slice) {
|
||||
if (t->kind == Type_Struct) {
|
||||
GB_ASSERT(t->Struct.soa_kind == StructSoa_Fixed);
|
||||
elem_type = t->Struct.soa_elem;
|
||||
context_name = str_lit("#soa array literal");
|
||||
if (!is_to_be_determined_array_count) {
|
||||
max_type_count = t->Struct.soa_count;
|
||||
}
|
||||
} else if (t->kind == Type_Slice) {
|
||||
elem_type = t->Slice.elem;
|
||||
context_name = str_lit("slice literal");
|
||||
} else if (t->kind == Type_Array) {
|
||||
@@ -9673,6 +9707,12 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
||||
if (!is_to_be_determined_array_count) {
|
||||
max_type_count = t->Array.count;
|
||||
}
|
||||
} else if (t->kind == Type_Array) {
|
||||
elem_type = t->Array.elem;
|
||||
context_name = str_lit("array literal");
|
||||
if (!is_to_be_determined_array_count) {
|
||||
max_type_count = t->Array.count;
|
||||
}
|
||||
} else if (t->kind == Type_DynamicArray) {
|
||||
elem_type = t->DynamicArray.elem;
|
||||
context_name = str_lit("dynamic array literal");
|
||||
@@ -9840,6 +9880,15 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
||||
error(node, "Expected %lld values for this array literal, got %lld", cast(long long)t->Array.count, cast(long long)max);
|
||||
}
|
||||
}
|
||||
} else if (t->kind == Type_Struct) {
|
||||
GB_ASSERT(t->Struct.soa_kind == StructSoa_Fixed);
|
||||
if (is_to_be_determined_array_count) {
|
||||
t->Struct.soa_count = cast(i32)max;
|
||||
} else if (cl->elems.count > 0 && cl->elems[0]->kind != Ast_FieldValue) {
|
||||
if (0 < max && max < t->Struct.soa_count) {
|
||||
error(node, "Expected %lld values for this #soa array literal, got %lld", cast(long long)t->Struct.soa_count, cast(long long)max);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11080,7 +11129,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
|
||||
case_ast_node(u, Uninit, node);
|
||||
o->mode = Addressing_Value;
|
||||
o->type = t_untyped_uninit;
|
||||
error(node, "Use of --- outside of variable declaration");
|
||||
error(node, "Global variables will always be zeroed if left unassigned, --- is disallowed");
|
||||
case_end;
|
||||
|
||||
|
||||
@@ -11312,6 +11361,13 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
|
||||
node->viral_state_flags |= de->expr->viral_state_flags;
|
||||
|
||||
if (o->mode == Addressing_Invalid) {
|
||||
o->mode = Addressing_Invalid;
|
||||
o->expr = node;
|
||||
return kind;
|
||||
} else if (o->mode == Addressing_Type) {
|
||||
gbString str = expr_to_string(o->expr);
|
||||
error(o->expr, "Cannot dereference '%s' because it is a type", str);
|
||||
|
||||
o->mode = Addressing_Invalid;
|
||||
o->expr = node;
|
||||
return kind;
|
||||
|
||||
+25
-10
@@ -418,7 +418,7 @@ gb_internal bool check_is_terminating(Ast *node, String const &label) {
|
||||
|
||||
|
||||
|
||||
gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs) {
|
||||
gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs, String context_name) {
|
||||
if (rhs->mode == Addressing_Invalid) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -430,7 +430,7 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O
|
||||
|
||||
Ast *node = unparen_expr(lhs->expr);
|
||||
|
||||
check_no_copy_assignment(*rhs, str_lit("assignment"));
|
||||
check_no_copy_assignment(*rhs, context_name);
|
||||
|
||||
// NOTE(bill): Ignore assignments to '_'
|
||||
if (is_blank_ident(node)) {
|
||||
@@ -630,7 +630,7 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O
|
||||
ctx->bit_field_bit_size = lhs_e->Variable.bit_field_bit_size;
|
||||
}
|
||||
|
||||
check_assignment(ctx, rhs, assignment_type, str_lit("assignment"));
|
||||
check_assignment(ctx, rhs, assignment_type, context_name);
|
||||
|
||||
ctx->bit_field_bit_size = prev_bit_field_bit_size;
|
||||
|
||||
@@ -1593,6 +1593,20 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_
|
||||
error_line("\tSuggestion: Was '#partial switch' wanted?\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (build_context.strict_style) {
|
||||
Token stok = ss->token;
|
||||
for_array(i, bs->stmts) {
|
||||
Ast *stmt = bs->stmts[i];
|
||||
if (stmt->kind != Ast_CaseClause) {
|
||||
continue;
|
||||
}
|
||||
Token ctok = stmt->CaseClause.token;
|
||||
if (ctok.pos.column > stok.pos.column) {
|
||||
error(ctok, "With '-strict-style', 'case' statements must share the same column as the 'switch' token");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gb_internal void check_block_stmt_for_errors(CheckerContext *ctx, Ast *body) {
|
||||
@@ -2404,7 +2418,7 @@ gb_internal void check_assign_stmt(CheckerContext *ctx, Ast *node) {
|
||||
|
||||
isize lhs_count = as->lhs.count;
|
||||
if (lhs_count == 0) {
|
||||
error(as->op, "Missing lhs in assignment statement");
|
||||
error(as->op, "Missing LHS in assignment statement");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2437,7 +2451,7 @@ gb_internal void check_assign_stmt(CheckerContext *ctx, Ast *node) {
|
||||
if (lhs_to_ignore[i]) {
|
||||
continue;
|
||||
}
|
||||
check_assignment_variable(ctx, &lhs_operands[i], &rhs_operands[i]);
|
||||
check_assignment_variable(ctx, &lhs_operands[i], &rhs_operands[i], str_lit("assignment"));
|
||||
}
|
||||
if (lhs_count != rhs_count) {
|
||||
error(as->lhs[0], "Assignment count mismatch '%td' = '%td'", lhs_count, rhs_count);
|
||||
@@ -2447,11 +2461,11 @@ gb_internal void check_assign_stmt(CheckerContext *ctx, Ast *node) {
|
||||
// a += 1; // Single-sided
|
||||
Token op = as->op;
|
||||
if (as->lhs.count != 1 || as->rhs.count != 1) {
|
||||
error(op, "Assignment operation '%.*s' requires single-valued expressions", LIT(op.string));
|
||||
error(op, "Assignment operator '%.*s' requires single-valued operands", LIT(op.string));
|
||||
return;
|
||||
}
|
||||
if (!gb_is_between(op.kind, Token__AssignOpBegin+1, Token__AssignOpEnd-1)) {
|
||||
error(op, "Unknown Assignment operation '%.*s'", LIT(op.string));
|
||||
error(op, "Unknown assignment operator '%.*s'", LIT(op.string));
|
||||
return;
|
||||
}
|
||||
Operand lhs = {Addressing_Invalid};
|
||||
@@ -2460,15 +2474,16 @@ gb_internal void check_assign_stmt(CheckerContext *ctx, Ast *node) {
|
||||
ast_node(be, BinaryExpr, binary_expr);
|
||||
be->op = op;
|
||||
be->op.kind = cast(TokenKind)(cast(i32)be->op.kind - (Token_AddEq - Token_Add));
|
||||
// NOTE(bill): Only use the first one will be used
|
||||
// NOTE(bill): Only use the first one will be used
|
||||
be->left = as->lhs[0];
|
||||
be->right = as->rhs[0];
|
||||
|
||||
check_expr(ctx, &lhs, as->lhs[0]);
|
||||
check_binary_expr(ctx, &rhs, binary_expr, nullptr, true);
|
||||
if (rhs.mode != Addressing_Invalid) {
|
||||
// NOTE(bill): Only use the first one will be used
|
||||
check_assignment_variable(ctx, &lhs, &rhs);
|
||||
be->op.string = substring(be->op.string, 0, be->op.string.len - 1);
|
||||
rhs.expr = binary_expr;
|
||||
check_assignment_variable(ctx, &lhs, &rhs, str_lit("assignment operation"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -3284,7 +3284,7 @@ gb_internal void check_array_type_internal(CheckerContext *ctx, Ast *e, Type **t
|
||||
}
|
||||
|
||||
if (count < 0) {
|
||||
error(at->count, "? can only be used in conjuction with compound literals");
|
||||
error(at->count, "? can only be used in conjunction with compound literals");
|
||||
count = 0;
|
||||
}
|
||||
|
||||
|
||||
+9
-3
@@ -2054,7 +2054,7 @@ gb_internal void add_type_info_type(CheckerContext *c, Type *t) {
|
||||
}
|
||||
|
||||
gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) {
|
||||
if (t == nullptr) {
|
||||
if (t == nullptr || c == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3776,6 +3776,12 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
|
||||
}
|
||||
ac->no_sanitize_address = true;
|
||||
return true;
|
||||
} else if (name == "no_sanitize_memory") {
|
||||
if (value != nullptr) {
|
||||
error(value, "'%.*s' expects no parameter", LIT(name));
|
||||
}
|
||||
ac->no_sanitize_memory = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -6672,7 +6678,7 @@ gb_internal void check_sort_init_and_fini_procedures(Checker *c) {
|
||||
gb_internal void add_type_info_for_type_definitions(Checker *c) {
|
||||
for_array(i, c->info.definitions) {
|
||||
Entity *e = c->info.definitions[i];
|
||||
if (e->kind == Entity_TypeName && e->type != nullptr) {
|
||||
if (e->kind == Entity_TypeName && e->type != nullptr && is_type_typed(e->type)) {
|
||||
i64 align = type_align_of(e->type);
|
||||
if (align > 0 && ptr_set_exists(&c->info.minimum_dependency_set, e)) {
|
||||
add_type_info_type(&c->builtin_ctx, e->type);
|
||||
@@ -6794,7 +6800,7 @@ gb_internal void check_parsed_files(Checker *c) {
|
||||
// NOTE(bill): Check for illegal cyclic type declarations
|
||||
for_array(i, c->info.definitions) {
|
||||
Entity *e = c->info.definitions[i];
|
||||
if (e->kind == Entity_TypeName && e->type != nullptr) {
|
||||
if (e->kind == Entity_TypeName && e->type != nullptr && is_type_typed(e->type)) {
|
||||
(void)type_align_of(e->type);
|
||||
} else if (e->kind == Entity_Procedure) {
|
||||
DeclInfo *decl = e->decl_info;
|
||||
|
||||
@@ -140,6 +140,7 @@ struct AttributeContext {
|
||||
bool instrumentation_enter : 1;
|
||||
bool instrumentation_exit : 1;
|
||||
bool no_sanitize_address : 1;
|
||||
bool no_sanitize_memory : 1;
|
||||
bool rodata : 1;
|
||||
bool ignore_duplicates : 1;
|
||||
u32 optimization_mode; // ProcedureOptimizationMode
|
||||
|
||||
@@ -240,6 +240,7 @@ BuiltinProc__type_begin,
|
||||
|
||||
BuiltinProc__type_simple_boolean_begin,
|
||||
BuiltinProc_type_is_boolean,
|
||||
BuiltinProc_type_is_bit_field,
|
||||
BuiltinProc_type_is_integer,
|
||||
BuiltinProc_type_is_rune,
|
||||
BuiltinProc_type_is_float,
|
||||
@@ -630,6 +631,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
||||
{STR_LIT("type_is_enum"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_bit_set"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_bit_field"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_simd_vector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_matrix"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
|
||||
+19
-11
@@ -43,7 +43,7 @@ struct OdinDocWriter {
|
||||
};
|
||||
|
||||
gb_internal OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e);
|
||||
gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type);
|
||||
gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type, bool cache);
|
||||
|
||||
template <typename T>
|
||||
gb_internal void odin_doc_writer_item_tracker_init(OdinDocWriterItemTracker<T> *t, isize size) {
|
||||
@@ -467,8 +467,8 @@ gb_internal OdinDocArray<OdinDocString> odin_doc_where_clauses(OdinDocWriter *w,
|
||||
return odin_write_slice(w, clauses.data, clauses.count);
|
||||
}
|
||||
|
||||
gb_internal OdinDocArray<OdinDocTypeIndex> odin_doc_type_as_slice(OdinDocWriter *w, Type *type) {
|
||||
OdinDocTypeIndex index = odin_doc_type(w, type);
|
||||
gb_internal OdinDocArray<OdinDocTypeIndex> odin_doc_type_as_slice(OdinDocWriter *w, Type *type, bool cache=true) {
|
||||
OdinDocTypeIndex index = odin_doc_type(w, type, cache);
|
||||
return odin_write_item_as_slice(w, index);
|
||||
}
|
||||
|
||||
@@ -479,7 +479,7 @@ gb_internal OdinDocArray<OdinDocEntityIndex> odin_doc_add_entity_as_slice(OdinDo
|
||||
|
||||
|
||||
|
||||
gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
|
||||
gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type, bool cache=true) {
|
||||
if (type == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
@@ -491,10 +491,13 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
|
||||
}
|
||||
}
|
||||
|
||||
u64 type_hash = type_hash_canonical_type(type);
|
||||
OdinDocTypeIndex *found = map_get(&w->type_cache, type_hash);
|
||||
if (found) {
|
||||
return *found;
|
||||
u64 type_hash = {0};
|
||||
if (cache) {
|
||||
type_hash = type_hash_canonical_type(type);
|
||||
OdinDocTypeIndex *found = map_get(&w->type_cache, type_hash);
|
||||
if (found) {
|
||||
return *found;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -502,7 +505,9 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
|
||||
OdinDocType doc_type = {};
|
||||
OdinDocTypeIndex type_index = 0;
|
||||
type_index = odin_doc_write_item(w, &w->types, &doc_type, &dst);
|
||||
map_set(&w->type_cache, type_hash, type_index);
|
||||
if (cache) {
|
||||
map_set(&w->type_cache, type_hash, type_index);
|
||||
}
|
||||
|
||||
switch (type->kind) {
|
||||
case Type_Basic:
|
||||
@@ -527,7 +532,10 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
|
||||
doc_type.kind = OdinDocType_Generic;
|
||||
doc_type.name = odin_doc_write_string(w, name);
|
||||
if (type->Generic.specialized) {
|
||||
doc_type.types = odin_doc_type_as_slice(w, type->Generic.specialized);
|
||||
// NOTE(laytan): do not look at the cache for the specialization, it would resolve
|
||||
// to the same entry as the type itself because `default_type` resolves to the
|
||||
// specialization of a generic type.
|
||||
doc_type.types = odin_doc_type_as_slice(w, type->Generic.specialized, cache=false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1163,4 +1171,4 @@ gb_internal void odin_doc_write(CheckerInfo *info, char const *filename) {
|
||||
|
||||
gb_internal bool is_in_doc_writer(void) {
|
||||
return g_in_doc_writer.load();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,6 +263,7 @@ struct Entity {
|
||||
bool uses_branch_location : 1;
|
||||
bool is_anonymous : 1;
|
||||
bool no_sanitize_address : 1;
|
||||
bool no_sanitize_memory : 1;
|
||||
} Procedure;
|
||||
struct {
|
||||
Array<Entity *> entities;
|
||||
|
||||
+1
-1
@@ -823,7 +823,7 @@ gb_internal int error_value_cmp(void const *a, void const *b) {
|
||||
gb_global String error_article_table[][2] = {
|
||||
{str_lit("a "), str_lit("bit_set literal")},
|
||||
{str_lit("a "), str_lit("constant declaration")},
|
||||
{str_lit("a "), str_lit("dynamiic array literal")},
|
||||
{str_lit("a "), str_lit("dynamic array literal")},
|
||||
{str_lit("a "), str_lit("map index")},
|
||||
{str_lit("a "), str_lit("map literal")},
|
||||
{str_lit("a "), str_lit("matrix literal")},
|
||||
|
||||
+5
-1
@@ -497,7 +497,11 @@ typedef i32 b32; // NOTE(bill): Prefer this!!!
|
||||
|
||||
#if !defined(gb_no_asan)
|
||||
#if defined(_MSC_VER)
|
||||
#define gb_no_asan __declspec(no_sanitize_address)
|
||||
#if _MSC_VER >= 1930
|
||||
#define gb_no_asan __declspec(no_sanitize_address)
|
||||
#else
|
||||
#define gb_no_asan
|
||||
#endif
|
||||
#else
|
||||
#define gb_no_asan __attribute__((disable_sanitizer_instrumentation))
|
||||
#endif
|
||||
|
||||
+5
-2
@@ -277,6 +277,9 @@ try_cross_linking:;
|
||||
|
||||
if (build_context.build_mode == BuildMode_DynamicLibrary) {
|
||||
link_settings = gb_string_append_fmt(link_settings, " /DLL");
|
||||
if (build_context.no_entry_point) {
|
||||
link_settings = gb_string_append_fmt(link_settings, " /NOENTRY");
|
||||
}
|
||||
} else {
|
||||
link_settings = gb_string_append_fmt(link_settings, " /ENTRY:mainCRTStartup");
|
||||
}
|
||||
@@ -701,12 +704,12 @@ try_cross_linking:;
|
||||
return result;
|
||||
}
|
||||
|
||||
object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(android_glue_static_lib));
|
||||
object_files = gb_string_append_fmt(object_files, "\'%.*s\' ", LIT(android_glue_static_lib));
|
||||
}
|
||||
|
||||
|
||||
for (String object_path : gen->output_object_paths) {
|
||||
object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path));
|
||||
object_files = gb_string_append_fmt(object_files, "\'%.*s\' ", LIT(object_path));
|
||||
}
|
||||
|
||||
gbString link_settings = gb_string_make_reserve(heap_allocator(), 32);
|
||||
|
||||
+57
-15
@@ -1313,7 +1313,7 @@ namespace lbAbiWasm {
|
||||
registers/arguments if possible rather than by pointer.
|
||||
*/
|
||||
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention, Type *original_type);
|
||||
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
|
||||
gb_internal lbArgType compute_return_type(lbFunctionType *ft, LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple, Type* original_type);
|
||||
|
||||
enum {MAX_DIRECT_STRUCT_SIZE = 32};
|
||||
|
||||
@@ -1323,7 +1323,9 @@ namespace lbAbiWasm {
|
||||
ft->ctx = c;
|
||||
ft->calling_convention = calling_convention;
|
||||
ft->args = compute_arg_types(c, arg_types, arg_count, calling_convention, original_type);
|
||||
ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple);
|
||||
|
||||
GB_ASSERT(original_type->kind == Type_Proc);
|
||||
ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple, original_type->Proc.results);
|
||||
return ft;
|
||||
}
|
||||
|
||||
@@ -1359,7 +1361,7 @@ namespace lbAbiWasm {
|
||||
return false;
|
||||
}
|
||||
|
||||
gb_internal bool type_can_be_direct(LLVMTypeRef type, ProcCallingConvention calling_convention) {
|
||||
gb_internal bool type_can_be_direct(LLVMTypeRef type, Type *original_type, ProcCallingConvention calling_convention) {
|
||||
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||
i64 sz = lb_sizeof(type);
|
||||
if (sz == 0) {
|
||||
@@ -1372,9 +1374,21 @@ namespace lbAbiWasm {
|
||||
return false;
|
||||
} else if (kind == LLVMStructTypeKind) {
|
||||
unsigned count = LLVMCountStructElementTypes(type);
|
||||
if (count == 1) {
|
||||
return type_can_be_direct(LLVMStructGetTypeAtIndex(type, 0), calling_convention);
|
||||
|
||||
// NOTE(laytan): raw unions are always structs with 1 field in LLVM, need to check our own def.
|
||||
Type *bt = base_type(original_type);
|
||||
if (bt->kind == Type_Struct && bt->Struct.is_raw_union) {
|
||||
count = cast(unsigned)bt->Struct.fields.count;
|
||||
}
|
||||
|
||||
if (count == 1) {
|
||||
return type_can_be_direct(
|
||||
LLVMStructGetTypeAtIndex(type, 0),
|
||||
type_internal_index(original_type, 0),
|
||||
calling_convention
|
||||
);
|
||||
}
|
||||
|
||||
} else if (is_basic_register_type(type)) {
|
||||
return true;
|
||||
}
|
||||
@@ -1398,7 +1412,7 @@ namespace lbAbiWasm {
|
||||
return false;
|
||||
}
|
||||
|
||||
gb_internal lbArgType is_struct(LLVMContextRef c, LLVMTypeRef type, ProcCallingConvention calling_convention) {
|
||||
gb_internal lbArgType is_struct(LLVMContextRef c, LLVMTypeRef type, Type *original_type, ProcCallingConvention calling_convention) {
|
||||
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||
GB_ASSERT(kind == LLVMArrayTypeKind || kind == LLVMStructTypeKind);
|
||||
|
||||
@@ -1406,15 +1420,15 @@ namespace lbAbiWasm {
|
||||
if (sz == 0) {
|
||||
return lb_arg_type_ignore(type);
|
||||
}
|
||||
if (type_can_be_direct(type, calling_convention)) {
|
||||
if (type_can_be_direct(type, original_type, calling_convention)) {
|
||||
return lb_arg_type_direct(type);
|
||||
}
|
||||
return lb_arg_type_indirect(type, nullptr);
|
||||
}
|
||||
|
||||
gb_internal lbArgType pseudo_slice(LLVMContextRef c, LLVMTypeRef type, ProcCallingConvention calling_convention) {
|
||||
gb_internal lbArgType pseudo_slice(LLVMContextRef c, LLVMTypeRef type, Type *original_type, ProcCallingConvention calling_convention) {
|
||||
if (build_context.metrics.ptr_size < build_context.metrics.int_size &&
|
||||
type_can_be_direct(type, calling_convention)) {
|
||||
type_can_be_direct(type, original_type, calling_convention)) {
|
||||
LLVMTypeRef types[2] = {
|
||||
LLVMStructGetTypeAtIndex(type, 0),
|
||||
// ignore padding
|
||||
@@ -1423,7 +1437,7 @@ namespace lbAbiWasm {
|
||||
LLVMTypeRef new_type = LLVMStructTypeInContext(c, types, gb_count_of(types), false);
|
||||
return lb_arg_type_direct(type, new_type, nullptr, nullptr);
|
||||
} else {
|
||||
return is_struct(c, type, calling_convention);
|
||||
return is_struct(c, type, original_type, calling_convention);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1444,9 +1458,9 @@ namespace lbAbiWasm {
|
||||
LLVMTypeKind kind = LLVMGetTypeKind(t);
|
||||
if (kind == LLVMStructTypeKind || kind == LLVMArrayTypeKind) {
|
||||
if (is_type_slice(ptype) || is_type_string(ptype)) {
|
||||
args[i] = pseudo_slice(c, t, calling_convention);
|
||||
args[i] = pseudo_slice(c, t, ptype, calling_convention);
|
||||
} else {
|
||||
args[i] = is_struct(c, t, calling_convention);
|
||||
args[i] = is_struct(c, t, ptype, calling_convention);
|
||||
}
|
||||
} else {
|
||||
args[i] = non_struct(c, t, false);
|
||||
@@ -1455,11 +1469,11 @@ namespace lbAbiWasm {
|
||||
return args;
|
||||
}
|
||||
|
||||
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type) {
|
||||
gb_internal lbArgType compute_return_type(lbFunctionType *ft, LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple, Type* original_type) {
|
||||
if (!return_is_defined) {
|
||||
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
||||
} else if (lb_is_type_kind(return_type, LLVMStructTypeKind) || lb_is_type_kind(return_type, LLVMArrayTypeKind)) {
|
||||
if (type_can_be_direct(return_type, ft->calling_convention)) {
|
||||
if (type_can_be_direct(return_type, original_type, ft->calling_convention)) {
|
||||
return lb_arg_type_direct(return_type);
|
||||
} else if (ft->calling_convention != ProcCC_CDecl) {
|
||||
i64 sz = lb_sizeof(return_type);
|
||||
@@ -1471,7 +1485,35 @@ namespace lbAbiWasm {
|
||||
}
|
||||
}
|
||||
|
||||
LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
|
||||
// Multiple returns.
|
||||
if (return_is_tuple) { \
|
||||
lbArgType return_arg = {};
|
||||
if (lb_is_type_kind(return_type, LLVMStructTypeKind)) {
|
||||
unsigned field_count = LLVMCountStructElementTypes(return_type);
|
||||
if (field_count > 1) {
|
||||
ft->original_arg_count = ft->args.count;
|
||||
ft->multiple_return_original_type = return_type;
|
||||
|
||||
for (unsigned i = 0; i < field_count-1; i++) {
|
||||
LLVMTypeRef field_type = LLVMStructGetTypeAtIndex(return_type, i);
|
||||
LLVMTypeRef field_pointer_type = LLVMPointerType(field_type, 0);
|
||||
lbArgType ret_partial = lb_arg_type_direct(field_pointer_type);
|
||||
array_add(&ft->args, ret_partial);
|
||||
}
|
||||
|
||||
return_arg = compute_return_type(
|
||||
ft,
|
||||
c,
|
||||
LLVMStructGetTypeAtIndex(return_type, field_count-1),
|
||||
true, false,
|
||||
type_internal_index(original_type, field_count-1)
|
||||
);
|
||||
}
|
||||
}
|
||||
if (return_arg.type != nullptr) {
|
||||
return return_arg;
|
||||
}
|
||||
}
|
||||
|
||||
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
|
||||
return lb_arg_type_indirect(return_type, attr);
|
||||
|
||||
+170
-3
@@ -292,12 +292,26 @@ gb_internal lbValue lb_const_source_code_location_const(lbModule *m, String cons
|
||||
i32 line = pos.line;
|
||||
i32 column = pos.column;
|
||||
|
||||
if (build_context.obfuscate_source_code_locations) {
|
||||
switch (build_context.source_code_location_info) {
|
||||
case SourceCodeLocationInfo_Normal:
|
||||
break;
|
||||
case SourceCodeLocationInfo_Obfuscated:
|
||||
file = obfuscate_string(file, "F");
|
||||
procedure = obfuscate_string(procedure, "P");
|
||||
|
||||
line = obfuscate_i32(line);
|
||||
column = obfuscate_i32(column);
|
||||
line = obfuscate_i32(line);
|
||||
column = obfuscate_i32(column);
|
||||
break;
|
||||
case SourceCodeLocationInfo_Filename:
|
||||
file = last_path_element(file);
|
||||
break;
|
||||
case SourceCodeLocationInfo_None:
|
||||
file = str_lit("");
|
||||
procedure = str_lit("");
|
||||
|
||||
line = 0;
|
||||
column = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
LLVMValueRef fields[4] = {};
|
||||
@@ -851,6 +865,148 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
case ExactValue_Compound:
|
||||
if (is_type_slice(type)) {
|
||||
return lb_const_value(m, type, value, cc);
|
||||
} else if (is_type_soa_struct(type)) {
|
||||
GB_ASSERT(type->kind == Type_Struct);
|
||||
GB_ASSERT(type->Struct.soa_kind == StructSoa_Fixed);
|
||||
ast_node(cl, CompoundLit, value.value_compound);
|
||||
Type *elem_type = type->Struct.soa_elem;
|
||||
isize elem_count = cl->elems.count;
|
||||
if (elem_count == 0 || !elem_type_can_be_constant(elem_type)) {
|
||||
return lb_const_nil(m, original_type);
|
||||
}
|
||||
if (cl->elems[0]->kind == Ast_FieldValue) {
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
// TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand
|
||||
|
||||
isize elem_count = cast(isize)type->Struct.soa_count;
|
||||
|
||||
LLVMValueRef *aos_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, elem_count);
|
||||
|
||||
isize value_index = 0;
|
||||
for (i64 i = 0; i < elem_count; i++) {
|
||||
bool found = false;
|
||||
|
||||
for (isize j = 0; j < elem_count; j++) {
|
||||
Ast *elem = cl->elems[j];
|
||||
ast_node(fv, FieldValue, elem);
|
||||
if (is_ast_range(fv->field)) {
|
||||
ast_node(ie, BinaryExpr, fv->field);
|
||||
TypeAndValue lo_tav = ie->left->tav;
|
||||
TypeAndValue hi_tav = ie->right->tav;
|
||||
GB_ASSERT(lo_tav.mode == Addressing_Constant);
|
||||
GB_ASSERT(hi_tav.mode == Addressing_Constant);
|
||||
|
||||
TokenKind op = ie->op.kind;
|
||||
i64 lo = exact_value_to_i64(lo_tav.value);
|
||||
i64 hi = exact_value_to_i64(hi_tav.value);
|
||||
if (op != Token_RangeHalf) {
|
||||
hi += 1;
|
||||
}
|
||||
if (lo == i) {
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
for (i64 k = lo; k < hi; k++) {
|
||||
aos_values[value_index++] = val;
|
||||
}
|
||||
|
||||
found = true;
|
||||
i += (hi-lo-1);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
TypeAndValue index_tav = fv->field->tav;
|
||||
GB_ASSERT(index_tav.mode == Addressing_Constant);
|
||||
i64 index = exact_value_to_i64(index_tav.value);
|
||||
if (index == i) {
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
aos_values[value_index++] = val;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
aos_values[value_index++] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
isize field_count = type->Struct.fields.count;
|
||||
LLVMValueRef *soa_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, field_count);
|
||||
|
||||
for (isize i = 0; i < field_count; i++) {
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, elem_count);
|
||||
|
||||
Entity *f = type->Struct.fields[i];
|
||||
Type *array_type = f->type;
|
||||
GB_ASSERT(array_type->kind == Type_Array);
|
||||
Type *field_type = array_type->Array.elem;
|
||||
|
||||
for (isize j = 0; j < elem_count; j++) {
|
||||
LLVMValueRef v = aos_values[j];
|
||||
if (v != nullptr) {
|
||||
values[j] = llvm_const_extract_value(m, v, cast(unsigned)i);
|
||||
} else {
|
||||
values[j] = LLVMConstNull(lb_type(m, field_type));
|
||||
}
|
||||
}
|
||||
|
||||
soa_values[i] = lb_build_constant_array_values(m, array_type, field_type, elem_count, values, cc);
|
||||
}
|
||||
|
||||
res.value = llvm_const_named_struct(m, type, soa_values, field_count);
|
||||
return res;
|
||||
} else {
|
||||
GB_ASSERT_MSG(elem_count == type->Struct.soa_count, "%td != %td", elem_count, type->Struct.soa_count);
|
||||
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
isize elem_count = cast(isize)type->Struct.soa_count;
|
||||
|
||||
LLVMValueRef *aos_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, elem_count);
|
||||
|
||||
for (isize i = 0; i < elem_count; i++) {
|
||||
TypeAndValue tav = cl->elems[i]->tav;
|
||||
GB_ASSERT(tav.mode != Addressing_Invalid);
|
||||
aos_values[i] = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
}
|
||||
for (isize i = elem_count; i < type->Struct.soa_count; i++) {
|
||||
aos_values[i] = nullptr;
|
||||
}
|
||||
|
||||
isize field_count = type->Struct.fields.count;
|
||||
LLVMValueRef *soa_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, field_count);
|
||||
|
||||
for (isize i = 0; i < field_count; i++) {
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, elem_count);
|
||||
|
||||
Entity *f = type->Struct.fields[i];
|
||||
Type *array_type = f->type;
|
||||
GB_ASSERT(array_type->kind == Type_Array);
|
||||
Type *field_type = array_type->Array.elem;
|
||||
|
||||
for (isize j = 0; j < elem_count; j++) {
|
||||
LLVMValueRef v = aos_values[j];
|
||||
if (v != nullptr) {
|
||||
values[j] = llvm_const_extract_value(m, v, cast(unsigned)i);
|
||||
} else {
|
||||
values[j] = LLVMConstNull(lb_type(m, field_type));
|
||||
}
|
||||
}
|
||||
|
||||
soa_values[i] = lb_build_constant_array_values(m, array_type, field_type, elem_count, values, cc);
|
||||
}
|
||||
|
||||
res.value = llvm_const_named_struct(m, type, soa_values, field_count);
|
||||
return res;
|
||||
}
|
||||
} else if (is_type_array(type)) {
|
||||
ast_node(cl, CompoundLit, value.value_compound);
|
||||
Type *elem_type = type->Array.elem;
|
||||
@@ -912,9 +1068,20 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
}
|
||||
}
|
||||
|
||||
res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc);
|
||||
return res;
|
||||
} else if (value.value_compound->tav.type == elem_type) {
|
||||
// Compound is of array item type; expand its value to all items in array.
|
||||
LLVMValueRef* values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count);
|
||||
|
||||
for (isize i = 0; i < type->Array.count; i++) {
|
||||
values[i] = lb_const_value(m, elem_type, value, cc).value;
|
||||
}
|
||||
|
||||
res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc);
|
||||
return res;
|
||||
} else {
|
||||
// Assume that compound value is an array literal
|
||||
GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count);
|
||||
|
||||
LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count);
|
||||
|
||||
@@ -4933,7 +4933,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
|
||||
if (cl->elems.count == 0) {
|
||||
break;
|
||||
}
|
||||
GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals);
|
||||
GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals || build_context.dynamic_literals);
|
||||
|
||||
Type *et = bt->DynamicArray.elem;
|
||||
lbValue size = lb_const_int(p->module, t_int, type_size_of(et));
|
||||
|
||||
@@ -546,8 +546,11 @@ gb_internal lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) {
|
||||
break;
|
||||
|
||||
case lbAddr_Swizzle:
|
||||
GB_PANIC("lbAddr_Swizzle should be handled elsewhere");
|
||||
break;
|
||||
|
||||
case lbAddr_SwizzleLarge:
|
||||
// TOOD(bill): is this good enough logic?
|
||||
GB_PANIC("lbAddr_SwizzleLarge should be handled elsewhere");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -565,10 +568,22 @@ gb_internal void lb_set_file_line_col(lbProcedure *p, Array<lbValue> arr, TokenP
|
||||
i32 line = pos.line;
|
||||
i32 col = pos.column;
|
||||
|
||||
if (build_context.obfuscate_source_code_locations) {
|
||||
switch (build_context.source_code_location_info) {
|
||||
case SourceCodeLocationInfo_Normal:
|
||||
break;
|
||||
case SourceCodeLocationInfo_Obfuscated:
|
||||
file = obfuscate_string(file, "F");
|
||||
line = obfuscate_i32(line);
|
||||
col = obfuscate_i32(col);
|
||||
break;
|
||||
case SourceCodeLocationInfo_Filename:
|
||||
file = last_path_element(file);
|
||||
break;
|
||||
case SourceCodeLocationInfo_None:
|
||||
file = str_lit("");
|
||||
line = 0;
|
||||
col = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
arr[0] = lb_find_or_add_entity_string(p->module, file, false);
|
||||
@@ -922,7 +937,7 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
|
||||
GB_ASSERT(value.value != nullptr);
|
||||
value = lb_emit_conv(p, value, lb_addr_type(addr));
|
||||
|
||||
lbValue dst = lb_addr_get_ptr(p, addr);
|
||||
lbValue dst = addr.addr;
|
||||
lbValue src = lb_address_from_load_or_generate_local(p, value);
|
||||
{
|
||||
lbValue src_ptrs[4] = {};
|
||||
@@ -948,7 +963,7 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
|
||||
GB_ASSERT(value.value != nullptr);
|
||||
value = lb_emit_conv(p, value, lb_addr_type(addr));
|
||||
|
||||
lbValue dst = lb_addr_get_ptr(p, addr);
|
||||
lbValue dst = addr.addr;
|
||||
lbValue src = lb_address_from_load_or_generate_local(p, value);
|
||||
for_array(i, addr.swizzle_large.indices) {
|
||||
lbValue src_ptr = lb_emit_array_epi(p, src, i);
|
||||
@@ -2203,7 +2218,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
|
||||
field_count = 3;
|
||||
}
|
||||
LLVMTypeRef *fields = gb_alloc_array(permanent_allocator(), LLVMTypeRef, field_count);
|
||||
fields[0] = LLVMPointerType(lb_type(m, type->Pointer.elem), 0);
|
||||
fields[0] = LLVMPointerType(lb_type(m, type->SoaPointer.elem), 0);
|
||||
if (bigger_int) {
|
||||
fields[1] = lb_type_padding_filler(m, build_context.ptr_size, build_context.ptr_size);
|
||||
fields[2] = LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.int_size);
|
||||
|
||||
+23
-21
@@ -345,7 +345,7 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i
|
||||
if (build_context.sanitizer_flags & SanitizerFlag_Address && !entity->Procedure.no_sanitize_address) {
|
||||
lb_add_attribute_to_proc(m, p->value, "sanitize_address");
|
||||
}
|
||||
if (build_context.sanitizer_flags & SanitizerFlag_Memory) {
|
||||
if (build_context.sanitizer_flags & SanitizerFlag_Memory && !entity->Procedure.no_sanitize_memory) {
|
||||
lb_add_attribute_to_proc(m, p->value, "sanitize_memory");
|
||||
}
|
||||
if (build_context.sanitizer_flags & SanitizerFlag_Thread) {
|
||||
@@ -546,6 +546,9 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) {
|
||||
GB_ASSERT(p->type != nullptr);
|
||||
|
||||
lb_ensure_abi_function_type(p->module, p);
|
||||
if (p->type->Proc.calling_convention == ProcCC_Odin) {
|
||||
lb_push_context_onto_stack_from_implicit_parameter(p);
|
||||
}
|
||||
{
|
||||
lbFunctionType *ft = p->abi_function_type;
|
||||
|
||||
@@ -743,9 +746,6 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) {
|
||||
|
||||
}
|
||||
}
|
||||
if (p->type->Proc.calling_convention == ProcCC_Odin) {
|
||||
lb_push_context_onto_stack_from_implicit_parameter(p);
|
||||
}
|
||||
|
||||
lb_set_debug_position_to_procedure_begin(p);
|
||||
if (p->debug_info != nullptr) {
|
||||
@@ -1962,7 +1962,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
|
||||
|
||||
LLVMValueRef values[2] = {};
|
||||
values[0] = lb_const_string(m, file_name).value;
|
||||
values[1] = lb_const_string(m, file->data).value;
|
||||
values[1] = lb_const_value(m, t_u8_slice, exact_value_string(file->data)).value;
|
||||
LLVMValueRef element = llvm_const_named_struct(m, t_load_directory_file, values, gb_count_of(values));
|
||||
elements[i] = element;
|
||||
}
|
||||
@@ -2774,15 +2774,18 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
|
||||
LLVMSetMetadata(instr, kind_id, LLVMMetadataAsValue(p->module->ctx, node));
|
||||
}
|
||||
break;
|
||||
case BuiltinProc_volatile_store: LLVMSetVolatile(instr, true); break;
|
||||
case BuiltinProc_atomic_store: LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent); break;
|
||||
case BuiltinProc_volatile_store:
|
||||
LLVMSetVolatile(instr, true);
|
||||
break;
|
||||
case BuiltinProc_atomic_store:
|
||||
LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent);
|
||||
LLVMSetVolatile(instr, true);
|
||||
break;
|
||||
case BuiltinProc_atomic_store_explicit:
|
||||
{
|
||||
auto ordering = llvm_atomic_ordering_from_odin(ce->args[2]);
|
||||
LLVMSetOrdering(instr, ordering);
|
||||
if (ordering == LLVMAtomicOrderingUnordered) {
|
||||
LLVMSetVolatile(instr, true);
|
||||
}
|
||||
LLVMSetVolatile(instr, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2808,15 +2811,18 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case BuiltinProc_volatile_load: LLVMSetVolatile(instr, true); break;
|
||||
case BuiltinProc_atomic_load: LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent); break;
|
||||
case BuiltinProc_volatile_load:
|
||||
LLVMSetVolatile(instr, true);
|
||||
break;
|
||||
case BuiltinProc_atomic_load:
|
||||
LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent);
|
||||
LLVMSetVolatile(instr, true);
|
||||
break;
|
||||
case BuiltinProc_atomic_load_explicit:
|
||||
{
|
||||
auto ordering = llvm_atomic_ordering_from_odin(ce->args[1]);
|
||||
LLVMSetOrdering(instr, ordering);
|
||||
if (ordering == LLVMAtomicOrderingUnordered) {
|
||||
LLVMSetVolatile(instr, true);
|
||||
}
|
||||
LLVMSetVolatile(instr, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2901,9 +2907,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
|
||||
lbValue res = {};
|
||||
res.value = LLVMBuildAtomicRMW(p->builder, op, dst.value, val.value, ordering, false);
|
||||
res.type = tv.type;
|
||||
if (ordering == LLVMAtomicOrderingUnordered) {
|
||||
LLVMSetVolatile(res.value, true);
|
||||
}
|
||||
LLVMSetVolatile(res.value, true);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -2939,9 +2943,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
|
||||
single_threaded
|
||||
);
|
||||
LLVMSetWeak(value, weak);
|
||||
if (success_ordering == LLVMAtomicOrderingUnordered || failure_ordering == LLVMAtomicOrderingUnordered) {
|
||||
LLVMSetVolatile(value, true);
|
||||
}
|
||||
LLVMSetVolatile(value, true);
|
||||
|
||||
if (is_type_tuple(tv.type)) {
|
||||
Type *fix_typed = alloc_type_tuple();
|
||||
|
||||
@@ -1072,10 +1072,22 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
|
||||
break;
|
||||
}
|
||||
case Type_Array: {
|
||||
lbValue array = lb_build_addr_ptr(p, expr);
|
||||
if (is_type_pointer(type_deref(array.type))) {
|
||||
array = lb_emit_load(p, array);
|
||||
lbValue array;
|
||||
lbAddr addr = lb_build_addr(p, expr);
|
||||
switch (addr.kind) {
|
||||
case lbAddr_Swizzle:
|
||||
case lbAddr_SwizzleLarge:
|
||||
// NOTE(laytan): apply the swizzle.
|
||||
array = lb_address_from_load(p, lb_addr_load(p, addr));
|
||||
break;
|
||||
default:
|
||||
array = lb_addr_get_ptr(p, addr);
|
||||
if (is_type_pointer(type_deref(array.type))) {
|
||||
array = lb_emit_load(p, array);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
lbAddr count_ptr = lb_add_local_generated(p, t_int, false);
|
||||
lb_addr_store(p, count_ptr, lb_const_int(p->module, t_int, et->Array.count));
|
||||
lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done, rs->reverse);
|
||||
|
||||
+92
-64
@@ -370,6 +370,7 @@ enum BuildFlagKind {
|
||||
BuildFlag_NoRTTI,
|
||||
BuildFlag_DynamicMapCalls,
|
||||
BuildFlag_ObfuscateSourceCodeLocations,
|
||||
BuildFlag_SourceCodeLocations,
|
||||
|
||||
BuildFlag_Compact,
|
||||
BuildFlag_GlobalDefinitions,
|
||||
@@ -594,9 +595,10 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
add_flag(&build_flags, BuildFlag_DynamicMapCalls, str_lit("dynamic-map-calls"), BuildFlagParam_None, Command__does_check);
|
||||
|
||||
add_flag(&build_flags, BuildFlag_ObfuscateSourceCodeLocations, str_lit("obfuscate-source-code-locations"), BuildFlagParam_None, Command__does_build);
|
||||
add_flag(&build_flags, BuildFlag_SourceCodeLocations, str_lit("source-code-locations"), BuildFlagParam_String, Command__does_build);
|
||||
|
||||
add_flag(&build_flags, BuildFlag_Short, str_lit("short"), BuildFlagParam_None, Command_doc);
|
||||
add_flag(&build_flags, BuildFlag_AllPackages, str_lit("all-packages"), BuildFlagParam_None, Command_doc | Command_test);
|
||||
add_flag(&build_flags, BuildFlag_AllPackages, str_lit("all-packages"), BuildFlagParam_None, Command_doc | Command_test | Command_build);
|
||||
add_flag(&build_flags, BuildFlag_DocFormat, str_lit("doc-format"), BuildFlagParam_None, Command_doc);
|
||||
|
||||
add_flag(&build_flags, BuildFlag_IgnoreWarnings, str_lit("ignore-warnings"), BuildFlagParam_None, Command_all);
|
||||
@@ -1422,7 +1424,23 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
break;
|
||||
|
||||
case BuildFlag_ObfuscateSourceCodeLocations:
|
||||
build_context.obfuscate_source_code_locations = true;
|
||||
gb_printf_err("'-obfuscate-source-code-locations' is now deprecated in favor of '-source-code-locations:obfuscated'\n");
|
||||
build_context.source_code_location_info = SourceCodeLocationInfo_Obfuscated;
|
||||
break;
|
||||
|
||||
case BuildFlag_SourceCodeLocations:
|
||||
if (str_eq_ignore_case(value.value_string, str_lit("normal"))) {
|
||||
build_context.source_code_location_info = SourceCodeLocationInfo_Normal;
|
||||
} else if (str_eq_ignore_case(value.value_string, str_lit("obfuscated"))) {
|
||||
build_context.source_code_location_info = SourceCodeLocationInfo_Obfuscated;
|
||||
} else if (str_eq_ignore_case(value.value_string, str_lit("filename"))) {
|
||||
build_context.source_code_location_info = SourceCodeLocationInfo_Filename;
|
||||
} else if (str_eq_ignore_case(value.value_string, str_lit("none"))) {
|
||||
build_context.source_code_location_info = SourceCodeLocationInfo_None;
|
||||
} else {
|
||||
gb_printf_err("-source-code-locations:<string> options are 'normal', 'obfuscated', 'filename', and 'none'\n");
|
||||
bad_flags = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case BuildFlag_DefaultToNilAllocator:
|
||||
@@ -1555,6 +1573,11 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
case BuildFlag_Sanitize:
|
||||
GB_ASSERT(value.kind == ExactValue_String);
|
||||
|
||||
if (build_context.sanitizer_flags != 0) {
|
||||
gb_printf_err("-sanitize:<string> may only be used once\n");
|
||||
bad_flags = true;
|
||||
}
|
||||
|
||||
if (str_eq_ignore_case(value.value_string, str_lit("address"))) {
|
||||
build_context.sanitizer_flags |= SanitizerFlag_Address;
|
||||
} else if (str_eq_ignore_case(value.value_string, str_lit("memory"))) {
|
||||
@@ -1733,6 +1756,12 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
bad_flags = true;
|
||||
}
|
||||
|
||||
|
||||
if ((build_context.command_kind & (Command_doc | Command_test)) == 0 && build_context.test_all_packages) {
|
||||
gb_printf_err("`-test-all-packages` can only be used with `odin build -build-mode:test`, `odin test`, or `odin doc`.\n");
|
||||
bad_flags = true;
|
||||
}
|
||||
|
||||
return !bad_flags;
|
||||
}
|
||||
|
||||
@@ -1985,39 +2014,39 @@ gb_internal void show_timings(Checker *c, Timings *t) {
|
||||
|
||||
if (build_context.show_debug_messages && build_context.show_more_timings) {
|
||||
{
|
||||
gb_printf("\n");
|
||||
gb_printf("Total Lines - %td\n", lines);
|
||||
gb_printf("Total Tokens - %td\n", tokens);
|
||||
gb_printf("Total Files - %td\n", files);
|
||||
gb_printf("Total Packages - %td\n", packages);
|
||||
gb_printf("Total File Size - %td\n", total_file_size);
|
||||
gb_printf("\n");
|
||||
gb_printf_err("\n");
|
||||
gb_printf_err("Total Lines - %td\n", lines);
|
||||
gb_printf_err("Total Tokens - %td\n", tokens);
|
||||
gb_printf_err("Total Files - %td\n", files);
|
||||
gb_printf_err("Total Packages - %td\n", packages);
|
||||
gb_printf_err("Total File Size - %td\n", total_file_size);
|
||||
gb_printf_err("\n");
|
||||
}
|
||||
{
|
||||
f64 time = total_tokenizing_time;
|
||||
gb_printf("Tokenization Only\n");
|
||||
gb_printf("LOC/s - %.3f\n", cast(f64)lines/time);
|
||||
gb_printf("us/LOC - %.3f\n", 1.0e6*time/cast(f64)lines);
|
||||
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/time);
|
||||
gb_printf("us/Token - %.3f\n", 1.0e6*time/cast(f64)tokens);
|
||||
gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/time);
|
||||
gb_printf("MiB/s - %.3f\n", cast(f64)(total_file_size/time)/(1024*1024));
|
||||
gb_printf("us/bytes - %.3f\n", 1.0e6*time/cast(f64)total_file_size);
|
||||
gb_printf_err("Tokenization Only\n");
|
||||
gb_printf_err("LOC/s - %.3f\n", cast(f64)lines/time);
|
||||
gb_printf_err("us/LOC - %.3f\n", 1.0e6*time/cast(f64)lines);
|
||||
gb_printf_err("Tokens/s - %.3f\n", cast(f64)tokens/time);
|
||||
gb_printf_err("us/Token - %.3f\n", 1.0e6*time/cast(f64)tokens);
|
||||
gb_printf_err("bytes/s - %.3f\n", cast(f64)total_file_size/time);
|
||||
gb_printf_err("MiB/s - %.3f\n", cast(f64)(total_file_size/time)/(1024*1024));
|
||||
gb_printf_err("us/bytes - %.3f\n", 1.0e6*time/cast(f64)total_file_size);
|
||||
|
||||
gb_printf("\n");
|
||||
gb_printf_err("\n");
|
||||
}
|
||||
{
|
||||
f64 time = total_parsing_time;
|
||||
gb_printf("Parsing Only\n");
|
||||
gb_printf("LOC/s - %.3f\n", cast(f64)lines/time);
|
||||
gb_printf("us/LOC - %.3f\n", 1.0e6*time/cast(f64)lines);
|
||||
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/time);
|
||||
gb_printf("us/Token - %.3f\n", 1.0e6*time/cast(f64)tokens);
|
||||
gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/time);
|
||||
gb_printf("MiB/s - %.3f\n", cast(f64)(total_file_size/time)/(1024*1024));
|
||||
gb_printf("us/bytes - %.3f\n", 1.0e6*time/cast(f64)total_file_size);
|
||||
gb_printf_err("Parsing Only\n");
|
||||
gb_printf_err("LOC/s - %.3f\n", cast(f64)lines/time);
|
||||
gb_printf_err("us/LOC - %.3f\n", 1.0e6*time/cast(f64)lines);
|
||||
gb_printf_err("Tokens/s - %.3f\n", cast(f64)tokens/time);
|
||||
gb_printf_err("us/Token - %.3f\n", 1.0e6*time/cast(f64)tokens);
|
||||
gb_printf_err("bytes/s - %.3f\n", cast(f64)total_file_size/time);
|
||||
gb_printf_err("MiB/s - %.3f\n", cast(f64)(total_file_size/time)/(1024*1024));
|
||||
gb_printf_err("us/bytes - %.3f\n", 1.0e6*time/cast(f64)total_file_size);
|
||||
|
||||
gb_printf("\n");
|
||||
gb_printf_err("\n");
|
||||
}
|
||||
{
|
||||
TimeStamp ts = {};
|
||||
@@ -2030,16 +2059,16 @@ gb_internal void show_timings(Checker *c, Timings *t) {
|
||||
GB_ASSERT(ts.label == "parse files");
|
||||
|
||||
f64 parse_time = time_stamp_as_s(ts, t->freq);
|
||||
gb_printf("Parse pass\n");
|
||||
gb_printf("LOC/s - %.3f\n", cast(f64)lines/parse_time);
|
||||
gb_printf("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
|
||||
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/parse_time);
|
||||
gb_printf("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens);
|
||||
gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time);
|
||||
gb_printf("MiB/s - %.3f\n", cast(f64)(total_file_size/parse_time)/(1024*1024));
|
||||
gb_printf("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size);
|
||||
gb_printf_err("Parse pass\n");
|
||||
gb_printf_err("LOC/s - %.3f\n", cast(f64)lines/parse_time);
|
||||
gb_printf_err("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
|
||||
gb_printf_err("Tokens/s - %.3f\n", cast(f64)tokens/parse_time);
|
||||
gb_printf_err("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens);
|
||||
gb_printf_err("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time);
|
||||
gb_printf_err("MiB/s - %.3f\n", cast(f64)(total_file_size/parse_time)/(1024*1024));
|
||||
gb_printf_err("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size);
|
||||
|
||||
gb_printf("\n");
|
||||
gb_printf_err("\n");
|
||||
}
|
||||
{
|
||||
TimeStamp ts = {};
|
||||
@@ -2060,27 +2089,27 @@ gb_internal void show_timings(Checker *c, Timings *t) {
|
||||
ts.finish = ts_end.finish;
|
||||
|
||||
f64 parse_time = time_stamp_as_s(ts, t->freq);
|
||||
gb_printf("Checker pass\n");
|
||||
gb_printf("LOC/s - %.3f\n", cast(f64)lines/parse_time);
|
||||
gb_printf("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
|
||||
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/parse_time);
|
||||
gb_printf("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens);
|
||||
gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time);
|
||||
gb_printf("MiB/s - %.3f\n", (cast(f64)total_file_size/parse_time)/(1024*1024));
|
||||
gb_printf("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size);
|
||||
gb_printf("\n");
|
||||
gb_printf_err("Checker pass\n");
|
||||
gb_printf_err("LOC/s - %.3f\n", cast(f64)lines/parse_time);
|
||||
gb_printf_err("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
|
||||
gb_printf_err("Tokens/s - %.3f\n", cast(f64)tokens/parse_time);
|
||||
gb_printf_err("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens);
|
||||
gb_printf_err("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time);
|
||||
gb_printf_err("MiB/s - %.3f\n", (cast(f64)total_file_size/parse_time)/(1024*1024));
|
||||
gb_printf_err("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size);
|
||||
gb_printf_err("\n");
|
||||
}
|
||||
{
|
||||
f64 total_time = t->total_time_seconds;
|
||||
gb_printf("Total pass\n");
|
||||
gb_printf("LOC/s - %.3f\n", cast(f64)lines/total_time);
|
||||
gb_printf("us/LOC - %.3f\n", 1.0e6*total_time/cast(f64)lines);
|
||||
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/total_time);
|
||||
gb_printf("us/Token - %.3f\n", 1.0e6*total_time/cast(f64)tokens);
|
||||
gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/total_time);
|
||||
gb_printf("MiB/s - %.3f\n", cast(f64)(total_file_size/total_time)/(1024*1024));
|
||||
gb_printf("us/bytes - %.3f\n", 1.0e6*total_time/cast(f64)total_file_size);
|
||||
gb_printf("\n");
|
||||
gb_printf_err("Total pass\n");
|
||||
gb_printf_err("LOC/s - %.3f\n", cast(f64)lines/total_time);
|
||||
gb_printf_err("us/LOC - %.3f\n", 1.0e6*total_time/cast(f64)lines);
|
||||
gb_printf_err("Tokens/s - %.3f\n", cast(f64)tokens/total_time);
|
||||
gb_printf_err("us/Token - %.3f\n", 1.0e6*total_time/cast(f64)tokens);
|
||||
gb_printf_err("bytes/s - %.3f\n", cast(f64)total_file_size/total_time);
|
||||
gb_printf_err("MiB/s - %.3f\n", cast(f64)(total_file_size/total_time)/(1024*1024));
|
||||
gb_printf_err("us/bytes - %.3f\n", 1.0e6*total_time/cast(f64)total_file_size);
|
||||
gb_printf_err("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2386,12 +2415,6 @@ gb_internal int print_show_help(String const arg0, String command, String option
|
||||
}
|
||||
}
|
||||
|
||||
if (test_only) {
|
||||
if (print_flag("-build-only")) {
|
||||
print_usage_line(2, "Only builds the test executable; does not automatically run it afterwards.");
|
||||
}
|
||||
}
|
||||
|
||||
if (check) {
|
||||
if (print_flag("-collection:<name>=<filepath>")) {
|
||||
print_usage_line(2, "Defines a library collection used for imports.");
|
||||
@@ -2658,8 +2681,14 @@ gb_internal int print_show_help(String const arg0, String command, String option
|
||||
}
|
||||
|
||||
|
||||
if (print_flag("-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.");
|
||||
if (print_flag("-source-code-locations:<string>")) {
|
||||
print_usage_line(2, "Processes the file and procedure strings, and line and column numbers, stored with a 'runtime.Source_Code_Location' value.");
|
||||
print_usage_line(2, "Available options:");
|
||||
print_usage_line(3, "-source-code-locations:normal");
|
||||
print_usage_line(3, "-source-code-locations:obfuscated");
|
||||
print_usage_line(3, "-source-code-locations:filename");
|
||||
print_usage_line(3, "-source-code-locations:none");
|
||||
print_usage_line(2, "The default is -source-code-locations:normal.");
|
||||
}
|
||||
|
||||
|
||||
@@ -2671,7 +2700,7 @@ gb_internal int print_show_help(String const arg0, String command, String option
|
||||
|
||||
if (doc) {
|
||||
if (print_flag("-out:<filepath>")) {
|
||||
print_usage_line(2, "Sets the base name of the resultig .odin-doc file.");
|
||||
print_usage_line(2, "Sets the base name of the resulting .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");
|
||||
}
|
||||
@@ -2722,7 +2751,6 @@ gb_internal int print_show_help(String const arg0, String command, String option
|
||||
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.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -5832,7 +5832,7 @@ gb_internal AstPackage *try_add_import_path(Parser *p, String path, String const
|
||||
for (FileInfo fi : list) {
|
||||
String name = fi.name;
|
||||
String ext = path_extension(name);
|
||||
if (ext == FILE_EXT) {
|
||||
if (ext == FILE_EXT && !path_is_directory(name)) {
|
||||
files_with_ext += 1;
|
||||
}
|
||||
if (ext == FILE_EXT && !is_excluded_target_filename(name)) {
|
||||
@@ -5857,7 +5857,7 @@ gb_internal AstPackage *try_add_import_path(Parser *p, String path, String const
|
||||
for (FileInfo fi : list) {
|
||||
String name = fi.name;
|
||||
String ext = path_extension(name);
|
||||
if (ext == FILE_EXT) {
|
||||
if (ext == FILE_EXT && !path_is_directory(name)) {
|
||||
if (is_excluded_target_filename(name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
+2
-2
@@ -197,7 +197,7 @@ gb_internal void timings_print_all(Timings *t, TimingUnit unit = TimingUnit_Mill
|
||||
|
||||
f64 total_time = time_stamp(t->total, t->freq, unit);
|
||||
|
||||
gb_printf("%.*s%.*s - % 9.3f %s - %6.2f%%\n",
|
||||
gb_printf_err("%.*s%.*s - % 9.3f %s - %6.2f%%\n",
|
||||
LIT(t->total.label),
|
||||
cast(int)(max_len-t->total.label.len), SPACES,
|
||||
total_time,
|
||||
@@ -207,7 +207,7 @@ gb_internal void timings_print_all(Timings *t, TimingUnit unit = TimingUnit_Mill
|
||||
for_array(i, t->sections) {
|
||||
TimeStamp ts = t->sections[i];
|
||||
f64 section_time = time_stamp(ts, t->freq, unit);
|
||||
gb_printf("%.*s%.*s - % 9.3f %s - %6.2f%%\n",
|
||||
gb_printf_err("%.*s%.*s - % 9.3f %s - %6.2f%%\n",
|
||||
LIT(ts.label),
|
||||
cast(int)(max_len-ts.label.len), SPACES,
|
||||
section_time,
|
||||
|
||||
+132
-14
@@ -1203,6 +1203,7 @@ gb_internal Type *type_deref(Type *t, bool allow_multi_pointer) {
|
||||
}
|
||||
|
||||
gb_internal bool is_type_named(Type *t) {
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
return true;
|
||||
}
|
||||
@@ -1212,6 +1213,7 @@ gb_internal bool is_type_named(Type *t) {
|
||||
gb_internal bool is_type_boolean(Type *t) {
|
||||
// t = core_type(t);
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_Boolean) != 0;
|
||||
}
|
||||
@@ -1220,6 +1222,7 @@ gb_internal bool is_type_boolean(Type *t) {
|
||||
gb_internal bool is_type_integer(Type *t) {
|
||||
// t = core_type(t);
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_Integer) != 0;
|
||||
}
|
||||
@@ -1241,15 +1244,18 @@ gb_internal bool is_type_integer_like(Type *t) {
|
||||
|
||||
gb_internal bool is_type_unsigned(Type *t) {
|
||||
t = base_type(t);
|
||||
// t = core_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_Unsigned) != 0;
|
||||
}
|
||||
if (t->kind == Type_Enum) {
|
||||
return (t->Enum.base_type->Basic.flags & BasicFlag_Unsigned) != 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
gb_internal bool is_type_integer_128bit(Type *t) {
|
||||
// t = core_type(t);
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_Integer) != 0 && t->Basic.size == 16;
|
||||
}
|
||||
@@ -1258,6 +1264,7 @@ gb_internal bool is_type_integer_128bit(Type *t) {
|
||||
gb_internal bool is_type_rune(Type *t) {
|
||||
// t = core_type(t);
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_Rune) != 0;
|
||||
}
|
||||
@@ -1266,6 +1273,7 @@ gb_internal bool is_type_rune(Type *t) {
|
||||
gb_internal bool is_type_numeric(Type *t) {
|
||||
// t = core_type(t);
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_Numeric) != 0;
|
||||
} else if (t->kind == Type_Enum) {
|
||||
@@ -1279,6 +1287,7 @@ gb_internal bool is_type_numeric(Type *t) {
|
||||
}
|
||||
gb_internal bool is_type_string(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_String) != 0;
|
||||
}
|
||||
@@ -1286,6 +1295,7 @@ gb_internal bool is_type_string(Type *t) {
|
||||
}
|
||||
gb_internal bool is_type_cstring(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
return t->Basic.kind == Basic_cstring;
|
||||
}
|
||||
@@ -1293,9 +1303,7 @@ gb_internal bool is_type_cstring(Type *t) {
|
||||
}
|
||||
gb_internal bool is_type_typed(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_Untyped) == 0;
|
||||
}
|
||||
@@ -1303,9 +1311,7 @@ gb_internal bool is_type_typed(Type *t) {
|
||||
}
|
||||
gb_internal bool is_type_untyped(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_Untyped) != 0;
|
||||
}
|
||||
@@ -1313,6 +1319,7 @@ gb_internal bool is_type_untyped(Type *t) {
|
||||
}
|
||||
gb_internal bool is_type_ordered(Type *t) {
|
||||
t = core_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
switch (t->kind) {
|
||||
case Type_Basic:
|
||||
return (t->Basic.flags & BasicFlag_Ordered) != 0;
|
||||
@@ -1325,6 +1332,7 @@ gb_internal bool is_type_ordered(Type *t) {
|
||||
}
|
||||
gb_internal bool is_type_ordered_numeric(Type *t) {
|
||||
t = core_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
switch (t->kind) {
|
||||
case Type_Basic:
|
||||
return (t->Basic.flags & BasicFlag_OrderedNumeric) != 0;
|
||||
@@ -1333,6 +1341,7 @@ gb_internal bool is_type_ordered_numeric(Type *t) {
|
||||
}
|
||||
gb_internal bool is_type_constant_type(Type *t) {
|
||||
t = core_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_ConstantType) != 0;
|
||||
}
|
||||
@@ -1346,6 +1355,7 @@ gb_internal bool is_type_constant_type(Type *t) {
|
||||
}
|
||||
gb_internal bool is_type_float(Type *t) {
|
||||
t = core_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_Float) != 0;
|
||||
}
|
||||
@@ -1353,6 +1363,7 @@ gb_internal bool is_type_float(Type *t) {
|
||||
}
|
||||
gb_internal bool is_type_complex(Type *t) {
|
||||
t = core_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_Complex) != 0;
|
||||
}
|
||||
@@ -1360,6 +1371,7 @@ gb_internal bool is_type_complex(Type *t) {
|
||||
}
|
||||
gb_internal bool is_type_quaternion(Type *t) {
|
||||
t = core_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_Quaternion) != 0;
|
||||
}
|
||||
@@ -1367,6 +1379,7 @@ gb_internal bool is_type_quaternion(Type *t) {
|
||||
}
|
||||
gb_internal bool is_type_complex_or_quaternion(Type *t) {
|
||||
t = core_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & (BasicFlag_Complex|BasicFlag_Quaternion)) != 0;
|
||||
}
|
||||
@@ -1374,6 +1387,7 @@ gb_internal bool is_type_complex_or_quaternion(Type *t) {
|
||||
}
|
||||
gb_internal bool is_type_pointer(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_Pointer) != 0;
|
||||
}
|
||||
@@ -1381,10 +1395,12 @@ gb_internal bool is_type_pointer(Type *t) {
|
||||
}
|
||||
gb_internal bool is_type_soa_pointer(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
return t->kind == Type_SoaPointer;
|
||||
}
|
||||
gb_internal bool is_type_multi_pointer(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
return t->kind == Type_MultiPointer;
|
||||
}
|
||||
gb_internal bool is_type_internally_pointer_like(Type *t) {
|
||||
@@ -1393,6 +1409,7 @@ gb_internal bool is_type_internally_pointer_like(Type *t) {
|
||||
|
||||
gb_internal bool is_type_tuple(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
return t->kind == Type_Tuple;
|
||||
}
|
||||
gb_internal bool is_type_uintptr(Type *t) {
|
||||
@@ -1415,14 +1432,17 @@ gb_internal bool is_type_u8(Type *t) {
|
||||
}
|
||||
gb_internal bool is_type_array(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
return t->kind == Type_Array;
|
||||
}
|
||||
gb_internal bool is_type_enumerated_array(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
return t->kind == Type_EnumeratedArray;
|
||||
}
|
||||
gb_internal bool is_type_matrix(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
return t->kind == Type_Matrix;
|
||||
}
|
||||
|
||||
@@ -1566,22 +1586,27 @@ gb_internal bool is_type_valid_for_matrix_elems(Type *t) {
|
||||
|
||||
gb_internal bool is_type_dynamic_array(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
return t->kind == Type_DynamicArray;
|
||||
}
|
||||
gb_internal bool is_type_slice(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
return t->kind == Type_Slice;
|
||||
}
|
||||
gb_internal bool is_type_proc(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
return t->kind == Type_Proc;
|
||||
}
|
||||
gb_internal bool is_type_asm_proc(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
return t->kind == Type_Proc && t->Proc.calling_convention == ProcCC_InlineAsm;
|
||||
}
|
||||
gb_internal bool is_type_simd_vector(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
return t->kind == Type_SimdVector;
|
||||
}
|
||||
|
||||
@@ -1621,11 +1646,13 @@ gb_internal Type *base_any_array_type(Type *t) {
|
||||
|
||||
gb_internal bool is_type_generic(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
return t->kind == Type_Generic;
|
||||
}
|
||||
|
||||
gb_internal bool is_type_u8_slice(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Slice) {
|
||||
return is_type_u8(t->Slice.elem);
|
||||
}
|
||||
@@ -1633,6 +1660,7 @@ gb_internal bool is_type_u8_slice(Type *t) {
|
||||
}
|
||||
gb_internal bool is_type_u8_array(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Array) {
|
||||
return is_type_u8(t->Array.elem);
|
||||
}
|
||||
@@ -1640,6 +1668,7 @@ gb_internal bool is_type_u8_array(Type *t) {
|
||||
}
|
||||
gb_internal bool is_type_u8_ptr(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Pointer) {
|
||||
return is_type_u8(t->Slice.elem);
|
||||
}
|
||||
@@ -1647,6 +1676,7 @@ gb_internal bool is_type_u8_ptr(Type *t) {
|
||||
}
|
||||
gb_internal bool is_type_u8_multi_ptr(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_MultiPointer) {
|
||||
return is_type_u8(t->Slice.elem);
|
||||
}
|
||||
@@ -1654,6 +1684,7 @@ gb_internal bool is_type_u8_multi_ptr(Type *t) {
|
||||
}
|
||||
gb_internal bool is_type_rune_array(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Array) {
|
||||
return is_type_rune(t->Array.elem);
|
||||
}
|
||||
@@ -1979,7 +2010,13 @@ gb_internal bool is_type_untyped_uninit(Type *t) {
|
||||
}
|
||||
|
||||
gb_internal bool is_type_empty_union(Type *t) {
|
||||
if (t == nullptr) {
|
||||
return false;
|
||||
}
|
||||
t = base_type(t);
|
||||
if (t == nullptr) {
|
||||
return false;
|
||||
}
|
||||
return t->kind == Type_Union && t->Union.variants.count == 0;
|
||||
}
|
||||
|
||||
@@ -2668,7 +2705,7 @@ gb_internal bool are_types_identical(Type *x, Type *y) {
|
||||
y = y->Named.base;
|
||||
}
|
||||
}
|
||||
if (x->kind != y->kind) {
|
||||
if (x == nullptr || y == nullptr || x->kind != y->kind) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -3059,11 +3096,15 @@ gb_internal i64 union_tag_size(Type *u) {
|
||||
compiler_error("how many variants do you have?! %lld", cast(long long)u->Union.variants.count);
|
||||
}
|
||||
|
||||
for_array(i, u->Union.variants) {
|
||||
Type *variant_type = u->Union.variants[i];
|
||||
i64 align = type_align_of(variant_type);
|
||||
if (max_align < align) {
|
||||
max_align = align;
|
||||
if (u->Union.custom_align > 0) {
|
||||
max_align = gb_max(max_align, u->Union.custom_align);
|
||||
} else {
|
||||
for_array(i, u->Union.variants) {
|
||||
Type *variant_type = u->Union.variants[i];
|
||||
i64 align = type_align_of(variant_type);
|
||||
if (max_align < align) {
|
||||
max_align = align;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4580,6 +4621,83 @@ gb_internal Type *alloc_type_proc_from_types(Type **param_types, unsigned param_
|
||||
// return type;
|
||||
// }
|
||||
|
||||
// Index a type that is internally a struct or array.
|
||||
gb_internal Type *type_internal_index(Type *t, isize index) {
|
||||
Type *bt = base_type(t);
|
||||
if (bt == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
switch (bt->kind) {
|
||||
case Type_Basic:
|
||||
{
|
||||
switch (bt->Basic.kind) {
|
||||
case Basic_complex32: return t_f16;
|
||||
case Basic_complex64: return t_f32;
|
||||
case Basic_complex128: return t_f64;
|
||||
case Basic_quaternion64: return t_f16;
|
||||
case Basic_quaternion128: return t_f32;
|
||||
case Basic_quaternion256: return t_f64;
|
||||
case Basic_string:
|
||||
{
|
||||
GB_ASSERT(index == 0 || index == 1);
|
||||
return index == 0 ? t_u8_ptr : t_int;
|
||||
}
|
||||
case Basic_any:
|
||||
{
|
||||
GB_ASSERT(index == 0 || index == 1);
|
||||
return index == 0 ? t_rawptr : t_typeid;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_Array: return bt->Array.elem;
|
||||
case Type_EnumeratedArray: return bt->EnumeratedArray.elem;
|
||||
case Type_SimdVector: return bt->SimdVector.elem;
|
||||
case Type_Slice:
|
||||
{
|
||||
GB_ASSERT(index == 0 || index == 1);
|
||||
return index == 0 ? t_rawptr : t_typeid;
|
||||
}
|
||||
case Type_DynamicArray:
|
||||
{
|
||||
switch (index) {
|
||||
case 0: return t_rawptr;
|
||||
case 1: return t_int;
|
||||
case 2: return t_int;
|
||||
case 3: return t_allocator;
|
||||
default: GB_PANIC("invalid raw dynamic array index");
|
||||
};
|
||||
}
|
||||
case Type_Struct:
|
||||
return get_struct_field_type(bt, index);
|
||||
case Type_Union:
|
||||
if (index < bt->Union.variants.count) {
|
||||
return bt->Union.variants[index];
|
||||
}
|
||||
return union_tag_type(bt);
|
||||
case Type_Tuple:
|
||||
return bt->Tuple.variables[index]->type;
|
||||
case Type_Matrix:
|
||||
return bt->Matrix.elem;
|
||||
case Type_SoaPointer:
|
||||
{
|
||||
GB_ASSERT(index == 0 || index == 1);
|
||||
return index == 0 ? t_rawptr : t_int;
|
||||
}
|
||||
case Type_Map:
|
||||
return type_internal_index(bt->Map.debug_metadata_type, index);
|
||||
case Type_BitField:
|
||||
return type_internal_index(bt->BitField.backing_type, index);
|
||||
case Type_Generic:
|
||||
return type_internal_index(bt->Generic.specialized, index);
|
||||
};
|
||||
|
||||
GB_PANIC("Unhandled type %s", type_to_string(bt));
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
gb_internal gbString write_type_to_string(gbString str, Type *type, bool shorthand=false, bool allow_polymorphic=false) {
|
||||
if (type == nullptr) {
|
||||
return gb_string_appendc(str, "<no type>");
|
||||
|
||||
Reference in New Issue
Block a user