diff options
Diffstat (limited to 'src/check_stmt.cpp')
| -rw-r--r-- | src/check_stmt.cpp | 116 |
1 files changed, 106 insertions, 10 deletions
diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 2418fcc5c..1b44ff4d7 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -894,15 +894,49 @@ gb_internal void error_var_decl_identifier(Ast *name) { } } -gb_internal void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { +gb_internal void check_unroll_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { ast_node(irs, UnrollRangeStmt, node); check_open_scope(ctx, node); + defer (check_close_scope(ctx)); Type *val0 = nullptr; Type *val1 = nullptr; Entity *entities[2] = {}; isize entity_count = 0; + i64 unroll_count = -1; + + if (irs->args.count > 0) { + if (irs->args.count > 1) { + error(irs->args[1], "#unroll only supports a single argument for the unroll per loop amount"); + } + Ast *arg = irs->args[0]; + if (arg->kind == Ast_FieldValue) { + error(arg, "#unroll does not yet support named arguments"); + arg = arg->FieldValue.value; + } + + Operand x = {}; + check_expr(ctx, &x, arg); + if (x.mode != Addressing_Constant || !is_type_integer(x.type)) { + gbString s = expr_to_string(x.expr); + error(x.expr, "Expected a constant integer for #unroll, got '%s'", s); + gb_string_free(s); + } else { + ExactValue value = exact_value_to_integer(x.value); + i64 v = exact_value_to_i64(value); + if (v < 1) { + error(x.expr, "Expected a constant integer >= 1 for #unroll, got %lld", cast(long long)v); + } else { + unroll_count = v; + if (v > 1024) { + error(x.expr, "Too large of a value for #unroll, got %lld, expected <= 1024", cast(long long)v); + } + } + + } + } + Ast *expr = unparen_expr(irs->expr); ExactValue inline_for_depth = exact_value_i64(0); @@ -946,18 +980,39 @@ gb_internal void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod val0 = t_rune; val1 = t_int; inline_for_depth = exact_value_i64(operand.value.value_string.len); + if (unroll_count > 0) { + error(node, "#unroll(%lld) does not support strings", cast(long long)unroll_count); + } } break; case Type_Array: val0 = t->Array.elem; val1 = t_int; - inline_for_depth = exact_value_i64(t->Array.count); + inline_for_depth = unroll_count > 0 ? exact_value_i64(unroll_count) : exact_value_i64(t->Array.count); break; case Type_EnumeratedArray: val0 = t->EnumeratedArray.elem; val1 = t->EnumeratedArray.index; + if (unroll_count > 0) { + error(node, "#unroll(%lld) does not support enumerated arrays", cast(long long)unroll_count); + } inline_for_depth = exact_value_i64(t->EnumeratedArray.count); break; + + case Type_Slice: + if (unroll_count > 0) { + val0 = t->Slice.elem; + val1 = t_int; + inline_for_depth = exact_value_i64(unroll_count); + } + break; + case Type_DynamicArray: + if (unroll_count > 0) { + val0 = t->DynamicArray.elem; + val1 = t_int; + inline_for_depth = exact_value_i64(unroll_count); + } + break; } } @@ -967,7 +1022,7 @@ gb_internal void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod error(operand.expr, "Cannot iterate over '%s' of type '%s' in an '#unroll for' statement", s, t); gb_string_free(t); gb_string_free(s); - } else if (operand.mode != Addressing_Constant) { + } else if (operand.mode != Addressing_Constant && unroll_count <= 0) { error(operand.expr, "An '#unroll for' expression must be known at compile time"); } } @@ -1050,8 +1105,6 @@ gb_internal void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod check_stmt(ctx, irs->body, mod_flags); - - check_close_scope(ctx); } gb_internal void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { @@ -1393,8 +1446,8 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ Ast *nil_seen = nullptr; - PtrSet<Type *> seen = {}; - defer (ptr_set_destroy(&seen)); + TypeSet seen = {}; + defer (type_set_destroy(&seen)); for (Ast *stmt : bs->stmts) { if (stmt->kind != Ast_CaseClause) { @@ -1462,7 +1515,7 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ GB_PANIC("Unknown type to type switch statement"); } - if (type_ptr_set_update(&seen, y.type)) { + if (type_set_update(&seen, y.type)) { TokenPos pos = cc->token.pos; gbString expr_str = expr_to_string(y.expr); error(y.expr, @@ -1516,7 +1569,7 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ auto unhandled = array_make<Type *>(temporary_allocator(), 0, variants.count); for (Type *t : variants) { - if (!type_ptr_set_exists(&seen, t)) { + if (!type_set_exists(&seen, t)) { array_add(&unhandled, t); } } @@ -2605,6 +2658,7 @@ gb_internal void check_for_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { if (cond && cond->kind == Ast_BinaryExpr && cond->BinaryExpr.left && cond->BinaryExpr.right && cond->BinaryExpr.op.kind == Token_GtEq && + type_of_expr(cond->BinaryExpr.left) != nullptr && is_type_unsigned(type_of_expr(cond->BinaryExpr.left)) && cond->BinaryExpr.right->tav.value.kind == ExactValue_Integer && is_exact_value_zero(cond->BinaryExpr.right->tav.value)) { @@ -2612,6 +2666,7 @@ gb_internal void check_for_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { } else if (cond && cond->kind == Ast_BinaryExpr && cond->BinaryExpr.left && cond->BinaryExpr.right && cond->BinaryExpr.op.kind == Token_LtEq && + type_of_expr(cond->BinaryExpr.right) != nullptr && is_type_unsigned(type_of_expr(cond->BinaryExpr.right)) && cond->BinaryExpr.left->tav.value.kind == ExactValue_Integer && is_exact_value_zero(cond->BinaryExpr.left->tav.value)) { @@ -2677,7 +2732,7 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) case_end; case_ast_node(irs, UnrollRangeStmt, node); - check_inline_range_stmt(ctx, node, mod_flags); + check_unroll_range_stmt(ctx, node, mod_flags); case_end; case_ast_node(ss, SwitchStmt, node); @@ -2700,6 +2755,47 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) if (ctx->decl) { ctx->decl->defer_used += 1; } + + // NOTE(bill): Handling errors/warnings + + Ast *stmt = ds->stmt; + Ast *original_stmt = stmt; + + bool is_singular = true; + while (is_singular && stmt->kind == Ast_BlockStmt) { + Ast *inner_stmt = nullptr; + for (Ast *s : stmt->BlockStmt.stmts) { + if (s->kind == Ast_EmptyStmt) { + continue; + } + if (inner_stmt != nullptr) { + is_singular = false; + break; + } + inner_stmt = s; + } + + if (inner_stmt != nullptr) { + stmt = inner_stmt; + } + } + if (!is_singular) { + stmt = original_stmt; + } + + switch (stmt->kind) { + case_ast_node(as, AssignStmt, stmt); + if (as->op.kind != Token_Eq) { + break; + } + for (Ast *lhs : as->lhs) { + Entity *e = entity_of_node(lhs); + if (e && e->flags & EntityFlag_Result) { + error(lhs, "Assignments to named return values within 'defer' will not affect the value that is returned"); + } + } + case_end; + } } case_end; |