mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-31 03:40:08 +00:00
Merge branch 'master' into tilde
This commit is contained in:
+39
-3
@@ -216,6 +216,43 @@ enum BuildPath : u8 {
|
||||
BuildPathCOUNT,
|
||||
};
|
||||
|
||||
enum VetFlags : u64 {
|
||||
VetFlag_NONE = 0,
|
||||
VetFlag_Unused = 1u<<0, // 1
|
||||
VetFlag_Shadowing = 1u<<1, // 2
|
||||
VetFlag_UsingStmt = 1u<<2, // 4
|
||||
VetFlag_UsingParam = 1u<<3, // 8
|
||||
VetFlag_Style = 1u<<4, // 16
|
||||
VetFlag_Semicolon = 1u<<5, // 32
|
||||
|
||||
VetFlag_Extra = 1u<<16,
|
||||
|
||||
VetFlag_All = VetFlag_Unused|VetFlag_Shadowing|VetFlag_UsingStmt, // excluding extra
|
||||
|
||||
VetFlag_Using = VetFlag_UsingStmt|VetFlag_UsingParam,
|
||||
};
|
||||
|
||||
u64 get_vet_flag_from_name(String const &name) {
|
||||
if (name == "unused") {
|
||||
return VetFlag_Unused;
|
||||
} else if (name == "shadowing") {
|
||||
return VetFlag_Shadowing;
|
||||
} else if (name == "using-stmt") {
|
||||
return VetFlag_UsingStmt;
|
||||
} else if (name == "using-param") {
|
||||
return VetFlag_UsingParam;
|
||||
} else if (name == "style") {
|
||||
return VetFlag_Style;
|
||||
} else if (name == "semicolon") {
|
||||
return VetFlag_Semicolon;
|
||||
} else if (name == "extra") {
|
||||
return VetFlag_Extra;
|
||||
}
|
||||
return VetFlag_NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// This stores the information for the specify architecture of this build
|
||||
struct BuildContext {
|
||||
// Constants
|
||||
@@ -255,6 +292,8 @@ struct BuildContext {
|
||||
String resource_filepath;
|
||||
String pdb_filepath;
|
||||
|
||||
u64 vet_flags;
|
||||
|
||||
bool has_resource;
|
||||
String link_flags;
|
||||
String extra_linker_flags;
|
||||
@@ -280,15 +319,12 @@ struct BuildContext {
|
||||
bool no_entry_point;
|
||||
bool no_thread_local;
|
||||
bool use_lld;
|
||||
bool vet;
|
||||
bool vet_extra;
|
||||
bool cross_compiling;
|
||||
bool different_os;
|
||||
bool keep_object_files;
|
||||
bool disallow_do;
|
||||
|
||||
bool strict_style;
|
||||
bool strict_style_init_only;
|
||||
|
||||
bool ignore_warnings;
|
||||
bool warnings_as_errors;
|
||||
|
||||
@@ -1406,7 +1406,7 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o
|
||||
}
|
||||
return false;
|
||||
} else if (name == "load_or") {
|
||||
warning(call, "'#load_or' is deprecated in favour of '#load(path) or_else default'");
|
||||
error(call, "'#load_or' has now been removed in favour of '#load(path) or_else default'");
|
||||
|
||||
if (ce->args.count != 2) {
|
||||
if (ce->args.count == 0) {
|
||||
|
||||
+10
-33
@@ -7,13 +7,15 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o
|
||||
e->type == t_invalid) {
|
||||
|
||||
if (operand->mode == Addressing_Builtin) {
|
||||
ERROR_BLOCK();
|
||||
gbString expr_str = expr_to_string(operand->expr);
|
||||
|
||||
// TODO(bill): is this a good enough error message?
|
||||
error(operand->expr,
|
||||
"Cannot assign built-in procedure '%s' in %.*s",
|
||||
expr_str,
|
||||
LIT(context_name));
|
||||
"Cannot assign built-in procedure '%s' in %.*s",
|
||||
expr_str,
|
||||
LIT(context_name));
|
||||
|
||||
error_line("\tBuilt-in procedures are implemented by the compiler and might not be actually instantiated procedure\n");
|
||||
|
||||
operand->mode = Addressing_Invalid;
|
||||
|
||||
@@ -159,9 +161,8 @@ gb_internal void check_init_constant(CheckerContext *ctx, Entity *e, Operand *op
|
||||
}
|
||||
|
||||
if (operand->mode != Addressing_Constant) {
|
||||
// TODO(bill): better error
|
||||
gbString str = expr_to_string(operand->expr);
|
||||
error(operand->expr, "'%s' is not a constant", str);
|
||||
error(operand->expr, "'%s' is not a compile-time known constant", str);
|
||||
gb_string_free(str);
|
||||
if (e->type == nullptr) {
|
||||
e->type = t_invalid;
|
||||
@@ -354,31 +355,7 @@ gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr,
|
||||
|
||||
// using decl
|
||||
if (decl->is_using) {
|
||||
warning(init_expr, "'using' an enum declaration is not allowed, prefer using implicit selector expressions e.g. '.A'");
|
||||
#if 1
|
||||
// NOTE(bill): Must be an enum declaration
|
||||
if (te->kind == Ast_EnumType) {
|
||||
Scope *parent = e->scope;
|
||||
if (parent->flags&ScopeFlag_File) {
|
||||
// NOTE(bill): Use package scope
|
||||
parent = parent->parent;
|
||||
}
|
||||
|
||||
Type *t = base_type(e->type);
|
||||
if (t->kind == Type_Enum) {
|
||||
for (Entity *f : t->Enum.fields) {
|
||||
if (f->kind != Entity_Constant) {
|
||||
continue;
|
||||
}
|
||||
String name = f->token.string;
|
||||
if (is_blank_ident(name)) {
|
||||
continue;
|
||||
}
|
||||
add_entity(ctx, parent, nullptr, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
error(init_expr, "'using' an enum declaration is not allowed, prefer using implicit selector expressions e.g. '.A'");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1064,7 +1041,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
||||
auto *fp = &ctx->info->foreigns;
|
||||
StringHashKey key = string_hash_string(name);
|
||||
Entity **found = string_map_get(fp, key);
|
||||
if (found) {
|
||||
if (found && e != *found) {
|
||||
Entity *f = *found;
|
||||
TokenPos pos = f->token.pos;
|
||||
Type *this_type = base_type(e->type);
|
||||
@@ -1636,7 +1613,7 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de
|
||||
}
|
||||
check_close_scope(ctx);
|
||||
|
||||
check_scope_usage(ctx->checker, ctx->scope);
|
||||
check_scope_usage(ctx->checker, ctx->scope, check_vet_flags(body));
|
||||
|
||||
add_deps_from_child_to_parent(decl);
|
||||
|
||||
|
||||
+14
-34
@@ -349,6 +349,10 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E
|
||||
return false;
|
||||
}
|
||||
|
||||
if (base_entity->flags & EntityFlag_Disabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String name = base_entity->token.string;
|
||||
|
||||
Type *src = base_type(base_entity->type);
|
||||
@@ -462,7 +466,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E
|
||||
|
||||
|
||||
{
|
||||
// LEAK TODO(bill): This is technically a memory leak as it has to generate the type twice
|
||||
// LEAK NOTE(bill): This is technically a memory leak as it has to generate the type twice
|
||||
bool prev_no_polymorphic_errors = nctx.no_polymorphic_errors;
|
||||
defer (nctx.no_polymorphic_errors = prev_no_polymorphic_errors);
|
||||
nctx.no_polymorphic_errors = false;
|
||||
@@ -470,7 +474,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E
|
||||
// NOTE(bill): Reset scope from the failed procedure type
|
||||
scope_reset(scope);
|
||||
|
||||
// LEAK TODO(bill): Cloning this AST may be leaky
|
||||
// LEAK NOTE(bill): Cloning this AST may be leaky but this is not really an issue due to arena-based allocation
|
||||
Ast *cloned_proc_type_node = clone_ast(pt->node);
|
||||
success = check_procedure_type(&nctx, final_proc_type, cloned_proc_type_node, &operands);
|
||||
if (!success) {
|
||||
@@ -778,16 +782,6 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
|
||||
}
|
||||
}
|
||||
|
||||
// ^T <- rawptr
|
||||
#if 0
|
||||
// TODO(bill): Should C-style (not C++) pointer cast be allowed?
|
||||
if (is_type_pointer(dst) && is_type_rawptr(src)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#if 1
|
||||
|
||||
|
||||
// rawptr <- ^T
|
||||
if (are_types_identical(type, t_rawptr) && is_type_pointer(src)) {
|
||||
return 5;
|
||||
@@ -808,7 +802,6 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (is_type_polymorphic(dst) && !is_type_polymorphic(src)) {
|
||||
bool modify_type = !c->no_polymorphic_errors;
|
||||
@@ -824,7 +817,6 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(bill): Determine which rule is a better on in practice
|
||||
if (dst->Union.variants.count == 1) {
|
||||
Type *vt = dst->Union.variants[0];
|
||||
i64 score = check_distance_between_types(c, operand, vt);
|
||||
@@ -1093,7 +1085,7 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ
|
||||
|
||||
// TODO(bill): is this a good enough error message?
|
||||
error(operand->expr,
|
||||
"Cannot assign overloaded procedure '%s' to '%s' in %.*s",
|
||||
"Cannot assign overloaded procedure group '%s' to '%s' in %.*s",
|
||||
expr_str,
|
||||
op_type_str,
|
||||
LIT(context_name));
|
||||
@@ -1120,7 +1112,6 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ
|
||||
|
||||
switch (operand->mode) {
|
||||
case Addressing_Builtin:
|
||||
// TODO(bill): Actually allow built in procedures to be passed around and thus be created on use
|
||||
error(operand->expr,
|
||||
"Cannot assign built-in procedure '%s' in %.*s",
|
||||
expr_str,
|
||||
@@ -1412,9 +1403,6 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T
|
||||
return false;
|
||||
case Type_Proc:
|
||||
if (source->kind == Type_Proc) {
|
||||
// return check_is_assignable_to(c, &o, poly);
|
||||
// TODO(bill): Polymorphic type assignment
|
||||
#if 1
|
||||
TypeProc *x = &poly->Proc;
|
||||
TypeProc *y = &source->Proc;
|
||||
if (x->calling_convention != y->calling_convention) {
|
||||
@@ -1447,7 +1435,6 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T
|
||||
}
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
return false;
|
||||
case Type_Map:
|
||||
@@ -1699,7 +1686,6 @@ gb_internal bool check_unary_op(CheckerContext *c, Operand *o, Token op) {
|
||||
gb_string_free(str);
|
||||
return false;
|
||||
}
|
||||
// TODO(bill): Handle errors correctly
|
||||
Type *type = base_type(core_array_type(o->type));
|
||||
gbString str = nullptr;
|
||||
switch (op.kind) {
|
||||
@@ -1743,7 +1729,6 @@ gb_internal bool check_unary_op(CheckerContext *c, Operand *o, Token op) {
|
||||
gb_internal bool check_binary_op(CheckerContext *c, Operand *o, Token op) {
|
||||
Type *main_type = o->type;
|
||||
|
||||
// TODO(bill): Handle errors correctly
|
||||
Type *type = base_type(core_array_type(main_type));
|
||||
Type *ct = core_type(type);
|
||||
|
||||
@@ -2261,7 +2246,7 @@ gb_internal bool check_is_not_addressable(CheckerContext *c, Operand *o) {
|
||||
}
|
||||
|
||||
gb_internal void check_old_for_or_switch_value_usage(Ast *expr) {
|
||||
if (!build_context.strict_style) {
|
||||
if (!(build_context.strict_style || (check_vet_flags(expr) & VetFlag_Style))) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2351,7 +2336,7 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *
|
||||
o->type = alloc_type_pointer(o->type);
|
||||
}
|
||||
} else {
|
||||
if (build_context.strict_style && ast_node_expect(node, Ast_UnaryExpr)) {
|
||||
if (ast_node_expect(node, Ast_UnaryExpr)) {
|
||||
ast_node(ue, UnaryExpr, node);
|
||||
check_old_for_or_switch_value_usage(ue->expr);
|
||||
}
|
||||
@@ -2775,8 +2760,6 @@ gb_internal void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *nod
|
||||
gb_string_free(err_str);
|
||||
}
|
||||
|
||||
// TODO(bill): Should we support shifts for fixed arrays and #simd vectors?
|
||||
|
||||
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);
|
||||
@@ -3099,7 +3082,7 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) {
|
||||
update_untyped_expr_type(c, x->expr, final_type, true);
|
||||
}
|
||||
|
||||
if (build_context.vet_extra) {
|
||||
if (check_vet_flags(x->expr) & VetFlag_Extra) {
|
||||
if (are_types_identical(x->type, type)) {
|
||||
gbString str = type_to_string(type);
|
||||
warning(x->expr, "Unneeded cast to the same type '%s'", str);
|
||||
@@ -3171,7 +3154,7 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type
|
||||
return false;
|
||||
}
|
||||
|
||||
if (build_context.vet_extra) {
|
||||
if (check_vet_flags(node) & VetFlag_Extra) {
|
||||
if (are_types_identical(o->type, dst_t)) {
|
||||
gbString str = type_to_string(dst_t);
|
||||
warning(o->expr, "Unneeded transmute to the same type '%s'", str);
|
||||
@@ -4437,7 +4420,6 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v
|
||||
case_end;
|
||||
|
||||
default:
|
||||
// TODO(bill): Should this be a general fallback?
|
||||
if (success_) *success_ = true;
|
||||
if (finish_) *finish_ = true;
|
||||
return empty_exact_value;
|
||||
@@ -4793,8 +4775,6 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
|
||||
}
|
||||
|
||||
if (entity == nullptr && selector->kind == Ast_Ident && is_type_array(type_deref(operand->type))) {
|
||||
// TODO(bill): Simd_Vector swizzling
|
||||
|
||||
String field_name = selector->Ident.token.string;
|
||||
if (1 < field_name.len && field_name.len <= 4) {
|
||||
u8 swizzles_xyzw[4] = {'x', 'y', 'z', 'w'};
|
||||
@@ -5989,8 +5969,8 @@ gb_internal bool check_call_arguments_single(CheckerContext *c, Ast *call, Opera
|
||||
}
|
||||
|
||||
Entity *entity_to_use = data->gen_entity != nullptr ? data->gen_entity : e;
|
||||
add_entity_use(c, ident, entity_to_use);
|
||||
if (!return_on_failure && entity_to_use != nullptr) {
|
||||
add_entity_use(c, ident, entity_to_use);
|
||||
update_untyped_expr_type(c, operand->expr, entity_to_use->type, true);
|
||||
add_type_and_value(c, operand->expr, operand->mode, entity_to_use->type, operand->value);
|
||||
}
|
||||
@@ -7157,7 +7137,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
|
||||
i32 id = operand->builtin_id;
|
||||
Entity *e = entity_of_node(operand->expr);
|
||||
if (e != nullptr && e->token.string == "expand_to_tuple") {
|
||||
warning(operand->expr, "'expand_to_tuple' has been replaced with 'expand_values'");
|
||||
error(operand->expr, "'expand_to_tuple' has been replaced with 'expand_values'");
|
||||
}
|
||||
if (!check_builtin_procedure(c, operand, call, id, type_hint)) {
|
||||
operand->mode = Addressing_Invalid;
|
||||
@@ -10033,7 +10013,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
|
||||
Type *type = type_of_expr(ac->expr);
|
||||
check_cast(c, o, type_hint);
|
||||
if (is_type_typed(type) && are_types_identical(type, type_hint)) {
|
||||
if (build_context.vet_extra) {
|
||||
if (check_vet_flags(node) & VetFlag_Extra) {
|
||||
error(node, "Redundant 'auto_cast' applied to expression");
|
||||
}
|
||||
}
|
||||
|
||||
+11
-6
@@ -384,7 +384,6 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O
|
||||
}
|
||||
|
||||
if (e != nullptr) {
|
||||
// HACK TODO(bill): Should the entities be freed as it's technically a leak
|
||||
rhs->mode = Addressing_Value;
|
||||
rhs->type = e->type;
|
||||
rhs->proc_group = nullptr;
|
||||
@@ -394,7 +393,7 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O
|
||||
ast_node(i, Ident, node);
|
||||
e = scope_lookup(ctx->scope, i->token.string);
|
||||
if (e != nullptr && e->kind == Entity_Variable) {
|
||||
used = (e->flags & EntityFlag_Used) != 0; // TODO(bill): Make backup just in case
|
||||
used = (e->flags & EntityFlag_Used) != 0; // NOTE(bill): Make backup just in case
|
||||
}
|
||||
}
|
||||
|
||||
@@ -888,7 +887,7 @@ gb_internal void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags
|
||||
check_open_scope(ctx, node);
|
||||
defer (check_close_scope(ctx));
|
||||
|
||||
check_label(ctx, ss->label, node); // TODO(bill): What should the label's "scope" be?
|
||||
check_label(ctx, ss->label, node);
|
||||
|
||||
if (ss->init != nullptr) {
|
||||
check_stmt(ctx, ss->init, 0);
|
||||
@@ -1125,7 +1124,7 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_
|
||||
check_open_scope(ctx, node);
|
||||
defer (check_close_scope(ctx));
|
||||
|
||||
check_label(ctx, ss->label, node); // TODO(bill): What should the label's "scope" be?
|
||||
check_label(ctx, ss->label, node);
|
||||
|
||||
if (ss->tag->kind != Ast_AssignStmt) {
|
||||
error(ss->tag, "Expected an 'in' assignment for this type switch statement");
|
||||
@@ -1960,7 +1959,7 @@ gb_internal void check_value_decl_stmt(CheckerContext *ctx, Ast *node, u32 mod_f
|
||||
Token token = ast_token(node);
|
||||
if (vd->type != nullptr && entity_count > 1) {
|
||||
error(token, "'using' can only be applied to one variable of the same type");
|
||||
// TODO(bill): Should a 'continue' happen here?
|
||||
// NOTE(bill): `using` will only be applied to a single declaration
|
||||
}
|
||||
|
||||
for (isize entity_index = 0; entity_index < 1; entity_index++) {
|
||||
@@ -2294,7 +2293,7 @@ gb_internal void check_for_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
||||
mod_flags |= Stmt_BreakAllowed | Stmt_ContinueAllowed;
|
||||
|
||||
check_open_scope(ctx, node);
|
||||
check_label(ctx, fs->label, node); // TODO(bill): What should the label's "scope" be?
|
||||
check_label(ctx, fs->label, node);
|
||||
|
||||
if (fs->init != nullptr) {
|
||||
check_stmt(ctx, fs->init, 0);
|
||||
@@ -2464,6 +2463,12 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags)
|
||||
error(us->token, "Empty 'using' list");
|
||||
return;
|
||||
}
|
||||
if (check_vet_flags(node) & VetFlag_UsingStmt) {
|
||||
ERROR_BLOCK();
|
||||
error(node, "'using' as a statement is not allowed when '-vet' or '-vet-using' is applied");
|
||||
error_line("\t'using' is considered bad practice to use as a statement outside of immediate refactoring\n");
|
||||
}
|
||||
|
||||
for (Ast *expr : us->list) {
|
||||
expr = unparen_expr(expr);
|
||||
Entity *e = nullptr;
|
||||
|
||||
@@ -1474,6 +1474,12 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
|
||||
Type *specialization = nullptr;
|
||||
|
||||
bool is_using = (p->flags&FieldFlag_using) != 0;
|
||||
if ((check_vet_flags(param) & VetFlag_UsingParam) && is_using) {
|
||||
ERROR_BLOCK();
|
||||
error(param, "'using' on a procedure parameter is now allowed when '-vet' or '-vet-using-param' is applied");
|
||||
error_line("\t'using' is considered bad practice to use as a statement/procedure parameter outside of immediate refactoring\n");
|
||||
|
||||
}
|
||||
|
||||
if (type_expr == nullptr) {
|
||||
param_value = handle_parameter_value(ctx, nullptr, &type, default_value, true);
|
||||
|
||||
+63
-36
@@ -521,6 +521,28 @@ GB_COMPARE_PROC(entity_variable_pos_cmp) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
gb_internal u64 check_vet_flags(CheckerContext *c) {
|
||||
AstFile *file = c->file;
|
||||
if (file == nullptr &&
|
||||
c->curr_proc_decl &&
|
||||
c->curr_proc_decl->proc_lit) {
|
||||
file = c->curr_proc_decl->proc_lit->file();
|
||||
}
|
||||
if (file && file->vet_flags_set) {
|
||||
return file->vet_flags;
|
||||
}
|
||||
return build_context.vet_flags;
|
||||
}
|
||||
|
||||
gb_internal u64 check_vet_flags(Ast *node) {
|
||||
AstFile *file = node->file();
|
||||
if (file && file->vet_flags_set) {
|
||||
return file->vet_flags;
|
||||
}
|
||||
return build_context.vet_flags;
|
||||
}
|
||||
|
||||
enum VettedEntityKind {
|
||||
VettedEntity_Invalid,
|
||||
|
||||
@@ -655,9 +677,9 @@ gb_internal bool check_vet_unused(Checker *c, Entity *e, VettedEntity *ve) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gb_internal void check_scope_usage(Checker *c, Scope *scope) {
|
||||
bool vet_unused = true;
|
||||
bool vet_shadowing = true;
|
||||
gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) {
|
||||
bool vet_unused = (vet_flags & VetFlag_Unused) != 0;
|
||||
bool vet_shadowing = (vet_flags & (VetFlag_Shadowing|VetFlag_Using)) != 0;
|
||||
|
||||
Array<VettedEntity> vetted_entities = {};
|
||||
array_init(&vetted_entities, heap_allocator());
|
||||
@@ -691,15 +713,17 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope) {
|
||||
|
||||
if (ve.kind == VettedEntity_Shadowed_And_Unused) {
|
||||
error(e->token, "'%.*s' declared but not used, possibly shadows declaration at line %d", LIT(name), other->token.pos.line);
|
||||
} else if (build_context.vet) {
|
||||
} else if (vet_flags) {
|
||||
switch (ve.kind) {
|
||||
case VettedEntity_Unused:
|
||||
error(e->token, "'%.*s' declared but not used", LIT(name));
|
||||
if (vet_flags & VetFlag_Unused) {
|
||||
error(e->token, "'%.*s' declared but not used", LIT(name));
|
||||
}
|
||||
break;
|
||||
case VettedEntity_Shadowed:
|
||||
if (e->flags&EntityFlag_Using) {
|
||||
if ((vet_flags & (VetFlag_Shadowing|VetFlag_Using)) != 0 && e->flags&EntityFlag_Using) {
|
||||
error(e->token, "Declaration of '%.*s' from 'using' shadows declaration at line %d", LIT(name), other->token.pos.line);
|
||||
} else {
|
||||
} else if ((vet_flags & (VetFlag_Shadowing)) != 0) {
|
||||
error(e->token, "Declaration of '%.*s' shadows declaration at line %d", LIT(name), other->token.pos.line);
|
||||
}
|
||||
break;
|
||||
@@ -726,7 +750,7 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope) {
|
||||
if (child->flags & (ScopeFlag_Proc|ScopeFlag_Type|ScopeFlag_File)) {
|
||||
// Ignore these
|
||||
} else {
|
||||
check_scope_usage(c, child);
|
||||
check_scope_usage(c, child, vet_flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -943,7 +967,6 @@ gb_internal void init_universal(void) {
|
||||
add_global_bool_constant("true", true);
|
||||
add_global_bool_constant("false", false);
|
||||
|
||||
// TODO(bill): Set through flags in the compiler
|
||||
add_global_string_constant("ODIN_VENDOR", bc->ODIN_VENDOR);
|
||||
add_global_string_constant("ODIN_VERSION", bc->ODIN_VERSION);
|
||||
add_global_string_constant("ODIN_ROOT", bc->ODIN_ROOT);
|
||||
@@ -1455,7 +1478,6 @@ gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMo
|
||||
if (ctx->decl) {
|
||||
mutex = &ctx->decl->type_and_value_mutex;
|
||||
} else if (ctx->pkg) {
|
||||
// TODO(bill): is a per package mutex is a good idea here?
|
||||
mutex = &ctx->pkg->type_and_value_mutex;
|
||||
}
|
||||
|
||||
@@ -1583,30 +1605,28 @@ gb_internal void add_entity_use(CheckerContext *c, Ast *identifier, Entity *enti
|
||||
if (entity == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (identifier != nullptr) {
|
||||
if (identifier->kind != Ast_Ident) {
|
||||
return;
|
||||
}
|
||||
Ast *empty_ident = nullptr;
|
||||
entity->identifier.compare_exchange_strong(empty_ident, identifier);
|
||||
|
||||
identifier->Ident.entity = entity;
|
||||
|
||||
String dmsg = entity->deprecated_message;
|
||||
if (dmsg.len > 0) {
|
||||
warning(identifier, "%.*s is deprecated: %.*s", LIT(entity->token.string), LIT(dmsg));
|
||||
}
|
||||
String wmsg = entity->warning_message;
|
||||
if (wmsg.len > 0) {
|
||||
warning(identifier, "%.*s: %.*s", LIT(entity->token.string), LIT(wmsg));
|
||||
}
|
||||
}
|
||||
entity->flags |= EntityFlag_Used;
|
||||
add_declaration_dependency(c, entity);
|
||||
entity->flags |= EntityFlag_Used;
|
||||
if (entity_has_deferred_procedure(entity)) {
|
||||
Entity *deferred = entity->Procedure.deferred_procedure.entity;
|
||||
add_entity_use(c, nullptr, deferred);
|
||||
}
|
||||
if (identifier == nullptr || identifier->kind != Ast_Ident) {
|
||||
return;
|
||||
}
|
||||
Ast *empty_ident = nullptr;
|
||||
entity->identifier.compare_exchange_strong(empty_ident, identifier);
|
||||
|
||||
identifier->Ident.entity = entity;
|
||||
|
||||
String dmsg = entity->deprecated_message;
|
||||
if (dmsg.len > 0) {
|
||||
warning(identifier, "%.*s is deprecated: %.*s", LIT(entity->token.string), LIT(dmsg));
|
||||
}
|
||||
String wmsg = entity->warning_message;
|
||||
if (wmsg.len > 0) {
|
||||
warning(identifier, "%.*s: %.*s", LIT(entity->token.string), LIT(wmsg));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2560,9 +2580,6 @@ gb_internal Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInf
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(bill): This could be multithreaded to improve performance
|
||||
// This means that the entity graph node set will have to be thread safe
|
||||
|
||||
TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 2");
|
||||
auto G = array_make<EntityGraphNode *>(allocator, 0, M.count);
|
||||
|
||||
@@ -2982,6 +2999,12 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_group_attribute) {
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if (name == "require_results") {
|
||||
if (value != nullptr) {
|
||||
error(elem, "Expected no value for '%.*s'", LIT(name));
|
||||
}
|
||||
ac->require_results = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -3059,7 +3082,7 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
|
||||
check_expr(c, &o, value);
|
||||
Entity *e = entity_of_node(o.expr);
|
||||
if (e != nullptr && e->kind == Entity_Procedure) {
|
||||
warning(elem, "'%.*s' is deprecated, please use one of the following instead: 'deferred_none', 'deferred_in', 'deferred_out'", LIT(name));
|
||||
error(elem, "'%.*s' is not allowed any more, please use one of the following instead: 'deferred_none', 'deferred_in', 'deferred_out'", LIT(name));
|
||||
if (ac->deferred_procedure.entity != nullptr) {
|
||||
error(elem, "Previous usage of a 'deferred_*' attribute");
|
||||
}
|
||||
@@ -4558,7 +4581,7 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) {
|
||||
if (value != nullptr) {
|
||||
error(elem, "Expected no parameter for '%.*s'", LIT(name));
|
||||
} else if (name == "force") {
|
||||
warning(elem, "'force' is deprecated and is identical to 'require'");
|
||||
error(elem, "'force' was replaced with 'require'");
|
||||
}
|
||||
ac->require_declaration = true;
|
||||
return true;
|
||||
@@ -5956,7 +5979,11 @@ gb_internal void check_parsed_files(Checker *c) {
|
||||
TIME_SECTION("check scope usage");
|
||||
for (auto const &entry : c->info.files) {
|
||||
AstFile *f = entry.value;
|
||||
check_scope_usage(c, f->scope);
|
||||
u64 vet_flags = build_context.vet_flags;
|
||||
if (f->vet_flags_set) {
|
||||
vet_flags = f->vet_flags;
|
||||
}
|
||||
check_scope_usage(c, f->scope, vet_flags);
|
||||
}
|
||||
|
||||
TIME_SECTION("add basic type information");
|
||||
@@ -6074,7 +6101,7 @@ gb_internal void check_parsed_files(Checker *c) {
|
||||
while (mpsc_dequeue(&c->info.intrinsics_entry_point_usage, &node)) {
|
||||
if (c->info.entry_point == nullptr && node != nullptr) {
|
||||
if (node->file()->pkg->kind != Package_Runtime) {
|
||||
warning(node, "usage of intrinsics.__entry_point will be a no-op");
|
||||
error(node, "usage of intrinsics.__entry_point will be a no-op");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -387,8 +387,6 @@ struct CheckerInfo {
|
||||
BlockingMutex foreign_mutex; // NOT recursive
|
||||
StringMap<Entity *> foreigns;
|
||||
|
||||
// NOTE(bill): These are actually MPSC queues
|
||||
// TODO(bill): Convert them to be MPSC queues
|
||||
MPSCQueue<Entity *> definition_queue;
|
||||
MPSCQueue<Entity *> entity_queue;
|
||||
MPSCQueue<Entity *> required_global_variable_queue;
|
||||
@@ -449,6 +447,9 @@ struct CheckerContext {
|
||||
Ast *assignment_lhs_hint;
|
||||
};
|
||||
|
||||
gb_internal u64 check_vet_flags(CheckerContext *c);
|
||||
gb_internal u64 check_vet_flags(Ast *node);
|
||||
|
||||
|
||||
struct Checker {
|
||||
Parser * parser;
|
||||
|
||||
+3
-4
@@ -291,7 +291,6 @@ gb_internal bool is_entity_kind_exported(EntityKind kind, bool allow_builtin = f
|
||||
}
|
||||
|
||||
gb_internal bool is_entity_exported(Entity *e, bool allow_builtin = false) {
|
||||
// TODO(bill): Determine the actual exportation rules for imports of entities
|
||||
GB_ASSERT(e != nullptr);
|
||||
if (!is_entity_kind_exported(e->kind, allow_builtin)) {
|
||||
return false;
|
||||
@@ -405,7 +404,7 @@ gb_internal Entity *alloc_entity_array_elem(Scope *scope, Token token, Type *typ
|
||||
return entity;
|
||||
}
|
||||
|
||||
gb_internal Entity *alloc_entity_procedure(Scope *scope, Token token, Type *signature_type, u64 tags) {
|
||||
gb_internal Entity *alloc_entity_procedure(Scope *scope, Token token, Type *signature_type, u64 tags=0) {
|
||||
Entity *entity = alloc_entity(Entity_Procedure, scope, token, signature_type);
|
||||
entity->Procedure.tags = tags;
|
||||
return entity;
|
||||
@@ -422,7 +421,7 @@ gb_internal Entity *alloc_entity_import_name(Scope *scope, Token token, Type *ty
|
||||
entity->ImportName.path = path;
|
||||
entity->ImportName.name = name;
|
||||
entity->ImportName.scope = import_scope;
|
||||
entity->state = EntityState_Resolved; // TODO(bill): Is this correct?
|
||||
entity->state = EntityState_Resolved;
|
||||
return entity;
|
||||
}
|
||||
|
||||
@@ -431,7 +430,7 @@ gb_internal Entity *alloc_entity_library_name(Scope *scope, Token token, Type *t
|
||||
Entity *entity = alloc_entity(Entity_LibraryName, scope, token, type);
|
||||
entity->LibraryName.paths = paths;
|
||||
entity->LibraryName.name = name;
|
||||
entity->state = EntityState_Resolved; // TODO(bill): Is this correct?
|
||||
entity->state = EntityState_Resolved;
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
||||
+2
-5
@@ -26,8 +26,8 @@ enum ExactValueKind {
|
||||
ExactValue_Complex = 5,
|
||||
ExactValue_Quaternion = 6,
|
||||
ExactValue_Pointer = 7,
|
||||
ExactValue_Compound = 8, // TODO(bill): Is this good enough?
|
||||
ExactValue_Procedure = 9, // TODO(bill): Is this good enough?
|
||||
ExactValue_Compound = 8,
|
||||
ExactValue_Procedure = 9,
|
||||
ExactValue_Typeid = 10,
|
||||
|
||||
ExactValue_Count,
|
||||
@@ -101,7 +101,6 @@ gb_internal ExactValue exact_value_bool(bool b) {
|
||||
}
|
||||
|
||||
gb_internal ExactValue exact_value_string(String string) {
|
||||
// TODO(bill): Allow for numbers with underscores in them
|
||||
ExactValue result = {ExactValue_String};
|
||||
result.value_string = string;
|
||||
return result;
|
||||
@@ -702,7 +701,6 @@ gb_internal void match_exact_values(ExactValue *x, ExactValue *y) {
|
||||
compiler_error("match_exact_values: How'd you get here? Invalid ExactValueKind %d", x->kind);
|
||||
}
|
||||
|
||||
// TODO(bill): Allow for pointer arithmetic? Or are pointer slices good enough?
|
||||
gb_internal ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y) {
|
||||
match_exact_values(&x, &y);
|
||||
|
||||
@@ -943,7 +941,6 @@ gb_internal bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y)
|
||||
case ExactValue_String: {
|
||||
String a = x.value_string;
|
||||
String b = y.value_string;
|
||||
// TODO(bill): gb_memcompare is used because the strings are UTF-8
|
||||
switch (op) {
|
||||
case Token_CmpEq: return a == b;
|
||||
case Token_NotEq: return a != b;
|
||||
|
||||
@@ -1861,8 +1861,8 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
|
||||
case Type_SimdVector:
|
||||
return lb_type_internal(m, base);
|
||||
|
||||
// TODO(bill): Deal with this correctly. Can this be named?
|
||||
case Type_Proc:
|
||||
// TODO(bill): Deal with this correctly. Can this be named?
|
||||
return lb_type_internal(m, base);
|
||||
|
||||
case Type_Tuple:
|
||||
@@ -2835,7 +2835,6 @@ gb_internal lbValue lb_find_value_from_entity(lbModule *m, Entity *e) {
|
||||
if (USE_SEPARATE_MODULES) {
|
||||
lbModule *other_module = lb_module_of_entity(m->gen, e);
|
||||
|
||||
// TODO(bill): correct this logic
|
||||
bool is_external = other_module != m;
|
||||
if (!is_external) {
|
||||
if (e->code_gen_module != nullptr) {
|
||||
|
||||
@@ -362,7 +362,6 @@ gb_internal lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name
|
||||
|
||||
Type *pt = p->type;
|
||||
lbCallingConventionKind cc_kind = lbCallingConvention_C;
|
||||
// TODO(bill): Clean up this logic
|
||||
if (!is_arch_wasm()) {
|
||||
cc_kind = lb_calling_convention_map[pt->Proc.calling_convention];
|
||||
}
|
||||
@@ -1702,7 +1701,6 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
|
||||
lbValue v = lb_build_expr(p, ce->args[0]);
|
||||
Type *t = base_type(v.type);
|
||||
if (is_type_pointer(t)) {
|
||||
// IMPORTANT TODO(bill): Should there be a nil pointer check?
|
||||
v = lb_emit_load(p, v);
|
||||
t = type_deref(t);
|
||||
}
|
||||
@@ -1730,7 +1728,6 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
|
||||
lbValue v = lb_build_expr(p, ce->args[0]);
|
||||
Type *t = base_type(v.type);
|
||||
if (is_type_pointer(t)) {
|
||||
// IMPORTANT TODO(bill): Should there be a nil pointer check?
|
||||
v = lb_emit_load(p, v);
|
||||
t = type_deref(t);
|
||||
}
|
||||
@@ -3144,7 +3141,7 @@ gb_internal lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) {
|
||||
|
||||
lbValue res = lb_build_call_expr_internal(p, expr);
|
||||
|
||||
if (ce->optional_ok_one) { // TODO(bill): Minor hack for #optional_ok procedures
|
||||
if (ce->optional_ok_one) {
|
||||
GB_ASSERT(is_type_tuple(res.type));
|
||||
GB_ASSERT(res.type->Tuple.variables.count == 2);
|
||||
return lb_emit_struct_ev(p, res, 0);
|
||||
|
||||
@@ -1688,7 +1688,6 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss
|
||||
lb_add_entity(p->module, case_entity, ptr);
|
||||
lb_add_debug_local_variable(p, ptr.value, case_entity->type, case_entity->token);
|
||||
} else {
|
||||
// TODO(bill): is the correct expected behaviour?
|
||||
lb_store_type_case_implicit(p, clause, parent_value);
|
||||
}
|
||||
|
||||
@@ -2014,12 +2013,10 @@ gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) {
|
||||
defer (lb_close_scope(p, lbDeferExit_Default, nullptr));
|
||||
|
||||
if (is->init != nullptr) {
|
||||
// TODO(bill): Should this have a separate block to begin with?
|
||||
#if 1
|
||||
lbBlock *init = lb_create_block(p, "if.init");
|
||||
lb_emit_jump(p, init);
|
||||
lb_start_block(p, init);
|
||||
#endif
|
||||
|
||||
lb_build_stmt(p, is->init);
|
||||
}
|
||||
lbBlock *then = lb_create_block(p, "if.then");
|
||||
|
||||
@@ -731,7 +731,6 @@ gb_internal void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup
|
||||
|
||||
type_set_offsets(t); // NOTE(bill): Just incase the offsets have not been set yet
|
||||
for (isize source_index = 0; source_index < count; source_index++) {
|
||||
// TODO(bill): Order fields in source order not layout order
|
||||
Entity *f = t->Struct.fields[source_index];
|
||||
lbValue tip = lb_type_info(m, f->type);
|
||||
i64 foffset = 0;
|
||||
|
||||
+89
-39
@@ -1,5 +1,4 @@
|
||||
// #define NO_ARRAY_BOUNDS_CHECK
|
||||
|
||||
#include "common.cpp"
|
||||
#include "timings.cpp"
|
||||
#include "tokenizer.cpp"
|
||||
@@ -74,6 +73,12 @@ gb_global Timings global_timings = {0};
|
||||
#include "linker.cpp"
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
#define ALLOW_TILDE 1
|
||||
#else
|
||||
#define ALLOW_TILDE 0
|
||||
#endif
|
||||
|
||||
#if ALLOW_TILDE
|
||||
#include "tilde.cpp"
|
||||
#endif
|
||||
|
||||
@@ -243,8 +248,16 @@ enum BuildFlagKind {
|
||||
BuildFlag_UseSeparateModules,
|
||||
BuildFlag_NoThreadedChecker,
|
||||
BuildFlag_ShowDebugMessages,
|
||||
|
||||
BuildFlag_Vet,
|
||||
BuildFlag_VetShadowing,
|
||||
BuildFlag_VetUnused,
|
||||
BuildFlag_VetUsingStmt,
|
||||
BuildFlag_VetUsingParam,
|
||||
BuildFlag_VetStyle,
|
||||
BuildFlag_VetSemicolon,
|
||||
BuildFlag_VetExtra,
|
||||
|
||||
BuildFlag_IgnoreUnknownAttributes,
|
||||
BuildFlag_ExtraLinkerFlags,
|
||||
BuildFlag_ExtraAssemblerFlags,
|
||||
@@ -261,7 +274,6 @@ enum BuildFlagKind {
|
||||
BuildFlag_DisallowDo,
|
||||
BuildFlag_DefaultToNilAllocator,
|
||||
BuildFlag_StrictStyle,
|
||||
BuildFlag_StrictStyleInitOnly,
|
||||
BuildFlag_ForeignErrorProcedures,
|
||||
BuildFlag_NoRTTI,
|
||||
BuildFlag_DynamicMapCalls,
|
||||
@@ -285,9 +297,9 @@ enum BuildFlagKind {
|
||||
BuildFlag_InternalIgnoreLazy,
|
||||
BuildFlag_InternalIgnoreLLVMBuild,
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
BuildFlag_Tilde,
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
BuildFlag_IgnoreVsSearch,
|
||||
BuildFlag_ResourceFile,
|
||||
BuildFlag_WindowsPdbName,
|
||||
@@ -422,8 +434,16 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
add_flag(&build_flags, BuildFlag_UseSeparateModules, str_lit("use-separate-modules"), BuildFlagParam_None, Command__does_build);
|
||||
add_flag(&build_flags, BuildFlag_NoThreadedChecker, str_lit("no-threaded-checker"), BuildFlagParam_None, Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_ShowDebugMessages, str_lit("show-debug-messages"), BuildFlagParam_None, Command_all);
|
||||
|
||||
add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None, Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_VetUnused, str_lit("vet-unused"), BuildFlagParam_None, Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_VetShadowing, str_lit("vet-shadowing"), BuildFlagParam_None, Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_VetUsingStmt, str_lit("vet-using-stmt"), BuildFlagParam_None, Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_VetUsingParam, str_lit("vet-using-param"), BuildFlagParam_None, Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_VetStyle, str_lit("vet-style"), BuildFlagParam_None, Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_VetSemicolon, str_lit("vet-semicolon"), BuildFlagParam_None, Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_VetExtra, str_lit("vet-extra"), BuildFlagParam_None, Command__does_check);
|
||||
|
||||
add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None, Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_ExtraLinkerFlags, str_lit("extra-linker-flags"), BuildFlagParam_String, Command__does_build);
|
||||
add_flag(&build_flags, BuildFlag_ExtraAssemblerFlags, str_lit("extra-assembler-flags"), BuildFlagParam_String, Command__does_build);
|
||||
@@ -439,7 +459,6 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
add_flag(&build_flags, BuildFlag_DisallowDo, str_lit("disallow-do"), BuildFlagParam_None, Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_DefaultToNilAllocator, str_lit("default-to-nil-allocator"), BuildFlagParam_None, Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_StrictStyle, str_lit("strict-style"), BuildFlagParam_None, Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_StrictStyleInitOnly, str_lit("strict-style-init-only"), BuildFlagParam_None, Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_ForeignErrorProcedures, str_lit("foreign-error-procedures"), BuildFlagParam_None, Command__does_check);
|
||||
|
||||
add_flag(&build_flags, BuildFlag_NoRTTI, str_lit("no-rtti"), BuildFlagParam_None, Command__does_check);
|
||||
@@ -461,9 +480,11 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
add_flag(&build_flags, BuildFlag_InternalIgnoreLazy, str_lit("internal-ignore-lazy"), BuildFlagParam_None, Command_all);
|
||||
add_flag(&build_flags, BuildFlag_InternalIgnoreLLVMBuild, str_lit("internal-ignore-llvm-build"),BuildFlagParam_None, Command_all);
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
#if ALLOW_TILDE
|
||||
add_flag(&build_flags, BuildFlag_Tilde, str_lit("tilde"), BuildFlagParam_None, Command__does_build);
|
||||
#endif
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
add_flag(&build_flags, BuildFlag_IgnoreVsSearch, str_lit("ignore-vs-search"), BuildFlagParam_None, Command__does_build);
|
||||
add_flag(&build_flags, BuildFlag_ResourceFile, str_lit("resource"), BuildFlagParam_String, Command__does_build);
|
||||
add_flag(&build_flags, BuildFlag_WindowsPdbName, str_lit("pdb-name"), BuildFlagParam_String, Command__does_build);
|
||||
@@ -956,13 +977,25 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
build_context.show_debug_messages = true;
|
||||
break;
|
||||
case BuildFlag_Vet:
|
||||
build_context.vet = true;
|
||||
if (build_context.vet_flags & VetFlag_Extra) {
|
||||
build_context.vet_flags |= VetFlag_All;
|
||||
} else {
|
||||
build_context.vet_flags &= ~VetFlag_Extra;
|
||||
build_context.vet_flags |= VetFlag_All;
|
||||
}
|
||||
break;
|
||||
case BuildFlag_VetExtra: {
|
||||
build_context.vet = true;
|
||||
build_context.vet_extra = true;
|
||||
|
||||
case BuildFlag_VetUnused: build_context.vet_flags |= VetFlag_Unused; break;
|
||||
case BuildFlag_VetShadowing: build_context.vet_flags |= VetFlag_Shadowing; break;
|
||||
case BuildFlag_VetUsingStmt: build_context.vet_flags |= VetFlag_UsingStmt; break;
|
||||
case BuildFlag_VetUsingParam: build_context.vet_flags |= VetFlag_UsingParam; break;
|
||||
case BuildFlag_VetStyle: build_context.vet_flags |= VetFlag_Style; break;
|
||||
case BuildFlag_VetSemicolon: build_context.vet_flags |= VetFlag_Semicolon; break;
|
||||
|
||||
case BuildFlag_VetExtra:
|
||||
build_context.vet_flags = VetFlag_All | VetFlag_Extra;
|
||||
break;
|
||||
}
|
||||
|
||||
case BuildFlag_IgnoreUnknownAttributes:
|
||||
build_context.ignore_unknown_attributes = true;
|
||||
break;
|
||||
@@ -1050,20 +1083,9 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
case BuildFlag_ForeignErrorProcedures:
|
||||
build_context.ODIN_FOREIGN_ERROR_PROCEDURES = true;
|
||||
break;
|
||||
case BuildFlag_StrictStyle: {
|
||||
if (build_context.strict_style_init_only) {
|
||||
gb_printf_err("-strict-style and -strict-style-init-only cannot be used together\n");
|
||||
}
|
||||
case BuildFlag_StrictStyle:
|
||||
build_context.strict_style = true;
|
||||
break;
|
||||
}
|
||||
case BuildFlag_StrictStyleInitOnly: {
|
||||
if (build_context.strict_style) {
|
||||
gb_printf_err("-strict-style and -strict-style-init-only cannot be used together\n");
|
||||
}
|
||||
build_context.strict_style_init_only = true;
|
||||
break;
|
||||
}
|
||||
case BuildFlag_Short:
|
||||
build_context.cmd_doc_flags |= CmdDocFlag_Short;
|
||||
break;
|
||||
@@ -1130,11 +1152,11 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
case BuildFlag_InternalIgnoreLLVMBuild:
|
||||
build_context.ignore_llvm_build = true;
|
||||
break;
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
case BuildFlag_Tilde:
|
||||
build_context.tilde_backend = true;
|
||||
break;
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
case BuildFlag_IgnoreVsSearch: {
|
||||
GB_ASSERT(value.kind == ExactValue_Invalid);
|
||||
build_context.ignore_microsoft_magic = true;
|
||||
@@ -1170,7 +1192,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
if (path_is_directory(path)) {
|
||||
gb_printf_err("Invalid -pdb-name path. %.*s, is a directory.\n", LIT(path));
|
||||
bad_flags = true;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
// #if defined(GB_SYSTEM_WINDOWS)
|
||||
// String ext = path_extension(path);
|
||||
@@ -1603,6 +1625,10 @@ gb_internal void print_show_help(String const arg0, String const &command) {
|
||||
print_usage_line(2, "Shows an advanced overview of the timings of different stages within the compiler in milliseconds");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-show-system-calls");
|
||||
print_usage_line(2, "Prints the whole command and arguments for calls to external tools like linker and assembler");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-export-timings:<format>");
|
||||
print_usage_line(2, "Export timings to one of a few formats. Requires `-show-timings` or `-show-more-timings`");
|
||||
print_usage_line(2, "Available options:");
|
||||
@@ -1712,29 +1738,55 @@ gb_internal void print_show_help(String const arg0, String const &command) {
|
||||
}
|
||||
|
||||
if (check) {
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
print_usage_line(1, "-no-threaded-checker");
|
||||
print_usage_line(2, "Disabled multithreading in the semantic checker stage");
|
||||
print_usage_line(0, "");
|
||||
#else
|
||||
print_usage_line(1, "-threaded-checker");
|
||||
print_usage_line(1, "[EXPERIMENTAL]");
|
||||
print_usage_line(2, "Multithread the semantic checker stage");
|
||||
print_usage_line(0, "");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (check) {
|
||||
print_usage_line(1, "-vet");
|
||||
print_usage_line(2, "Do extra checks on the code");
|
||||
print_usage_line(2, "Extra checks include:");
|
||||
print_usage_line(3, "Variable shadowing within procedures");
|
||||
print_usage_line(3, "Unused declarations");
|
||||
print_usage_line(2, "-vet-unused");
|
||||
print_usage_line(2, "-vet-shadowing");
|
||||
print_usage_line(2, "-vet-using-stmt");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-vet-unused");
|
||||
print_usage_line(2, "Checks for unused declarations");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-vet-shadowing");
|
||||
print_usage_line(2, "Checks for variable shadowing within procedures");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-vet-using-stmt");
|
||||
print_usage_line(2, "Checks for the use of 'using' as a statement");
|
||||
print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-vet-using-param");
|
||||
print_usage_line(2, "Checks for the use of 'using' on procedure parameters");
|
||||
print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-vet-style");
|
||||
print_usage_line(2, "Errs on missing trailing commas followed by a newline");
|
||||
print_usage_line(2, "Errs on deprecated syntax");
|
||||
print_usage_line(2, "Does not err on unneeded tokens (unlike -strict-style)");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-vet-semicolon");
|
||||
print_usage_line(2, "Errs on unneeded semicolons");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-vet-extra");
|
||||
print_usage_line(2, "Do even more checks than standard vet on the code");
|
||||
print_usage_line(2, "To treat the extra warnings as errors, use -warnings-as-errors");
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
if (check) {
|
||||
print_usage_line(1, "-ignore-unknown-attributes");
|
||||
print_usage_line(2, "Ignores unknown attributes");
|
||||
print_usage_line(2, "This can be used with metaprogramming tools");
|
||||
@@ -1804,10 +1856,8 @@ gb_internal void print_show_help(String const arg0, String const &command) {
|
||||
|
||||
print_usage_line(1, "-strict-style");
|
||||
print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-strict-style-init-only");
|
||||
print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons, only on the initial project");
|
||||
print_usage_line(2, "Errs on missing trailing commas followed by a newline");
|
||||
print_usage_line(2, "Errs on deprecated syntax");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-ignore-warnings");
|
||||
@@ -2417,7 +2467,7 @@ int main(int arg_count, char const **arg_ptr) {
|
||||
for_array(i, build_context.build_paths) {
|
||||
String build_path = path_to_string(heap_allocator(), build_context.build_paths[i]);
|
||||
debugf("build_paths[%ld]: %.*s\n", i, LIT(build_path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TIME_SECTION("init thread pool");
|
||||
@@ -2487,7 +2537,7 @@ int main(int arg_count, char const **arg_ptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
#if ALLOW_TILDE
|
||||
if (build_context.tilde_backend) {
|
||||
LinkerData linker_data = {};
|
||||
MAIN_TIME_SECTION("Tilde Code Gen");
|
||||
|
||||
+127
-33
@@ -1,7 +1,21 @@
|
||||
#include "parser_pos.cpp"
|
||||
|
||||
// #undef at the bottom of this file
|
||||
#define ALLOW_NEWLINE (!build_context.strict_style)
|
||||
gb_internal u64 ast_file_vet_flags(AstFile *f) {
|
||||
if (f->vet_flags_set) {
|
||||
return f->vet_flags;
|
||||
}
|
||||
return build_context.vet_flags;
|
||||
}
|
||||
|
||||
gb_internal bool ast_file_vet_style(AstFile *f) {
|
||||
return (ast_file_vet_flags(f) & VetFlag_Style) != 0;
|
||||
}
|
||||
|
||||
|
||||
gb_internal bool file_allow_newline(AstFile *f) {
|
||||
bool is_strict = build_context.strict_style || ast_file_vet_style(f);
|
||||
return !is_strict;
|
||||
}
|
||||
|
||||
gb_internal Token token_end_of_line(AstFile *f, Token tok) {
|
||||
u8 const *start = f->tokenizer.start + tok.pos.offset;
|
||||
@@ -1567,29 +1581,29 @@ gb_internal void assign_removal_flag_to_semicolon(AstFile *f) {
|
||||
Token *prev_token = &f->tokens[f->prev_token_index];
|
||||
Token *curr_token = &f->tokens[f->curr_token_index];
|
||||
GB_ASSERT(prev_token->kind == Token_Semicolon);
|
||||
if (prev_token->string == ";") {
|
||||
bool ok = false;
|
||||
if (curr_token->pos.line > prev_token->pos.line) {
|
||||
if (prev_token->string != ";") {
|
||||
return;
|
||||
}
|
||||
bool ok = false;
|
||||
if (curr_token->pos.line > prev_token->pos.line) {
|
||||
ok = true;
|
||||
} else if (curr_token->pos.line == prev_token->pos.line) {
|
||||
switch (curr_token->kind) {
|
||||
case Token_CloseBrace:
|
||||
case Token_CloseParen:
|
||||
case Token_EOF:
|
||||
ok = true;
|
||||
} else if (curr_token->pos.line == prev_token->pos.line) {
|
||||
switch (curr_token->kind) {
|
||||
case Token_CloseBrace:
|
||||
case Token_CloseParen:
|
||||
case Token_EOF:
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
if (build_context.strict_style) {
|
||||
syntax_error(*prev_token, "Found unneeded semicolon");
|
||||
} else if (build_context.strict_style_init_only && f->pkg->kind == Package_Init) {
|
||||
syntax_error(*prev_token, "Found unneeded semicolon");
|
||||
}
|
||||
prev_token->flags |= TokenFlag_Remove;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (build_context.strict_style || (ast_file_vet_flags(f) & VetFlag_Semicolon)) {
|
||||
syntax_error(*prev_token, "Found unneeded semicolon");
|
||||
}
|
||||
prev_token->flags |= TokenFlag_Remove;
|
||||
}
|
||||
|
||||
gb_internal void expect_semicolon(AstFile *f) {
|
||||
@@ -2748,7 +2762,7 @@ gb_internal Ast *parse_call_expr(AstFile *f, Ast *operand) {
|
||||
isize prev_expr_level = f->expr_level;
|
||||
bool prev_allow_newline = f->allow_newline;
|
||||
f->expr_level = 0;
|
||||
f->allow_newline = ALLOW_NEWLINE;
|
||||
f->allow_newline = file_allow_newline(f);
|
||||
|
||||
open_paren = expect_token(f, Token_OpenParen);
|
||||
|
||||
@@ -3147,7 +3161,7 @@ gb_internal Ast *parse_expr(AstFile *f, bool lhs) {
|
||||
|
||||
gb_internal Array<Ast *> parse_expr_list(AstFile *f, bool lhs) {
|
||||
bool allow_newline = f->allow_newline;
|
||||
f->allow_newline = ALLOW_NEWLINE;
|
||||
f->allow_newline = file_allow_newline(f);
|
||||
|
||||
auto list = array_make<Ast *>(heap_allocator());
|
||||
for (;;) {
|
||||
@@ -3472,7 +3486,7 @@ gb_internal Ast *parse_results(AstFile *f, bool *diverging) {
|
||||
Ast *list = nullptr;
|
||||
expect_token(f, Token_OpenParen);
|
||||
list = parse_field_list(f, nullptr, FieldFlag_Results, Token_CloseParen, true, false);
|
||||
if (ALLOW_NEWLINE) {
|
||||
if (file_allow_newline(f)) {
|
||||
skip_possible_newline(f);
|
||||
}
|
||||
expect_token_after(f, Token_CloseParen, "parameter list");
|
||||
@@ -3532,7 +3546,7 @@ gb_internal Ast *parse_proc_type(AstFile *f, Token proc_token) {
|
||||
|
||||
expect_token(f, Token_OpenParen);
|
||||
params = parse_field_list(f, nullptr, FieldFlag_Signature, Token_CloseParen, true, true);
|
||||
if (ALLOW_NEWLINE) {
|
||||
if (file_allow_newline(f)) {
|
||||
skip_possible_newline(f);
|
||||
}
|
||||
expect_token_after(f, Token_CloseParen, "parameter list");
|
||||
@@ -3754,7 +3768,7 @@ gb_internal bool allow_field_separator(AstFile *f) {
|
||||
}
|
||||
if (token.kind == Token_Semicolon) {
|
||||
bool ok = false;
|
||||
if (ALLOW_NEWLINE && token_is_newline(token)) {
|
||||
if (file_allow_newline(f) && token_is_newline(token)) {
|
||||
TokenKind next = peek_token(f).kind;
|
||||
switch (next) {
|
||||
case Token_CloseBrace:
|
||||
@@ -3818,7 +3832,7 @@ gb_internal bool check_procedure_name_list(Array<Ast *> const &names) {
|
||||
gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow, bool allow_default_parameters, bool allow_typeid_token) {
|
||||
bool prev_allow_newline = f->allow_newline;
|
||||
defer (f->allow_newline = prev_allow_newline);
|
||||
f->allow_newline = ALLOW_NEWLINE;
|
||||
f->allow_newline = file_allow_newline(f);
|
||||
|
||||
Token start_token = f->curr_token;
|
||||
|
||||
@@ -4954,7 +4968,6 @@ gb_internal bool init_parser(Parser *p) {
|
||||
|
||||
gb_internal void destroy_parser(Parser *p) {
|
||||
GB_ASSERT(p != nullptr);
|
||||
// TODO(bill): Fix memory leak
|
||||
for (AstPackage *pkg : p->packages) {
|
||||
for (AstFile *file : pkg->files) {
|
||||
destroy_ast_file(file);
|
||||
@@ -4998,7 +5011,6 @@ gb_internal WORKER_TASK_PROC(parser_worker_proc) {
|
||||
|
||||
|
||||
gb_internal void parser_add_file_to_process(Parser *p, AstPackage *pkg, FileInfo fi, TokenPos pos) {
|
||||
// TODO(bill): Use a better allocator
|
||||
ImportedFile f = {pkg, fi, pos, p->file_to_process_count++};
|
||||
auto wd = gb_alloc_item(permanent_allocator(), ParserWorkerData);
|
||||
wd->parser = p;
|
||||
@@ -5528,6 +5540,88 @@ gb_internal bool parse_build_tag(Token token_for_pos, String s) {
|
||||
return any_correct;
|
||||
}
|
||||
|
||||
gb_internal String vet_tag_get_token(String s, String *out) {
|
||||
s = string_trim_whitespace(s);
|
||||
isize n = 0;
|
||||
while (n < s.len) {
|
||||
Rune rune = 0;
|
||||
isize width = utf8_decode(&s[n], s.len-n, &rune);
|
||||
if (n == 0 && rune == '!') {
|
||||
|
||||
} else if (!rune_is_letter(rune) && !rune_is_digit(rune) && rune != '-') {
|
||||
isize k = gb_max(gb_max(n, width), 1);
|
||||
*out = substring(s, k, s.len);
|
||||
return substring(s, 0, k);
|
||||
}
|
||||
n += width;
|
||||
}
|
||||
out->len = 0;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
gb_internal u64 parse_vet_tag(Token token_for_pos, String s) {
|
||||
String const prefix = str_lit("+vet");
|
||||
GB_ASSERT(string_starts_with(s, prefix));
|
||||
s = string_trim_whitespace(substring(s, prefix.len, s.len));
|
||||
|
||||
if (s.len == 0) {
|
||||
return VetFlag_All;
|
||||
}
|
||||
|
||||
|
||||
u64 vet_flags = 0;
|
||||
u64 vet_not_flags = 0;
|
||||
|
||||
while (s.len > 0) {
|
||||
String p = string_trim_whitespace(vet_tag_get_token(s, &s));
|
||||
if (p.len == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
bool is_notted = false;
|
||||
if (p[0] == '!') {
|
||||
is_notted = true;
|
||||
p = substring(p, 1, p.len);
|
||||
if (p.len == 0) {
|
||||
syntax_error(token_for_pos, "Expected a vet flag name after '!'");
|
||||
return build_context.vet_flags;
|
||||
}
|
||||
}
|
||||
|
||||
u64 flag = get_vet_flag_from_name(p);
|
||||
if (flag != VetFlag_NONE) {
|
||||
if (is_notted) {
|
||||
vet_not_flags |= flag;
|
||||
} else {
|
||||
vet_flags |= flag;
|
||||
}
|
||||
} else {
|
||||
ERROR_BLOCK();
|
||||
syntax_error(token_for_pos, "Invalid vet flag name: %.*s", LIT(p));
|
||||
error_line("\tExpected one of the following\n");
|
||||
error_line("\tunused\n");
|
||||
error_line("\tshadowing\n");
|
||||
error_line("\tusing-stmt\n");
|
||||
error_line("\tusing-param\n");
|
||||
error_line("\textra\n");
|
||||
return build_context.vet_flags;
|
||||
}
|
||||
}
|
||||
|
||||
if (vet_flags == 0 && vet_not_flags == 0) {
|
||||
return build_context.vet_flags;
|
||||
}
|
||||
if (vet_flags == 0 && vet_not_flags != 0) {
|
||||
return build_context.vet_flags &~ vet_not_flags;
|
||||
}
|
||||
if (vet_flags != 0 && vet_not_flags == 0) {
|
||||
return vet_flags;
|
||||
}
|
||||
GB_ASSERT(vet_flags != 0 && vet_not_flags != 0);
|
||||
return vet_flags &~ vet_not_flags;
|
||||
}
|
||||
|
||||
gb_internal String dir_from_path(String path) {
|
||||
String base_dir = path;
|
||||
for (isize i = path.len-1; i >= 0; i--) {
|
||||
@@ -5679,6 +5773,9 @@ gb_internal bool parse_file(Parser *p, AstFile *f) {
|
||||
if (!parse_build_tag(tok, lc)) {
|
||||
return false;
|
||||
}
|
||||
} else if (string_starts_with(lc, str_lit("+vet"))) {
|
||||
f->vet_flags = parse_vet_tag(tok, lc);
|
||||
f->vet_flags_set = true;
|
||||
} else if (string_starts_with(lc, str_lit("+ignore"))) {
|
||||
return false;
|
||||
} else if (string_starts_with(lc, str_lit("+private"))) {
|
||||
@@ -5920,6 +6017,3 @@ gb_internal ParseFileError parse_packages(Parser *p, String init_filename) {
|
||||
return ParseFile_None;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#undef ALLOW_NEWLINE
|
||||
|
||||
@@ -104,6 +104,8 @@ struct AstFile {
|
||||
Token package_token;
|
||||
String package_name;
|
||||
|
||||
u64 vet_flags;
|
||||
bool vet_flags_set;
|
||||
|
||||
// >= 0: In Expression
|
||||
// < 0: In Control Clause
|
||||
|
||||
+2
-2
@@ -696,8 +696,8 @@ gb_internal void tokenizer_get_token(Tokenizer *t, Token *token, int repeat=0) {
|
||||
if (entry->kind != Token_Invalid && entry->hash == hash) {
|
||||
if (str_eq(entry->text, token->string)) {
|
||||
token->kind = entry->kind;
|
||||
if (token->kind == Token_not_in && entry->text == "notin") {
|
||||
syntax_warning(*token, "'notin' is deprecated in favour of 'not_in'");
|
||||
if (token->kind == Token_not_in && entry->text.len == 5) {
|
||||
syntax_error(*token, "Did you mean 'not_in'?");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+14
-10
@@ -143,6 +143,7 @@ struct TypeStruct {
|
||||
Type * soa_elem;
|
||||
i32 soa_count;
|
||||
StructSoaKind soa_kind;
|
||||
BlockingMutex mutex; // for settings offsets
|
||||
|
||||
bool is_polymorphic;
|
||||
bool are_offsets_set : 1;
|
||||
@@ -244,6 +245,7 @@ struct TypeProc {
|
||||
TYPE_KIND(Tuple, struct { \
|
||||
Slice<Entity *> variables; /* Entity_Variable */ \
|
||||
i64 * offsets; \
|
||||
BlockingMutex mutex; /* for settings offsets */ \
|
||||
bool are_offsets_being_processed; \
|
||||
bool are_offsets_set; \
|
||||
bool is_packed; \
|
||||
@@ -822,6 +824,9 @@ gb_internal void type_path_pop(TypePath *tp) {
|
||||
#define FAILURE_ALIGNMENT 0
|
||||
|
||||
gb_internal bool type_ptr_set_update(PtrSet<Type *> *s, Type *t) {
|
||||
if (t == nullptr) {
|
||||
return true;
|
||||
}
|
||||
if (ptr_set_exists(s, t)) {
|
||||
return true;
|
||||
}
|
||||
@@ -830,13 +835,17 @@ gb_internal bool type_ptr_set_update(PtrSet<Type *> *s, Type *t) {
|
||||
}
|
||||
|
||||
gb_internal bool type_ptr_set_exists(PtrSet<Type *> *s, Type *t) {
|
||||
if (t == nullptr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ptr_set_exists(s, t)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO(bill, 2019-10-05): This is very slow and it's probably a lot
|
||||
// faster to cache types correctly
|
||||
for (Type *f : *s) {
|
||||
for (Type *f : *s) if (f->kind == t->kind) {
|
||||
if (are_types_identical(t, f)) {
|
||||
ptr_set_add(s, t);
|
||||
return true;
|
||||
@@ -989,7 +998,7 @@ gb_internal Type *alloc_type_enumerated_array(Type *elem, Type *index, ExactValu
|
||||
|
||||
gb_internal Type *alloc_type_slice(Type *elem) {
|
||||
Type *t = alloc_type(Type_Slice);
|
||||
t->Array.elem = elem;
|
||||
t->Slice.elem = elem;
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -2667,7 +2676,6 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple
|
||||
x->Struct.soa_kind == y->Struct.soa_kind &&
|
||||
x->Struct.soa_count == y->Struct.soa_count &&
|
||||
are_types_identical(x->Struct.soa_elem, y->Struct.soa_elem)) {
|
||||
// TODO(bill); Fix the custom alignment rule
|
||||
for_array(i, x->Struct.fields) {
|
||||
Entity *xf = x->Struct.fields[i];
|
||||
Entity *yf = y->Struct.fields[i];
|
||||
@@ -2808,7 +2816,6 @@ gb_internal i64 union_tag_size(Type *u) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO(bill): Is this an okay approach?
|
||||
i64 max_align = 1;
|
||||
|
||||
if (u->Union.variants.count < 1ull<<8) {
|
||||
@@ -2818,7 +2825,7 @@ gb_internal i64 union_tag_size(Type *u) {
|
||||
} else if (u->Union.variants.count < 1ull<<32) {
|
||||
max_align = 4;
|
||||
} else {
|
||||
GB_PANIC("how many variants do you have?!");
|
||||
compiler_error("how many variants do you have?! %lld", cast(long long)u->Union.variants.count);
|
||||
}
|
||||
|
||||
for_array(i, u->Union.variants) {
|
||||
@@ -3137,8 +3144,6 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name
|
||||
switch (type->Basic.kind) {
|
||||
case Basic_any: {
|
||||
#if 1
|
||||
// IMPORTANT TODO(bill): Should these members be available to should I only allow them with
|
||||
// `Raw_Any` type?
|
||||
String data_str = str_lit("data");
|
||||
String id_str = str_lit("id");
|
||||
gb_local_persist Entity *entity__any_data = alloc_entity_field(nullptr, make_token_ident(data_str), t_rawptr, false, 0);
|
||||
@@ -3672,10 +3677,9 @@ gb_internal i64 *type_set_offsets_of(Slice<Entity *> const &fields, bool is_pack
|
||||
}
|
||||
|
||||
gb_internal bool type_set_offsets(Type *t) {
|
||||
MUTEX_GUARD(&g_type_mutex); // TODO(bill): only per struct
|
||||
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Struct) {
|
||||
MUTEX_GUARD(&t->Struct.mutex);
|
||||
if (!t->Struct.are_offsets_set) {
|
||||
t->Struct.are_offsets_being_processed = true;
|
||||
t->Struct.offsets = type_set_offsets_of(t->Struct.fields, t->Struct.is_packed, t->Struct.is_raw_union);
|
||||
@@ -3684,6 +3688,7 @@ gb_internal bool type_set_offsets(Type *t) {
|
||||
return true;
|
||||
}
|
||||
} else if (is_type_tuple(t)) {
|
||||
MUTEX_GUARD(&t->Tuple.mutex);
|
||||
if (!t->Tuple.are_offsets_set) {
|
||||
t->Tuple.are_offsets_being_processed = true;
|
||||
t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, t->Tuple.is_packed, false);
|
||||
@@ -3858,7 +3863,6 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) {
|
||||
max = size;
|
||||
}
|
||||
}
|
||||
// TODO(bill): Is this how it should work?
|
||||
return align_formula(max, align);
|
||||
} else {
|
||||
i64 count = 0, size = 0, align = 0;
|
||||
|
||||
Reference in New Issue
Block a user