Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion libsolidity/analysis/ConstantEvaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,29 @@ TypedValue convertType(TypedValue const& _value, Type const& _type)
}, _value.value);
}

TypedValue cleanupValue(rational const& _value, Type const& _type)
{
if (_type.category() != Type::Category::Integer)
return convertType(_value, _type);

auto const* integerType = dynamic_cast<IntegerType const*>(&_type);
solAssert(integerType);

bigint integerValue = _value.numerator() / _value.denominator();

unsigned int numBits = integerType->numBits();
bigint mask = (bigint(1) << numBits) - 1;
bigint sign = bigint(1) << (numBits - 1);
// clean bits out of range
integerValue = integerValue & mask;

// extend sign if needed
if (integerType->isSigned() && (integerValue & sign))
integerValue = integerValue | ~mask;

return convertType(rational(integerValue), _type);
}

TypedValue constantToTypedValue(Type const& _type)
{
if (_type.category() == Type::Category::RationalNumber)
Expand Down Expand Up @@ -411,7 +434,9 @@ void ConstantEvaluator::endVisit(BinaryOperation const& _operation)
std::get<rational>(right.value)
))
{
TypedValue convertedValue = convertType(*value, *resultType);
TypedValue convertedValue = TokenTraits::isShiftOp(_operation.getOperator()) ?
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it could be done only for left shift.

cleanupValue(*value, *resultType) :
convertType(*value, *resultType);
if (!convertedValue.type)
m_errorReporter.fatalTypeError(
2643_error,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
contract C {
uint constant ONE = 1;
uint constant OVERFLOW = 2**255 << ONE;

uint[OVERFLOW + 1] a;

function testEquivalence() public view returns (bool) {
uint runTimeResult = 2**255 << ONE;
return OVERFLOW == runTimeResult;
}
}
// ----
// testEquivalence() -> true
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
uint8 constant UNSIGNED = 16;
int8 constant SIGNED = 16;
contract C {
// should be 0
uint8 constant public URESULT = UNSIGNED << 5;
int8 constant public SRESULT = SIGNED << 2;
// use as array length so constant values are evaluated in comptime
uint[URESULT + 1] a;
uint[SRESULT] b;

function testEquivalence() public view returns (bool) {
uint8 runTimeUResult = UNSIGNED << 5;
int8 runTimeSResult = SIGNED << 2;

return
URESULT == runTimeUResult &&
SRESULT == runTimeSResult
;
}
}
// ----
// testEquivalence() -> true
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
contract C {
int8 constant NEG = -63;
int8 constant POS = 63;
// should be 4 -> 1100 0001 << 2 = 0000 0100
int8 constant public NLEFT_OPERAND = NEG << 2;
// should be -4 -> 0011 1111 << 2 = 1111 1100
int8 constant public PLEFT_OPERAND = POS << 2;
// use as array length so constant values are evaluated in compTime
uint[NLEFT_OPERAND] a;
uint[PLEFT_OPERAND * -1] b;

function testEquivalence() public view returns (bool) {
int8 runTimeNResult = NEG << 2;
int8 runTimePResult = POS << 2;

return
NLEFT_OPERAND == runTimeNResult &&
PLEFT_OPERAND == runTimePResult
;
}
}
// ----
// testEquivalence() -> true