aboutsummaryrefslogtreecommitdiff
path: root/src/ir.cpp
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2018-02-08 21:54:44 -0500
committerAndrew Kelley <superjoe30@gmail.com>2018-02-08 21:54:44 -0500
commit54c06bf7158ce52c5de8d09f109215c467a3bf6a (patch)
tree1087306b7a45c59ad1072877f34f65efd6dc2a1c /src/ir.cpp
parent8fc6e31567057ca39466a34b63917f6f22f2c288 (diff)
downloadzig-54c06bf7158ce52c5de8d09f109215c467a3bf6a.tar.gz
zig-54c06bf7158ce52c5de8d09f109215c467a3bf6a.zip
error sets: runtime safety for int-to-err and err set cast
Diffstat (limited to 'src/ir.cpp')
-rw-r--r--src/ir.cpp50
1 files changed, 40 insertions, 10 deletions
diff --git a/src/ir.cpp b/src/ir.cpp
index 9cc05a2bc2..fa2815d6dd 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -8505,19 +8505,49 @@ static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *sourc
IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
source_instr->source_node, wanted_type);
- BigInt err_count;
- bigint_init_unsigned(&err_count, ira->codegen->errors_by_index.length);
- if (bigint_cmp_zero(&val->data.x_bigint) == CmpEQ || bigint_cmp(&val->data.x_bigint, &err_count) != CmpLT) {
- Buf *val_buf = buf_alloc();
- bigint_append_buf(val_buf, &val->data.x_bigint, 10);
- ir_add_error(ira, source_instr,
- buf_sprintf("integer value %s represents no error", buf_ptr(val_buf)));
+ if (!resolve_inferred_error_set(ira, wanted_type, source_instr->source_node)) {
return ira->codegen->invalid_instruction;
}
- size_t index = bigint_as_unsigned(&val->data.x_bigint);
- result->value.data.x_err_set = ira->codegen->errors_by_index.at(index);
- return result;
+ if (type_is_global_error_set(wanted_type)) {
+ BigInt err_count;
+ bigint_init_unsigned(&err_count, ira->codegen->errors_by_index.length);
+
+ if (bigint_cmp_zero(&val->data.x_bigint) == CmpEQ || bigint_cmp(&val->data.x_bigint, &err_count) != CmpLT) {
+ Buf *val_buf = buf_alloc();
+ bigint_append_buf(val_buf, &val->data.x_bigint, 10);
+ ir_add_error(ira, source_instr,
+ buf_sprintf("integer value %s represents no error", buf_ptr(val_buf)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ size_t index = bigint_as_unsigned(&val->data.x_bigint);
+ result->value.data.x_err_set = ira->codegen->errors_by_index.at(index);
+ return result;
+ } else {
+ ErrorTableEntry *err = nullptr;
+ BigInt err_int;
+
+ for (uint32_t i = 0, count = wanted_type->data.error_set.err_count; i < count; i += 1) {
+ ErrorTableEntry *this_err = wanted_type->data.error_set.errors[i];
+ bigint_init_unsigned(&err_int, this_err->value);
+ if (bigint_cmp(&val->data.x_bigint, &err_int) == CmpEQ) {
+ err = this_err;
+ break;
+ }
+ }
+
+ if (err == nullptr) {
+ Buf *val_buf = buf_alloc();
+ bigint_append_buf(val_buf, &val->data.x_bigint, 10);
+ ir_add_error(ira, source_instr,
+ buf_sprintf("integer value %s represents no error in '%s'", buf_ptr(val_buf), buf_ptr(&wanted_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ result->value.data.x_err_set = err;
+ return result;
+ }
}
IrInstruction *result = ir_build_int_to_err(&ira->new_irb, source_instr->scope, source_instr->source_node, target);