diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index 762ef264a645b0e5f86f5b1c962e2fc6fc316824..031811fc49d5feccc22b28b5fb9470d7549f05d4 100755 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -8011,10 +8011,10 @@ class NumBinopNode(BinopNode): return if self.type.is_complex: self.infix = False - if self.type.is_int and env.directives['overflowcheck'] and self.operator in ('+', '-', '*'): + if self.type.is_int and env.directives['overflowcheck'] and self.operator in self.overflow_op_names: self.overflow_check = True self.func = self.type.overflow_check_binop( - self.op_names[self.operator], + self.overflow_op_names[self.operator], env, const_rhs = self.operand2.has_constant_result()) self.is_temp = True @@ -8118,10 +8118,11 @@ class NumBinopNode(BinopNode): "**": "PyNumber_Power" } - op_names = { + overflow_op_names = { "+": "add", "-": "sub", "*": "mul", + "<<": "lshift", } class IntBinopNode(NumBinopNode): diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py index c0a51c0293d3f94e9a82400de0e68f64e7a1ed24..308fa303a7c386676aed0bcf8828bafbebe1965b 100755 --- a/Cython/Compiler/PyrexTypes.py +++ b/Cython/Compiler/PyrexTypes.py @@ -403,14 +403,17 @@ class CTypedefType(BaseType): return self.typedef_base_type.create_from_py_utility_code(env) def overflow_check_binop(self, binop, env, const_rhs=False): - if const_rhs: - binop += "_const" env.use_utility_code(UtilityCode.load("Common", "Overflow.c")) type = self.declaration_code("") name = self.specialization_name() - _load_overflow_base(env) - env.use_utility_code(TempitaUtilityCode.load("SizeCheck", "Overflow.c", context={'TYPE': type, 'NAME': name})) - env.use_utility_code(TempitaUtilityCode.load("Binop", "Overflow.c", context={'TYPE': type, 'NAME': name, 'BINOP': binop})) + if binop == "lshift": + env.use_utility_code(TempitaUtilityCode.load("LeftShift", "Overflow.c", context={'TYPE': type, 'NAME': name})) + else: + if const_rhs: + binop += "_const" + _load_overflow_base(env) + env.use_utility_code(TempitaUtilityCode.load("SizeCheck", "Overflow.c", context={'TYPE': type, 'NAME': name})) + env.use_utility_code(TempitaUtilityCode.load("Binop", "Overflow.c", context={'TYPE': type, 'NAME': name, 'BINOP': binop})) return "__Pyx_%s_%s_checking_overflow" % (binop, name) def error_condition(self, result_code): @@ -1563,19 +1566,22 @@ class CIntType(CNumericType): env.use_utility_code(UtilityCode.load("Common", "Overflow.c")) type = self.declaration_code("") name = self.specialization_name() - if const_rhs: - binop += "_const" - if type in ('int', 'long', 'long long'): - env.use_utility_code(TempitaUtilityCode.load("BaseCaseSigned", "Overflow.c", context={'INT': type, 'NAME': name})) - elif type in ('unsigned int', 'unsigned long', 'unsigned long long'): - env.use_utility_code(TempitaUtilityCode.load("BaseCaseUnsigned", "Overflow.c", context={'UINT': type, 'NAME': name})) - elif self.rank <= 1: - # sizeof(short) < sizeof(int) - return "__Pyx_%s_%s_no_overflow" % (binop, name) + if binop == "lshift": + env.use_utility_code(TempitaUtilityCode.load("LeftShift", "Overflow.c", context={'TYPE': type, 'NAME': name})) else: - _load_overflow_base(env) - env.use_utility_code(TempitaUtilityCode.load("SizeCheck", "Overflow.c", context={'TYPE': type, 'NAME': name})) - env.use_utility_code(TempitaUtilityCode.load("Binop", "Overflow.c", context={'TYPE': type, 'NAME': name, 'BINOP': binop})) + if const_rhs: + binop += "_const" + if type in ('int', 'long', 'long long'): + env.use_utility_code(TempitaUtilityCode.load("BaseCaseSigned", "Overflow.c", context={'INT': type, 'NAME': name})) + elif type in ('unsigned int', 'unsigned long', 'unsigned long long'): + env.use_utility_code(TempitaUtilityCode.load("BaseCaseUnsigned", "Overflow.c", context={'UINT': type, 'NAME': name})) + elif self.rank <= 1: + # sizeof(short) < sizeof(int) + return "__Pyx_%s_%s_no_overflow" % (binop, name) + else: + _load_overflow_base(env) + env.use_utility_code(TempitaUtilityCode.load("SizeCheck", "Overflow.c", context={'TYPE': type, 'NAME': name})) + env.use_utility_code(TempitaUtilityCode.load("Binop", "Overflow.c", context={'TYPE': type, 'NAME': name, 'BINOP': binop})) return "__Pyx_%s_%s_checking_overflow" % (binop, name) def _load_overflow_base(env): diff --git a/Cython/Utility/Overflow.c b/Cython/Utility/Overflow.c index 2b2f85087a98a31329f12a3f9215f08a69e5c977..23b44a9401672415e10fc1e3e7d99a75a93e95fb 100644 --- a/Cython/Utility/Overflow.c +++ b/Cython/Utility/Overflow.c @@ -268,3 +268,12 @@ static CYTHON_INLINE {{TYPE}} __Pyx_{{BINOP}}_{{NAME}}_checking_overflow({{TYPE} } } } + +/////////////// LeftShift.proto /////////////// + +static CYTHON_INLINE {{TYPE}} __Pyx_lshift_{{NAME}}_checking_overflow({{TYPE}} a, {{TYPE}} b, int *overflow) { + *overflow |= (b < 0) | (b > (8 * sizeof({{TYPE}}))) | (a > (__PYX_MAX({{TYPE}}) >> b)); + return a << b; +} +#define __Pyx_lshift_const_{{NAME}}_checking_overflow __Pyx_lshift_{{NAME}}_checking_overflow + diff --git a/tests/run/overflow_check.pxi b/tests/run/overflow_check.pxi index 9a6936b3e5702b38b4e81b72e93753e1b1b82e6f..1bf9610e5a4a246b9c9dcfe17d72add48aba55d4 100644 --- a/tests/run/overflow_check.pxi +++ b/tests/run/overflow_check.pxi @@ -206,3 +206,19 @@ def test_mul_const(INT a): True """ return int(a * <INT>100) + +@cython.overflowcheck(True) +def test_lshift(INT a, int b): + """ + >>> test_lshift(1, 10) + 1024 + >>> expect_overflow(test_lshift, 1, 100) + >>> expect_overflow(test_lshift, max_value, 1) + >>> test_lshift(max_value, 0) == max_value + True + + >>> check(test_lshift, operator.lshift, 10, 15) + >>> check(test_lshift, operator.lshift, 10, 30) + >>> check(test_lshift, operator.lshift, 100, 60) + """ + return int(a << b)