mirror of
https://github.com/odin-lang/Odin.git
synced 2026-02-15 07:43:13 +00:00
Also allow #no_bounds_check on an expression #499
This commit is contained in:
@@ -3052,7 +3052,7 @@ bool check_index_value(CheckerContext *c, bool open_range, Ast *index_value, i64
|
||||
}
|
||||
|
||||
if (operand.mode == Addressing_Constant &&
|
||||
(c->stmt_state_flags & StmtStateFlag_no_bounds_check) == 0) {
|
||||
(c->state_flags & StateFlag_no_bounds_check) == 0) {
|
||||
BigInt i = exact_value_to_integer(operand.value).value_integer;
|
||||
if (i.neg) {
|
||||
gbString expr_str = expr_to_string(operand.expr);
|
||||
@@ -6974,6 +6974,24 @@ bool check_range(CheckerContext *c, Ast *node, Operand *x, Operand *y, ExactValu
|
||||
|
||||
|
||||
ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) {
|
||||
u32 prev_state_flags = c->state_flags;
|
||||
defer (c->state_flags = prev_state_flags);
|
||||
if (node->state_flags != 0) {
|
||||
u32 in = node->state_flags;
|
||||
u32 out = c->state_flags;
|
||||
|
||||
if (in & StateFlag_no_bounds_check) {
|
||||
out |= StateFlag_no_bounds_check;
|
||||
out &= ~StateFlag_bounds_check;
|
||||
} else if (in & StateFlag_bounds_check) {
|
||||
out |= StateFlag_bounds_check;
|
||||
out &= ~StateFlag_no_bounds_check;
|
||||
}
|
||||
|
||||
c->state_flags = out;
|
||||
}
|
||||
|
||||
|
||||
ExprKind kind = Expr_Stmt;
|
||||
|
||||
o->mode = Addressing_Invalid;
|
||||
|
||||
@@ -335,27 +335,26 @@ Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs)
|
||||
|
||||
void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags);
|
||||
void check_stmt(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
u32 prev_stmt_state_flags = ctx->stmt_state_flags;
|
||||
u32 prev_state_flags = ctx->state_flags;
|
||||
|
||||
if (node->stmt_state_flags != 0) {
|
||||
u32 in = node->stmt_state_flags;
|
||||
u32 out = ctx->stmt_state_flags;
|
||||
if (node->state_flags != 0) {
|
||||
u32 in = node->state_flags;
|
||||
u32 out = ctx->state_flags;
|
||||
|
||||
if (in & StmtStateFlag_no_bounds_check) {
|
||||
out |= StmtStateFlag_no_bounds_check;
|
||||
out &= ~StmtStateFlag_bounds_check;
|
||||
} else {
|
||||
// if (in & StmtStateFlag_bounds_check) {
|
||||
out |= StmtStateFlag_bounds_check;
|
||||
out &= ~StmtStateFlag_no_bounds_check;
|
||||
if (in & StateFlag_no_bounds_check) {
|
||||
out |= StateFlag_no_bounds_check;
|
||||
out &= ~StateFlag_bounds_check;
|
||||
} else if (in & StateFlag_bounds_check) {
|
||||
out |= StateFlag_bounds_check;
|
||||
out &= ~StateFlag_no_bounds_check;
|
||||
}
|
||||
|
||||
ctx->stmt_state_flags = out;
|
||||
ctx->state_flags = out;
|
||||
}
|
||||
|
||||
check_stmt_internal(ctx, node, flags);
|
||||
|
||||
ctx->stmt_state_flags = prev_stmt_state_flags;
|
||||
ctx->state_flags = prev_state_flags;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -332,7 +332,7 @@ void check_open_scope(CheckerContext *c, Ast *node) {
|
||||
break;
|
||||
}
|
||||
c->scope = scope;
|
||||
c->stmt_state_flags |= StmtStateFlag_bounds_check;
|
||||
c->state_flags |= StateFlag_bounds_check;
|
||||
}
|
||||
|
||||
void check_close_scope(CheckerContext *c) {
|
||||
@@ -3766,11 +3766,11 @@ void check_proc_info(Checker *c, ProcInfo pi) {
|
||||
bool no_bounds_check = (pi.tags & ProcTag_no_bounds_check) != 0;
|
||||
|
||||
if (bounds_check) {
|
||||
ctx.stmt_state_flags |= StmtStateFlag_bounds_check;
|
||||
ctx.stmt_state_flags &= ~StmtStateFlag_no_bounds_check;
|
||||
ctx.state_flags |= StateFlag_bounds_check;
|
||||
ctx.state_flags &= ~StateFlag_no_bounds_check;
|
||||
} else if (no_bounds_check) {
|
||||
ctx.stmt_state_flags |= StmtStateFlag_no_bounds_check;
|
||||
ctx.stmt_state_flags &= ~StmtStateFlag_bounds_check;
|
||||
ctx.state_flags |= StateFlag_no_bounds_check;
|
||||
ctx.state_flags &= ~StateFlag_bounds_check;
|
||||
}
|
||||
|
||||
check_proc_body(&ctx, pi.token, pi.decl, pi.type, pi.body);
|
||||
|
||||
@@ -265,7 +265,7 @@ struct CheckerContext {
|
||||
Scope * scope;
|
||||
DeclInfo * decl;
|
||||
|
||||
u32 stmt_state_flags;
|
||||
u32 state_flags;
|
||||
bool in_defer; // TODO(bill): Actually handle correctly
|
||||
Type * type_hint;
|
||||
|
||||
|
||||
70
src/ir.cpp
70
src/ir.cpp
@@ -12,7 +12,7 @@ struct irModule {
|
||||
gbAllocator tmp_allocator;
|
||||
bool generate_debug_info;
|
||||
|
||||
u64 stmt_state_flags;
|
||||
u64 state_flags;
|
||||
|
||||
// String source_filename;
|
||||
String layout;
|
||||
@@ -5968,7 +5968,7 @@ void ir_emit_bounds_check(irProcedure *proc, Token token, irValue *index, irValu
|
||||
if (build_context.no_bounds_check) {
|
||||
return;
|
||||
}
|
||||
if ((proc->module->stmt_state_flags & StmtStateFlag_no_bounds_check) != 0) {
|
||||
if ((proc->module->state_flags & StateFlag_no_bounds_check) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5995,7 +5995,7 @@ void ir_emit_slice_bounds_check(irProcedure *proc, Token token, irValue *low, ir
|
||||
if (build_context.no_bounds_check) {
|
||||
return;
|
||||
}
|
||||
if ((proc->module->stmt_state_flags & StmtStateFlag_no_bounds_check) != 0) {
|
||||
if ((proc->module->state_flags & StateFlag_no_bounds_check) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -6034,7 +6034,7 @@ void ir_emit_dynamic_array_bounds_check(irProcedure *proc, Token token, irValue
|
||||
if (build_context.no_bounds_check) {
|
||||
return;
|
||||
}
|
||||
if ((proc->module->stmt_state_flags & StmtStateFlag_no_bounds_check) != 0) {
|
||||
if ((proc->module->state_flags & StateFlag_no_bounds_check) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -6905,6 +6905,24 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu
|
||||
irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr);
|
||||
|
||||
irValue *ir_build_expr(irProcedure *proc, Ast *expr) {
|
||||
u64 prev_state_flags = proc->module->state_flags;
|
||||
defer (proc->module->state_flags = prev_state_flags);
|
||||
|
||||
if (expr->state_flags != 0) {
|
||||
u64 in = expr->state_flags;
|
||||
u64 out = proc->module->state_flags;
|
||||
|
||||
if (in & StateFlag_bounds_check) {
|
||||
out |= StateFlag_bounds_check;
|
||||
out &= ~StateFlag_no_bounds_check;
|
||||
} else if (in & StateFlag_no_bounds_check) {
|
||||
out |= StateFlag_no_bounds_check;
|
||||
out &= ~StateFlag_bounds_check;
|
||||
}
|
||||
|
||||
proc->module->state_flags = out;
|
||||
}
|
||||
|
||||
irValue *v = ir_build_expr_internal(proc, expr);
|
||||
return v;
|
||||
}
|
||||
@@ -8857,28 +8875,28 @@ void ir_build_stmt_list(irProcedure *proc, Array<Ast *> stmts) {
|
||||
|
||||
void ir_build_stmt_internal(irProcedure *proc, Ast *node);
|
||||
void ir_build_stmt(irProcedure *proc, Ast *node) {
|
||||
u64 prev_stmt_state_flags = proc->module->stmt_state_flags;
|
||||
u64 prev_state_flags = proc->module->state_flags;
|
||||
defer (proc->module->state_flags = prev_state_flags);
|
||||
|
||||
if (node->stmt_state_flags != 0) {
|
||||
u64 in = node->stmt_state_flags;
|
||||
u64 out = proc->module->stmt_state_flags;
|
||||
if (node->state_flags != 0) {
|
||||
u64 in = node->state_flags;
|
||||
u64 out = proc->module->state_flags;
|
||||
|
||||
if (in & StmtStateFlag_bounds_check) {
|
||||
out |= StmtStateFlag_bounds_check;
|
||||
out &= ~StmtStateFlag_no_bounds_check;
|
||||
} else if (in & StmtStateFlag_no_bounds_check) {
|
||||
out |= StmtStateFlag_no_bounds_check;
|
||||
out &= ~StmtStateFlag_bounds_check;
|
||||
if (in & StateFlag_bounds_check) {
|
||||
out |= StateFlag_bounds_check;
|
||||
out &= ~StateFlag_no_bounds_check;
|
||||
} else if (in & StateFlag_no_bounds_check) {
|
||||
out |= StateFlag_no_bounds_check;
|
||||
out &= ~StateFlag_bounds_check;
|
||||
}
|
||||
|
||||
proc->module->stmt_state_flags = out;
|
||||
proc->module->state_flags = out;
|
||||
}
|
||||
|
||||
ir_push_debug_location(proc->module, node, proc->debug_scope);
|
||||
ir_build_stmt_internal(proc, node);
|
||||
ir_pop_debug_location(proc->module);
|
||||
|
||||
proc->module->stmt_state_flags = prev_stmt_state_flags;
|
||||
}
|
||||
|
||||
void ir_build_when_stmt(irProcedure *proc, AstWhenStmt *ws) {
|
||||
@@ -10483,19 +10501,19 @@ void ir_build_proc(irValue *value, irProcedure *parent) {
|
||||
proc->parent = parent;
|
||||
|
||||
if (proc->body != nullptr) {
|
||||
u64 prev_stmt_state_flags = proc->module->stmt_state_flags;
|
||||
u64 prev_state_flags = proc->module->state_flags;
|
||||
|
||||
if (proc->tags != 0) {
|
||||
u64 in = proc->tags;
|
||||
u64 out = proc->module->stmt_state_flags;
|
||||
u64 out = proc->module->state_flags;
|
||||
if (in & ProcTag_bounds_check) {
|
||||
out |= StmtStateFlag_bounds_check;
|
||||
out &= ~StmtStateFlag_no_bounds_check;
|
||||
out |= StateFlag_bounds_check;
|
||||
out &= ~StateFlag_no_bounds_check;
|
||||
} else if (in & ProcTag_no_bounds_check) {
|
||||
out |= StmtStateFlag_no_bounds_check;
|
||||
out &= ~StmtStateFlag_bounds_check;
|
||||
out |= StateFlag_no_bounds_check;
|
||||
out &= ~StateFlag_bounds_check;
|
||||
}
|
||||
proc->module->stmt_state_flags = out;
|
||||
proc->module->state_flags = out;
|
||||
}
|
||||
|
||||
ir_begin_procedure_body(proc);
|
||||
@@ -10503,7 +10521,7 @@ void ir_build_proc(irValue *value, irProcedure *parent) {
|
||||
ir_build_stmt(proc, proc->body);
|
||||
ir_end_procedure_body(proc);
|
||||
|
||||
proc->module->stmt_state_flags = prev_stmt_state_flags;
|
||||
proc->module->state_flags = prev_state_flags;
|
||||
}
|
||||
|
||||
// NOTE(lachsinc): For now we pop the debug location inside ir_end_procedure_body().
|
||||
@@ -10592,8 +10610,8 @@ void ir_init_module(irModule *m, Checker *c) {
|
||||
map_init(&m->constant_value_to_global, heap_allocator());
|
||||
|
||||
// Default states
|
||||
m->stmt_state_flags = 0;
|
||||
m->stmt_state_flags |= StmtStateFlag_bounds_check;
|
||||
m->state_flags = 0;
|
||||
m->state_flags |= StateFlag_bounds_check;
|
||||
|
||||
{
|
||||
// Add type info data
|
||||
|
||||
@@ -1727,7 +1727,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
syntax_error(operand, "#no_deferred can only be applied to procedure calls");
|
||||
operand = ast_bad_expr(f, token, f->curr_token);
|
||||
}
|
||||
operand->stmt_state_flags |= StmtStateFlag_no_deferred;
|
||||
operand->state_flags |= StateFlag_no_deferred;
|
||||
} */ else if (name.string == "file") {
|
||||
return ast_basic_directive(f, token, name.string);
|
||||
} else if (name.string == "line") { return ast_basic_directive(f, token, name.string);
|
||||
@@ -1757,6 +1757,20 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
break;
|
||||
}
|
||||
return original_type;
|
||||
} else if (name.string == "bounds_check") {
|
||||
Ast *operand = parse_expr(f, lhs);
|
||||
operand->state_flags |= StateFlag_bounds_check;
|
||||
if ((operand->state_flags & StateFlag_no_bounds_check) != 0) {
|
||||
syntax_error(token, "#bounds_check and #no_bounds_check cannot be applied together");
|
||||
}
|
||||
return operand;
|
||||
} else if (name.string == "no_bounds_check") {
|
||||
Ast *operand = parse_expr(f, lhs);
|
||||
operand->state_flags |= StateFlag_no_bounds_check;
|
||||
if ((operand->state_flags & StateFlag_bounds_check) != 0) {
|
||||
syntax_error(token, "#bounds_check and #no_bounds_check cannot be applied together");
|
||||
}
|
||||
return operand;
|
||||
} else {
|
||||
operand = ast_tag_expr(f, token, name, parse_expr(f, false));
|
||||
}
|
||||
@@ -4025,15 +4039,15 @@ Ast *parse_stmt(AstFile *f) {
|
||||
|
||||
if (tag == "bounds_check") {
|
||||
s = parse_stmt(f);
|
||||
s->stmt_state_flags |= StmtStateFlag_bounds_check;
|
||||
if ((s->stmt_state_flags & StmtStateFlag_no_bounds_check) != 0) {
|
||||
s->state_flags |= StateFlag_bounds_check;
|
||||
if ((s->state_flags & StateFlag_no_bounds_check) != 0) {
|
||||
syntax_error(token, "#bounds_check and #no_bounds_check cannot be applied together");
|
||||
}
|
||||
return s;
|
||||
} else if (tag == "no_bounds_check") {
|
||||
s = parse_stmt(f);
|
||||
s->stmt_state_flags |= StmtStateFlag_no_bounds_check;
|
||||
if ((s->stmt_state_flags & StmtStateFlag_bounds_check) != 0) {
|
||||
s->state_flags |= StateFlag_no_bounds_check;
|
||||
if ((s->state_flags & StateFlag_bounds_check) != 0) {
|
||||
syntax_error(token, "#bounds_check and #no_bounds_check cannot be applied together");
|
||||
}
|
||||
return s;
|
||||
|
||||
@@ -184,11 +184,11 @@ enum ProcCallingConvention {
|
||||
ProcCC_ForeignBlockDefault = -1,
|
||||
};
|
||||
|
||||
enum StmtStateFlag {
|
||||
StmtStateFlag_bounds_check = 1<<0,
|
||||
StmtStateFlag_no_bounds_check = 1<<1,
|
||||
enum StateFlag {
|
||||
StateFlag_bounds_check = 1<<0,
|
||||
StateFlag_no_bounds_check = 1<<1,
|
||||
|
||||
StmtStateFlag_no_deferred = 1<<5,
|
||||
StateFlag_no_deferred = 1<<5,
|
||||
};
|
||||
|
||||
enum ViralStateFlag {
|
||||
@@ -573,7 +573,7 @@ isize const ast_variant_sizes[] = {
|
||||
|
||||
struct Ast {
|
||||
AstKind kind;
|
||||
u32 stmt_state_flags;
|
||||
u32 state_flags;
|
||||
u32 viral_state_flags;
|
||||
bool been_handled;
|
||||
AstFile * file;
|
||||
|
||||
Reference in New Issue
Block a user