diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-03-11 14:22:40 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-03-11 14:22:40 -0400 |
| commit | 51c6bb92b1c0c02b214ae21986dce3f2e9960099 (patch) | |
| tree | 58d7865a9829233fa789fc1a9a4946c66d38d89e /src/ir.cpp | |
| parent | 83f6f730cdd5bb9c2a12b30c0aac33d858a1eaa8 (diff) | |
| parent | 2f1052a313cb09f87f04cef56805c33be62eb169 (diff) | |
| download | zig-51c6bb92b1c0c02b214ae21986dce3f2e9960099.tar.gz zig-51c6bb92b1c0c02b214ae21986dce3f2e9960099.zip | |
Merge pull request #4709 from LemonBoy/implement-2096
Stricter shift left/right safety checks
Diffstat (limited to 'src/ir.cpp')
| -rw-r--r-- | src/ir.cpp | 68 |
1 files changed, 41 insertions, 27 deletions
diff --git a/src/ir.cpp b/src/ir.cpp index e5b28f84c2..bb2dc75c64 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -16635,49 +16635,69 @@ static IrInstGen *ir_analyze_bit_shift(IrAnalyze *ira, IrInstSrcBinOp *bin_op_in IrInstGen *casted_op2; IrBinOp op_id = bin_op_instruction->op_id; if (op1->value->type->id == ZigTypeIdComptimeInt) { + // comptime_int has no finite bit width casted_op2 = op2; if (op_id == IrBinOpBitShiftLeftLossy) { op_id = IrBinOpBitShiftLeftExact; } - if (casted_op2->value->data.x_bigint.is_negative) { + if (!instr_is_comptime(op2)) { + ir_add_error(ira, &bin_op_instruction->base.base, + buf_sprintf("LHS of shift must be an integer type, or RHS must be compile-time known")); + return ira->codegen->invalid_inst_gen; + } + + ZigValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad); + if (op2_val == nullptr) + return ira->codegen->invalid_inst_gen; + + if (op2_val->data.x_bigint.is_negative) { Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &casted_op2->value->data.x_bigint, 10); - ir_add_error(ira, &casted_op2->base, buf_sprintf("shift by negative value %s", buf_ptr(val_buf))); + bigint_append_buf(val_buf, &op2_val->data.x_bigint, 10); + ir_add_error(ira, &casted_op2->base, + buf_sprintf("shift by negative value %s", buf_ptr(val_buf))); return ira->codegen->invalid_inst_gen; } } else { + const unsigned bit_count = op1->value->type->data.integral.bit_count; ZigType *shift_amt_type = get_smallest_unsigned_int_type(ira->codegen, - op1->value->type->data.integral.bit_count - 1); - if (bin_op_instruction->op_id == IrBinOpBitShiftLeftLossy && - op2->value->type->id == ZigTypeIdComptimeInt) { + bit_count > 0 ? bit_count - 1 : 0); - ZigValue *op2_val = ir_resolve_const(ira, op2, UndefBad); + casted_op2 = ir_implicit_cast(ira, op2, shift_amt_type); + if (type_is_invalid(casted_op2->value->type)) + return ira->codegen->invalid_inst_gen; + + // This check is only valid iff op1 has at least one bit + if (bit_count > 0 && instr_is_comptime(casted_op2)) { + ZigValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad); if (op2_val == nullptr) return ira->codegen->invalid_inst_gen; - if (!bigint_fits_in_bits(&op2_val->data.x_bigint, - shift_amt_type->data.integral.bit_count, - op2_val->data.x_bigint.is_negative)) { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &op2_val->data.x_bigint, 10); + + BigInt bit_count_value = {0}; + bigint_init_unsigned(&bit_count_value, bit_count); + + if (bigint_cmp(&op2_val->data.x_bigint, &bit_count_value) != CmpLT) { ErrorMsg* msg = ir_add_error(ira, &bin_op_instruction->base.base, buf_sprintf("RHS of shift is too large for LHS type")); - add_error_note( - ira->codegen, - msg, - op2->base.source_node, - buf_sprintf("value %s cannot fit into type %s", - buf_ptr(val_buf), - buf_ptr(&shift_amt_type->name))); + add_error_note(ira->codegen, msg, op1->base.source_node, + buf_sprintf("type %s has only %u bits", + buf_ptr(&op1->value->type->name), bit_count)); + return ira->codegen->invalid_inst_gen; } } + } - casted_op2 = ir_implicit_cast(ira, op2, shift_amt_type); - if (type_is_invalid(casted_op2->value->type)) + // Fast path for zero RHS + if (instr_is_comptime(casted_op2)) { + ZigValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad); + if (op2_val == nullptr) return ira->codegen->invalid_inst_gen; + + if (bigint_cmp_zero(&op2_val->data.x_bigint) == CmpEQ) + return ir_analyze_cast(ira, &bin_op_instruction->base.base, op1->value->type, op1); } if (instr_is_comptime(op1) && instr_is_comptime(casted_op2)) { @@ -16690,12 +16710,6 @@ static IrInstGen *ir_analyze_bit_shift(IrAnalyze *ira, IrInstSrcBinOp *bin_op_in return ira->codegen->invalid_inst_gen; return ir_analyze_math_op(ira, &bin_op_instruction->base.base, op1->value->type, op1_val, op_id, op2_val); - } else if (op1->value->type->id == ZigTypeIdComptimeInt) { - ir_add_error(ira, &bin_op_instruction->base.base, - buf_sprintf("LHS of shift must be an integer type, or RHS must be compile-time known")); - return ira->codegen->invalid_inst_gen; - } else if (instr_is_comptime(casted_op2) && bigint_cmp_zero(&casted_op2->value->data.x_bigint) == CmpEQ) { - return ir_build_cast(ira, &bin_op_instruction->base.base, op1->value->type, op1, CastOpNoop); } return ir_build_bin_op_gen(ira, &bin_op_instruction->base.base, op1->value->type, |
