diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index f702f5cdb..b43e0cf9f 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -286,6 +286,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) m_currentLValue->storeValue(*rightIntermediateType, _assignment.location()); else // compound assignment { + solAssert(binOp != Token::Exp, "Compound exp is not possible."); solAssert(leftType.isValueType(), "Compound operators only available for value types."); unsigned lvalueSize = m_currentLValue->sizeOnStack(); unsigned itemSize = _assignment.annotation().type->sizeOnStack(); @@ -452,7 +453,10 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) bool cleanupNeeded = cleanupNeededForOp(commonType->category(), c_op); TypePointer leftTargetType = commonType; - TypePointer rightTargetType = TokenTraits::isShiftOp(c_op) ? rightExpression.annotation().type->mobileType() : commonType; + TypePointer rightTargetType = + TokenTraits::isShiftOp(c_op) || c_op == Token::Exp ? + rightExpression.annotation().type->mobileType() : + commonType; solAssert(rightTargetType, ""); // for commutative operators, push the literal as late as possible to allow improved optimization @@ -474,6 +478,8 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) if (TokenTraits::isShiftOp(c_op)) // shift only cares about the signedness of both sides appendShiftOperatorCode(c_op, *leftTargetType, *rightTargetType); + else if (c_op == Token::Exp) + appendExpOperatorCode(*leftTargetType, *rightTargetType); else if (TokenTraits::isCompareOp(c_op)) appendCompareOperatorCode(c_op, *commonType); else @@ -2080,9 +2086,6 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token _operator, Type cons m_context << (c_isSigned ? Instruction::SMOD : Instruction::MOD); break; } - case Token::Exp: - m_context << Instruction::EXP; - break; default: solAssert(false, "Unknown arithmetic operator."); } @@ -2177,6 +2180,14 @@ void ExpressionCompiler::appendShiftOperatorCode(Token _operator, Type const& _v } } +void ExpressionCompiler::appendExpOperatorCode(Type const& _valueType, Type const& _exponentType) +{ + solAssert(_valueType.category() == Type::Category::Integer, ""); + solAssert(!dynamic_cast(_exponentType).isSigned(), ""); + + m_context << Instruction::EXP; +} + void ExpressionCompiler::appendExternalFunctionCall( FunctionType const& _functionType, vector> const& _arguments, diff --git a/libsolidity/codegen/ExpressionCompiler.h b/libsolidity/codegen/ExpressionCompiler.h index c0a703d78..7b574b59c 100644 --- a/libsolidity/codegen/ExpressionCompiler.h +++ b/libsolidity/codegen/ExpressionCompiler.h @@ -101,6 +101,7 @@ private: void appendArithmeticOperatorCode(Token _operator, Type const& _type); void appendBitOperatorCode(Token _operator); void appendShiftOperatorCode(Token _operator, Type const& _valueType, Type const& _shiftAmountType); + void appendExpOperatorCode(Type const& _valueType, Type const& _exponentType); /// @} /// Appends code to call a function of the given type with the given arguments. diff --git a/test/libsolidity/semanticTests/cleanup/exp_cleanup_smaller_base.sol b/test/libsolidity/semanticTests/cleanup/exp_cleanup_smaller_base.sol new file mode 100644 index 000000000..3ef61f219 --- /dev/null +++ b/test/libsolidity/semanticTests/cleanup/exp_cleanup_smaller_base.sol @@ -0,0 +1,11 @@ +contract C { + function f() public pure returns (uint16 x) { + // tests that ``e`` is not converted to uint8 + // right before the exp + uint16 e = 0x100; + uint8 b = 0x2; + return b**e; + } +} +// ---- +// f() -> 0x00