aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndreas T Jonsson <mail@andreasjonsson.se>2024-05-16 13:48:44 +0200
committerAndreas T Jonsson <mail@andreasjonsson.se>2024-05-16 13:48:44 +0200
commita93bbf6f922cd59683c9ed1aeaf5bb9940c843c1 (patch)
treed30eb60984886812d2e36a32e501ed68f7453074 /src
parent5541f602335a74c357046a603119c6b49b63e25d (diff)
parentf9fd8f0c25bb0b239e5421c39217d2f8c449911f (diff)
Merge branch 'master' into netbsd-ci
Diffstat (limited to 'src')
-rw-r--r--src/build_settings.cpp5
-rw-r--r--src/check_expr.cpp25
-rw-r--r--src/check_stmt.cpp54
-rw-r--r--src/check_type.cpp13
-rw-r--r--src/error.cpp15
-rw-r--r--src/llvm_backend_expr.cpp52
-rw-r--r--src/llvm_backend_general.cpp2
-rw-r--r--src/llvm_backend_stmt.cpp41
-rw-r--r--src/parser.cpp31
-rw-r--r--src/path.cpp5
10 files changed, 203 insertions, 40 deletions
diff --git a/src/build_settings.cpp b/src/build_settings.cpp
index 0fd5d504a..7eb198185 100644
--- a/src/build_settings.cpp
+++ b/src/build_settings.cpp
@@ -732,10 +732,11 @@ enum VetFlags : u64 {
VetFlag_Semicolon = 1u<<4,
VetFlag_UnusedVariables = 1u<<5,
VetFlag_UnusedImports = 1u<<6,
+ VetFlag_Deprecated = 1u<<7,
VetFlag_Unused = VetFlag_UnusedVariables|VetFlag_UnusedImports,
- VetFlag_All = VetFlag_Unused|VetFlag_Shadowing|VetFlag_UsingStmt,
+ VetFlag_All = VetFlag_Unused|VetFlag_Shadowing|VetFlag_UsingStmt|VetFlag_Deprecated,
VetFlag_Using = VetFlag_UsingStmt|VetFlag_UsingParam,
};
@@ -757,6 +758,8 @@ u64 get_vet_flag_from_name(String const &name) {
return VetFlag_Style;
} else if (name == "semicolon") {
return VetFlag_Semicolon;
+ } else if (name == "deprecated") {
+ return VetFlag_Deprecated;
}
return VetFlag_NONE;
}
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 08f488642..6a293a97e 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -1441,6 +1441,13 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T
// return check_is_assignable_to(c, &o, poly); // && is_type_subtype_of_and_allow_polymorphic(o.type, poly);
}
return false;
+
+ case Type_BitField:
+ if (source->kind == Type_BitField) {
+ return is_polymorphic_type_assignable(c, poly->BitField.backing_type, source->BitField.backing_type, true, modify_type);
+ }
+ return false;
+
case Type_Tuple:
GB_PANIC("This should never happen");
return false;
@@ -1787,6 +1794,13 @@ gb_internal bool check_unary_op(CheckerContext *c, Operand *o, Token op) {
gb_string_free(str);
return false;
}
+ if (o->mode == Addressing_Type) {
+ gbString str = type_to_string(o->type);
+ error(o->expr, "Expected an expression for operator '%.*s', got type '%s'", LIT(op.string), str);
+ gb_string_free(str);
+ return false;
+ }
+
Type *type = base_type(core_array_type(o->type));
gbString str = nullptr;
switch (op.kind) {
@@ -10249,6 +10263,17 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node,
case Type_Struct:
if (is_type_soa_struct(t)) {
valid = true;
+ if (t->Struct.soa_kind == StructSoa_Fixed) {
+ max_count = t->Struct.soa_count;
+ if (o->mode != Addressing_Variable && !is_type_pointer(o->type)) {
+ gbString str = expr_to_string(node);
+ error(node, "Cannot slice #soa array '%s', value is not addressable", str);
+ gb_string_free(str);
+ o->mode = Addressing_Invalid;
+ o->expr = node;
+ return kind;
+ }
+ }
o->type = make_soa_struct_slice(c, nullptr, nullptr, t->Struct.soa_elem);
}
break;
diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp
index c018077f9..875503874 100644
--- a/src/check_stmt.cpp
+++ b/src/check_stmt.cpp
@@ -169,9 +169,16 @@ gb_internal bool check_has_break_list(Slice<Ast *> const &stmts, String const &l
return false;
}
+gb_internal bool check_has_break_expr(Ast * expr, String const &label) {
+ if (expr && expr->viral_state_flags & ViralStateFlag_ContainsOrBreak) {
+ return true;
+ }
+ return false;
+}
+
gb_internal bool check_has_break_expr_list(Slice<Ast *> const &exprs, String const &label) {
for (Ast *expr : exprs) {
- if (expr && expr->viral_state_flags & ViralStateFlag_ContainsOrBreak) {
+ if (check_has_break_expr(expr, label)) {
return true;
}
}
@@ -196,6 +203,13 @@ gb_internal bool check_has_break(Ast *stmt, String const &label, bool implicit)
return check_has_break_list(stmt->BlockStmt.stmts, label, implicit);
case Ast_IfStmt:
+ if (stmt->IfStmt.init && check_has_break(stmt->IfStmt.init, label, implicit)) {
+ return true;
+ }
+ if (stmt->IfStmt.cond && check_has_break_expr(stmt->IfStmt.cond, label)) {
+ return true;
+ }
+
if (check_has_break(stmt->IfStmt.body, label, implicit) ||
(stmt->IfStmt.else_stmt != nullptr && check_has_break(stmt->IfStmt.else_stmt, label, implicit))) {
return true;
@@ -206,6 +220,9 @@ gb_internal bool check_has_break(Ast *stmt, String const &label, bool implicit)
return check_has_break_list(stmt->CaseClause.stmts, label, implicit);
case Ast_SwitchStmt:
+ if (stmt->SwitchStmt.init && check_has_break_expr(stmt->SwitchStmt.init, label)) {
+ return true;
+ }
if (label != "" && check_has_break(stmt->SwitchStmt.body, label, false)) {
return true;
}
@@ -218,6 +235,16 @@ gb_internal bool check_has_break(Ast *stmt, String const &label, bool implicit)
break;
case Ast_ForStmt:
+ if (stmt->ForStmt.init && check_has_break(stmt->ForStmt.init, label, implicit)) {
+ return true;
+ }
+ if (stmt->ForStmt.cond && check_has_break_expr(stmt->ForStmt.cond, label)) {
+ return true;
+ }
+ if (stmt->ForStmt.post && check_has_break(stmt->ForStmt.post, label, implicit)) {
+ return true;
+ }
+
if (label != "" && check_has_break(stmt->ForStmt.body, label, false)) {
return true;
}
@@ -253,7 +280,16 @@ gb_internal bool check_has_break(Ast *stmt, String const &label, bool implicit)
return false;
}
-
+String label_string(Ast *node) {
+ GB_ASSERT(node != nullptr);
+ if (node->kind == Ast_Ident) {
+ return node->Ident.token.string;
+ } else if (node->kind == Ast_Label) {
+ return label_string(node->Label.name);
+ }
+ GB_ASSERT("INVALID LABEL");
+ return {};
+}
// NOTE(bill): The last expression has to be a 'return' statement
// TODO(bill): This is a mild hack and should be probably handled properly
@@ -264,7 +300,12 @@ gb_internal bool check_is_terminating(Ast *node, String const &label) {
case_end;
case_ast_node(bs, BlockStmt, node);
- return check_is_terminating_list(bs->stmts, label);
+ if (check_is_terminating_list(bs->stmts, label)) {
+ if (bs->label != nullptr) {
+ return check_is_terminating_list(bs->stmts, label_string(bs->label));
+ }
+ return true;
+ }
case_end;
case_ast_node(es, ExprStmt, node);
@@ -321,6 +362,9 @@ gb_internal bool check_is_terminating(Ast *node, String const &label) {
case_ast_node(fs, ForStmt, node);
if (fs->cond == nullptr && !check_has_break(fs->body, label, true)) {
+ if (fs->label) {
+ return !check_has_break(fs->body, label_string(fs->label), false);
+ }
return true;
}
case_end;
@@ -734,7 +778,7 @@ gb_internal bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us,
for (auto const &entry : scope->elements) {
String name = entry.key;
Entity *decl = entry.value;
- if (!is_entity_exported(decl)) continue;
+ if (!is_entity_exported(decl, true)) continue;
Entity *found = scope_insert_with_name(ctx->scope, name, decl);
if (found != nullptr) {
@@ -759,6 +803,8 @@ gb_internal bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us,
bool is_ptr = is_type_pointer(e->type);
Type *t = base_type(type_deref(e->type));
if (t->kind == Type_Struct) {
+ wait_signal_until_available(&t->Struct.fields_wait_signal);
+
Scope *found = t->Struct.scope;
GB_ASSERT(found != nullptr);
for (auto const &entry : found->elements) {
diff --git a/src/check_type.cpp b/src/check_type.cpp
index 4df0c5d19..c209a8e09 100644
--- a/src/check_type.cpp
+++ b/src/check_type.cpp
@@ -19,10 +19,12 @@ gb_internal void populate_using_array_index(CheckerContext *ctx, Ast *node, AstF
}
} else {
Token tok = make_token_ident(name);
- if (field->names.count > 0) {
- tok.pos = ast_token(field->names[0]).pos;
- } else {
- tok.pos = ast_token(field->type).pos;
+ if (field) {
+ if (field->names.count > 0) {
+ tok.pos = ast_token(field->names[0]).pos;
+ } else {
+ tok.pos = ast_token(field->type).pos;
+ }
}
Entity *f = alloc_entity_array_elem(nullptr, tok, t->Array.elem, idx);
add_entity(ctx, ctx->scope, nullptr, f);
@@ -191,9 +193,10 @@ gb_internal void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entit
if (is_using && p->names.count > 0) {
Type *first_type = fields_array[fields_array.count-1]->type;
+ bool soa_ptr = is_type_soa_pointer(first_type);
Type *t = base_type(type_deref(first_type));
- if (!does_field_type_allow_using(t) &&
+ if ((soa_ptr || !does_field_type_allow_using(t)) &&
p->names.count >= 1 &&
p->names[0]->kind == Ast_Ident) {
Token name_token = p->names[0]->Ident.token;
diff --git a/src/error.cpp b/src/error.cpp
index 688d1b34a..f5123b969 100644
--- a/src/error.cpp
+++ b/src/error.cpp
@@ -672,7 +672,20 @@ gb_internal int error_value_cmp(void const *a, void const *b) {
return token_pos_cmp(x->pos, y->pos);
}
+gb_internal bool errors_already_printed = false;
+
gb_internal void print_all_errors(void) {
+ if (errors_already_printed) {
+ if (global_error_collector.warning_count.load() == global_error_collector.error_values.count) {
+ for (ErrorValue &ev : global_error_collector.error_values) {
+ array_free(&ev.msg);
+ }
+ array_clear(&global_error_collector.error_values);
+ errors_already_printed = false;
+ }
+ return;
+ }
+
auto const &escape_char = [](gbString res, u8 c) -> gbString {
switch (c) {
case '\n': res = gb_string_append_length(res, "\\n", 2); break;
@@ -827,4 +840,6 @@ gb_internal void print_all_errors(void) {
}
gbFile *f = gb_file_get_standard(gbFileStandard_Error);
gb_file_write(f, res, gb_string_length(res));
+
+ errors_already_printed = true;
} \ No newline at end of file
diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp
index ad02ff7dd..899b74e56 100644
--- a/src/llvm_backend_expr.cpp
+++ b/src/llvm_backend_expr.cpp
@@ -4141,7 +4141,7 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) {
if (se->high == nullptr) {
lbValue offset = base;
LLVMValueRef indices[1] = {low.value};
- offset.value = LLVMBuildGEP2(p->builder, lb_type(p->module, offset.type->MultiPointer.elem), offset.value, indices, 1, "");
+ offset.value = LLVMBuildGEP2(p->builder, lb_type(p->module, base_type(offset.type)->MultiPointer.elem), offset.value, indices, 1, "");
lb_addr_store(p, res, offset);
} else {
low = lb_emit_conv(p, low, t_int);
@@ -4150,7 +4150,7 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) {
lb_emit_multi_pointer_slice_bounds_check(p, se->open, low, high);
LLVMValueRef indices[1] = {low.value};
- LLVMValueRef ptr = LLVMBuildGEP2(p->builder, lb_type(p->module, base.type->MultiPointer.elem), base.value, indices, 1, "");
+ LLVMValueRef ptr = LLVMBuildGEP2(p->builder, lb_type(p->module, base_type(base.type)->MultiPointer.elem), base.value, indices, 1, "");
LLVMValueRef len = LLVMBuildSub(p->builder, high.value, low.value, "");
LLVMValueRef gep0 = lb_emit_struct_ep(p, res.addr, 0).value;
@@ -5194,6 +5194,54 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
lbValue ptr = lb_address_from_load_or_generate_local(p, lb_build_expr(p, expr));
return lb_addr(ptr);
case_end;
+
+
+ case_ast_node(be, OrBranchExpr, expr);
+ lbBlock *block = nullptr;
+
+ if (be->label != nullptr) {
+ lbBranchBlocks bb = lb_lookup_branch_blocks(p, be->label);
+ switch (be->token.kind) {
+ case Token_or_break: block = bb.break_; break;
+ case Token_or_continue: block = bb.continue_; break;
+ }
+ } else {
+ for (lbTargetList *t = p->target_list; t != nullptr && block == nullptr; t = t->prev) {
+ if (t->is_block) {
+ continue;
+ }
+
+ switch (be->token.kind) {
+ case Token_or_break: block = t->break_; break;
+ case Token_or_continue: block = t->continue_; break;
+ }
+ }
+ }
+
+ GB_ASSERT(block != nullptr);
+ TypeAndValue tv = expr->tav;
+
+ lbValue lhs = {};
+ lbValue rhs = {};
+ lb_emit_try_lhs_rhs(p, be->expr, tv, &lhs, &rhs);
+ Type *type = default_type(tv.type);
+ if (lhs.value) {
+ lhs = lb_emit_conv(p, lhs, type);
+ } else if (type != nullptr && type != t_invalid) {
+ lhs = lb_const_nil(p->module, type);
+ }
+
+ lbBlock *then = lb_create_block(p, "or_branch.then");
+ lbBlock *else_ = lb_create_block(p, "or_branch.else");
+
+ lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_);
+ lb_start_block(p, else_);
+ lb_emit_defer_stmts(p, lbDeferExit_Branch, block);
+ lb_emit_jump(p, block);
+ lb_start_block(p, then);
+
+ return lb_addr(lb_address_from_load_or_generate_local(p, lhs));
+ case_end;
}
TokenPos token_pos = ast_token(expr).pos;
diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp
index 9caddfb51..3c1a7ee7f 100644
--- a/src/llvm_backend_general.cpp
+++ b/src/llvm_backend_general.cpp
@@ -1180,7 +1180,7 @@ gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) {
Type *t = addr.bitfield.type;
if (do_mask) {
- GB_ASSERT(addr.bitfield.bit_size < 8*type_size_of(ct));
+ GB_ASSERT(addr.bitfield.bit_size <= 8*type_size_of(ct));
lbValue mask = lb_const_int(p->module, t, (1ull<<cast(u64)addr.bitfield.bit_size)-1);
r = lb_emit_arith(p, Token_And, r, mask, t);
diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp
index 851433415..b18db4e45 100644
--- a/src/llvm_backend_stmt.cpp
+++ b/src/llvm_backend_stmt.cpp
@@ -2157,6 +2157,16 @@ gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) {
lb_open_scope(p, is->scope); // Scope #1
defer (lb_close_scope(p, lbDeferExit_Default, nullptr));
+ lbBlock *then = lb_create_block(p, "if.then");
+ lbBlock *done = lb_create_block(p, "if.done");
+ lbBlock *else_ = done;
+ if (is->else_stmt != nullptr) {
+ else_ = lb_create_block(p, "if.else");
+ }
+ if (is->label != nullptr) {
+ lbTargetList *tl = lb_push_target_list(p, is->label, done, nullptr, nullptr);
+ tl->is_block = true;
+ }
if (is->init != nullptr) {
lbBlock *init = lb_create_block(p, "if.init");
lb_emit_jump(p, init);
@@ -2164,22 +2174,12 @@ gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) {
lb_build_stmt(p, is->init);
}
- lbBlock *then = lb_create_block(p, "if.then");
- lbBlock *done = lb_create_block(p, "if.done");
- lbBlock *else_ = done;
- if (is->else_stmt != nullptr) {
- else_ = lb_create_block(p, "if.else");
- }
lbValue cond = lb_build_cond(p, is->cond, then, else_);
// Note `cond.value` only set for non-and/or conditions and const negs so that the `LLVMIsConstant()`
// and `LLVMConstIntGetZExtValue()` calls below will be valid and `LLVMInstructionEraseFromParent()`
// will target the correct (& only) branch statement
- if (is->label != nullptr) {
- lbTargetList *tl = lb_push_target_list(p, is->label, done, nullptr, nullptr);
- tl->is_block = true;
- }
if (cond.value && LLVMIsConstant(cond.value)) {
// NOTE(bill): Do a compile time short circuit for when the condition is constantly known.
@@ -2244,15 +2244,6 @@ gb_internal void lb_build_for_stmt(lbProcedure *p, Ast *node) {
if (p->debug_info != nullptr) {
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, node));
}
-
- if (fs->init != nullptr) {
- #if 1
- lbBlock *init = lb_create_block(p, "for.init");
- lb_emit_jump(p, init);
- lb_start_block(p, init);
- #endif
- lb_build_stmt(p, fs->init);
- }
lbBlock *body = lb_create_block(p, "for.body");
lbBlock *done = lb_create_block(p, "for.done"); // NOTE(bill): Append later
lbBlock *loop = body;
@@ -2264,6 +2255,17 @@ gb_internal void lb_build_for_stmt(lbProcedure *p, Ast *node) {
post = lb_create_block(p, "for.post");
}
+ lb_push_target_list(p, fs->label, done, post, nullptr);
+
+ if (fs->init != nullptr) {
+ #if 1
+ lbBlock *init = lb_create_block(p, "for.init");
+ lb_emit_jump(p, init);
+ lb_start_block(p, init);
+ #endif
+ lb_build_stmt(p, fs->init);
+ }
+
lb_emit_jump(p, loop);
lb_start_block(p, loop);
@@ -2276,7 +2278,6 @@ gb_internal void lb_build_for_stmt(lbProcedure *p, Ast *node) {
lb_start_block(p, body);
}
- lb_push_target_list(p, fs->label, done, post, nullptr);
lb_build_stmt(p, fs->body);
diff --git a/src/parser.cpp b/src/parser.cpp
index ee3c56daf..e296e6935 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -11,6 +11,9 @@ gb_internal bool ast_file_vet_style(AstFile *f) {
return (ast_file_vet_flags(f) & VetFlag_Style) != 0;
}
+gb_internal bool ast_file_vet_deprecated(AstFile *f) {
+ return (ast_file_vet_flags(f) & VetFlag_Deprecated) != 0;
+}
gb_internal bool file_allow_newline(AstFile *f) {
bool is_strict = build_context.strict_style || ast_file_vet_style(f);
@@ -1569,7 +1572,7 @@ gb_internal Token expect_operator(AstFile *f) {
LIT(p));
}
if (prev.kind == Token_Ellipsis) {
- syntax_warning(prev, "'..' for ranges has now been deprecated, prefer '..='");
+ syntax_error(prev, "'..' for ranges are not allowed, did you mean '..<' or '..='?");
f->tokens[f->curr_token_index].flags |= TokenFlag_Replace;
}
@@ -5508,11 +5511,15 @@ gb_internal AstPackage *try_add_import_path(Parser *p, String path, String const
}
}
if (files_with_ext == 0 || files_to_reserve == 1) {
+ ERROR_BLOCK();
if (files_with_ext != 0) {
syntax_error(pos, "Directory contains no .odin files for the specified platform: %.*s", LIT(rel_path));
} else {
syntax_error(pos, "Empty directory that contains no .odin files: %.*s", LIT(rel_path));
}
+ if (build_context.command_kind == Command_test) {
+ error_line("\tSuggestion: Make an .odin file that imports packages to test and use the `-all-packages` flag.");
+ }
return nullptr;
}
@@ -5690,8 +5697,26 @@ gb_internal bool determine_path_from_string(BlockingMutex *file_mutex, Ast *node
if (collection_name.len > 0) {
// NOTE(bill): `base:runtime` == `core:runtime`
- if (collection_name == "core" && string_starts_with(file_str, str_lit("runtime"))) {
- collection_name = str_lit("base");
+ if (collection_name == "core") {
+ bool replace_with_base = false;
+ if (string_starts_with(file_str, str_lit("runtime"))) {
+ replace_with_base = true;
+ } else if (string_starts_with(file_str, str_lit("intrinsics"))) {
+ replace_with_base = true;
+ } if (string_starts_with(file_str, str_lit("builtin"))) {
+ replace_with_base = true;
+ }
+
+ if (replace_with_base) {
+ collection_name = str_lit("base");
+ }
+ if (replace_with_base) {
+ if (ast_file_vet_deprecated(node->file())) {
+ syntax_error(node, "import \"core:%.*s\" has been deprecated in favour of \"base:%.*s\"", LIT(file_str), LIT(file_str));
+ } else {
+ syntax_warning(ast_token(node), "import \"core:%.*s\" has been deprecated in favour of \"base:%.*s\"", LIT(file_str), LIT(file_str));
+ }
+ }
}
if (collection_name == "system") {
diff --git a/src/path.cpp b/src/path.cpp
index 2f016a578..26ccb7cbf 100644
--- a/src/path.cpp
+++ b/src/path.cpp
@@ -400,16 +400,13 @@ gb_internal ReadDirectoryError read_directory(String path, Array<FileInfo> *fi)
continue;
}
- if (S_ISDIR(dir_stat.st_mode)) {
- continue;
- }
-
i64 size = dir_stat.st_size;
FileInfo info = {};
info.name = copy_string(a, name);
info.fullpath = path_to_full_path(a, filepath);
info.size = size;
+ info.is_dir = S_ISDIR(dir_stat.st_mode);
array_add(fi, info);
}