From b8b4f5e9f9a89eac1218551b5da322b41c7813f4 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi <alex@rtfs.hu> Date: Sat, 30 Apr 2016 00:15:22 +0100 Subject: Support bitshifting in variables --- libsolidity/ast/Types.cpp | 5 +++ libsolidity/codegen/ExpressionCompiler.cpp | 49 +++++++++++++++++++++++++----- libsolidity/codegen/ExpressionCompiler.h | 2 +- 3 files changed, 47 insertions(+), 9 deletions(-) (limited to 'libsolidity') diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index d9660bc0..6b4dd432 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -347,6 +347,11 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe // All integer types can be compared if (Token::isCompareOp(_operator)) return commonType; + // Disable >>> here. + if (_operator == Token::SHR) + return TypePointer(); + if (Token::isShiftOp(_operator) && !isAddress()) // && !_other->isAddress()) + return shared_from_this(); if (Token::isBooleanOp(_operator)) return TypePointer(); if (auto intType = dynamic_pointer_cast<IntegerType const>(commonType)) diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 5748d818..d28ffed8 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -211,6 +211,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) Token::Value op = _assignment.assignmentOperator(); if (op != Token::Assign) // compound assignment { + Token::Value target_op = Token::AssignmentToBinaryOp(op); solUnimplementedAssert(_assignment.annotation().type->isValueType(), "Compound operators not implemented for non-value types."); unsigned lvalueSize = m_currentLValue->sizeOnStack(); unsigned itemSize = _assignment.annotation().type->sizeOnStack(); @@ -221,7 +222,11 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) // value lvalue_ref value lvalue_ref } m_currentLValue->retrieveValue(_assignment.location(), true); - appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), *_assignment.annotation().type); + if (Token::isShiftOp(target_op)) + // shift only cares about the signedness of both sides + appendShiftOperatorCode(target_op, *_assignment.leftHandSide().annotation().type, *_assignment.rightHandSide().annotation().type); + else + appendOrdinaryBinaryOperatorCode(target_op, *_assignment.annotation().type); if (lvalueSize > 0) { solAssert(itemSize + lvalueSize <= 16, "Stack too deep, try removing local variables."); @@ -361,7 +366,7 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) else { bool cleanupNeeded = false; - if (Token::isCompareOp(c_op)) + if (Token::isCompareOp(c_op) || Token::isShiftOp(c_op)) cleanupNeeded = true; if (commonType.category() == Type::Category::Integer && (c_op == Token::Div || c_op == Token::Mod)) cleanupNeeded = true; @@ -386,7 +391,10 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) leftExpression.accept(*this); utils().convertType(*leftExpression.annotation().type, commonType, cleanupNeeded); } - if (Token::isCompareOp(c_op)) + if (Token::isShiftOp(c_op)) + // shift only cares about the signedness of both sides + appendShiftOperatorCode(c_op, *leftExpression.annotation().type, *rightExpression.annotation().type); + else if (Token::isCompareOp(c_op)) appendCompareOperatorCode(c_op, commonType); else appendOrdinaryBinaryOperatorCode(c_op, commonType); @@ -1326,8 +1334,6 @@ void ExpressionCompiler::appendOrdinaryBinaryOperatorCode(Token::Value _operator appendArithmeticOperatorCode(_operator, _type); else if (Token::isBitOp(_operator)) appendBitOperatorCode(_operator); - else if (Token::isShiftOp(_operator)) - appendShiftOperatorCode(_operator); else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown binary operator.")); } @@ -1390,17 +1396,44 @@ void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator) } } -void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator) +void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator, Type const& _leftType, Type const& _rightType) { - solUnimplemented("Shift operators not yet implemented."); + // stack: rvalue lvalue + + bool c_leftSigned = false; + if (auto leftType = dynamic_cast<IntegerType const*>(&_leftType)) + c_leftSigned = leftType->isSigned(); + else + solUnimplemented("Only IntegerType can be shifted."); + + // The RValue can be a RationalNumberType too. + bool c_rightSigned = false; + if (auto rightType = dynamic_cast<RationalNumberType const*>(&_rightType)) + { + solAssert(rightType->integerType(), "integerType() called for fractional number."); + c_rightSigned = rightType->integerType()->isSigned(); + } + else if (auto rightType = dynamic_cast<IntegerType const*>(&_rightType)) + c_rightSigned = rightType->isSigned(); + else + solUnimplemented("Not implemented yet - FixedPointType."); + + // shift with negative rvalue throws exception + if (c_rightSigned) + { + m_context << u256(0) << Instruction::DUP3 << Instruction::SLT; + m_context.appendConditionalJumpTo(m_context.errorTag()); + } + switch (_operator) { case Token::SHL: + m_context << Instruction::SWAP1 << u256(2) << Instruction::EXP << Instruction::MUL; break; case Token::SAR: + m_context << Instruction::SWAP1 << u256(2) << Instruction::EXP << Instruction::SWAP1 << (c_leftSigned ? Instruction::SDIV : Instruction::DIV); break; case Token::SHR: - break; default: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown shift operator.")); } diff --git a/libsolidity/codegen/ExpressionCompiler.h b/libsolidity/codegen/ExpressionCompiler.h index f08bded9..e6cf382c 100644 --- a/libsolidity/codegen/ExpressionCompiler.h +++ b/libsolidity/codegen/ExpressionCompiler.h @@ -91,7 +91,7 @@ private: void appendArithmeticOperatorCode(Token::Value _operator, Type const& _type); void appendBitOperatorCode(Token::Value _operator); - void appendShiftOperatorCode(Token::Value _operator); + void appendShiftOperatorCode(Token::Value _operator, Type const& _leftType, Type const& _rightType); /// @} /// Appends code to call a function of the given type with the given arguments. -- cgit v1.2.3 From 2df60bec923e1bac74cde00ae9bda641ca29d6c1 Mon Sep 17 00:00:00 2001 From: chriseth <c@ethdev.com> Date: Mon, 5 Dec 2016 18:40:50 +0100 Subject: Type after shift should be type of left operand. --- libsolidity/ast/Types.cpp | 47 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) (limited to 'libsolidity') diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 6b4dd432..896d51fa 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -340,6 +340,28 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe _other->category() != category() ) return TypePointer(); + if (Token::isShiftOp(_operator)) + { + // Disable >>> here. + if (_operator == Token::SHR) + return TypePointer(); + + // Shifts are not symmetric with respect to the type + if (isAddress()) + return TypePointer(); + if (IntegerType const* otherInt = dynamic_cast<decltype(otherInt)>(_other.get())) + { + if (!otherInt->isAddress()) + return shared_from_this(); + } + else if (RationalNumberType const* otherRat = dynamic_cast<decltype(otherRat)>(_other.get())) + { + if (!otherRat->isFractional()) + return shared_from_this(); + } + return TypePointer(); + } + auto commonType = Type::commonType(shared_from_this(), _other); //might be a integer or fixed point if (!commonType) return TypePointer(); @@ -347,11 +369,6 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe // All integer types can be compared if (Token::isCompareOp(_operator)) return commonType; - // Disable >>> here. - if (_operator == Token::SHR) - return TypePointer(); - if (Token::isShiftOp(_operator) && !isAddress()) // && !_other->isAddress()) - return shared_from_this(); if (Token::isBooleanOp(_operator)) return TypePointer(); if (auto intType = dynamic_pointer_cast<IntegerType const>(commonType)) @@ -959,6 +976,26 @@ TypePointer FixedBytesType::unaryOperatorResult(Token::Value _operator) const TypePointer FixedBytesType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const { + if (Token::isShiftOp(_operator)) + { + // Disable >>> here. + if (_operator == Token::SHR) + return TypePointer(); + + // Shifts are not symmetric with respect to the type + if (IntegerType const* otherInt = dynamic_cast<decltype(otherInt)>(_other.get())) + { + if (!otherInt->isAddress()) + return shared_from_this(); + } + else if (RationalNumberType const* otherRat = dynamic_cast<decltype(otherRat)>(_other.get())) + { + if (!otherRat->isFractional()) + return shared_from_this(); + } + return TypePointer(); + } + auto commonType = dynamic_pointer_cast<FixedBytesType const>(Type::commonType(shared_from_this(), _other)); if (!commonType) return TypePointer(); -- cgit v1.2.3 From 273804503096d8d5d0c9d1fcece48da871f2d90f Mon Sep 17 00:00:00 2001 From: chriseth <c@ethdev.com> Date: Tue, 6 Dec 2016 23:45:17 +0100 Subject: Cleaner shift handling and type conversion for binary operations. --- libsolidity/ast/Types.cpp | 50 +++++------- libsolidity/codegen/ExpressionCompiler.cpp | 119 ++++++++++++++++++----------- libsolidity/codegen/ExpressionCompiler.h | 6 +- 3 files changed, 100 insertions(+), 75 deletions(-) (limited to 'libsolidity') diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 896d51fa..03ff8471 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -251,6 +251,19 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition return members; } +bool isValidShiftAndAmountType(Token::Value _operator, Type const& _shiftAmountType) +{ + // Disable >>> here. + if (_operator == Token::SHR) + return false; + else if (IntegerType const* otherInt = dynamic_cast<decltype(otherInt)>(&_shiftAmountType)) + return !otherInt->isAddress(); + else if (RationalNumberType const* otherRat = dynamic_cast<decltype(otherRat)>(&_shiftAmountType)) + return otherRat->integerType() && !otherRat->integerType()->isSigned(); + else + return false; +} + IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier): m_bits(_bits), m_modifier(_modifier) { @@ -342,24 +355,13 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe return TypePointer(); if (Token::isShiftOp(_operator)) { - // Disable >>> here. - if (_operator == Token::SHR) - return TypePointer(); - // Shifts are not symmetric with respect to the type if (isAddress()) return TypePointer(); - if (IntegerType const* otherInt = dynamic_cast<decltype(otherInt)>(_other.get())) - { - if (!otherInt->isAddress()) - return shared_from_this(); - } - else if (RationalNumberType const* otherRat = dynamic_cast<decltype(otherRat)>(_other.get())) - { - if (!otherRat->isFractional()) - return shared_from_this(); - } - return TypePointer(); + if (isValidShiftAndAmountType(_operator, *_other)) + return shared_from_this(); + else + return TypePointer(); } auto commonType = Type::commonType(shared_from_this(), _other); //might be a integer or fixed point @@ -978,22 +980,10 @@ TypePointer FixedBytesType::binaryOperatorResult(Token::Value _operator, TypePoi { if (Token::isShiftOp(_operator)) { - // Disable >>> here. - if (_operator == Token::SHR) + if (isValidShiftAndAmountType(_operator, *_other)) + return shared_from_this(); + else return TypePointer(); - - // Shifts are not symmetric with respect to the type - if (IntegerType const* otherInt = dynamic_cast<decltype(otherInt)>(_other.get())) - { - if (!otherInt->isAddress()) - return shared_from_this(); - } - else if (RationalNumberType const* otherRat = dynamic_cast<decltype(otherRat)>(_other.get())) - { - if (!otherRat->isFractional()) - return shared_from_this(); - } - return TypePointer(); } auto commonType = dynamic_pointer_cast<FixedBytesType const>(Type::commonType(shared_from_this(), _other)); diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index d28ffed8..afe91c5c 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -197,22 +197,37 @@ bool ExpressionCompiler::visit(Conditional const& _condition) bool ExpressionCompiler::visit(Assignment const& _assignment) { CompilerContext::LocationSetter locationSetter(m_context, _assignment); + Token::Value op = _assignment.assignmentOperator(); + Token::Value binOp = op == Token::Assign ? op : Token::AssignmentToBinaryOp(op); + Type const& leftType = *_assignment.leftHandSide().annotation().type; + if (leftType.category() == Type::Category::Tuple) + { + solAssert(*_assignment.annotation().type == TupleType(), ""); + solAssert(op == Token::Assign, ""); + } + else + solAssert(*_assignment.annotation().type == leftType, ""); + bool cleanupNeeded = false; + if (op != Token::Assign) + cleanupNeeded = cleanupNeededForOp(leftType.category(), binOp); _assignment.rightHandSide().accept(*this); // Perform some conversion already. This will convert storage types to memory and literals // to their actual type, but will not convert e.g. memory to storage. - TypePointer type = _assignment.rightHandSide().annotation().type->closestTemporaryType( - _assignment.leftHandSide().annotation().type - ); - utils().convertType(*_assignment.rightHandSide().annotation().type, *type); + TypePointer rightIntermediateType; + if (op != Token::Assign && Token::isShiftOp(binOp)) + rightIntermediateType = _assignment.rightHandSide().annotation().type->mobileType(); + else + rightIntermediateType = _assignment.rightHandSide().annotation().type->closestTemporaryType( + _assignment.leftHandSide().annotation().type + ); + utils().convertType(*_assignment.rightHandSide().annotation().type, *rightIntermediateType, cleanupNeeded); _assignment.leftHandSide().accept(*this); solAssert(!!m_currentLValue, "LValue not retrieved."); - Token::Value op = _assignment.assignmentOperator(); if (op != Token::Assign) // compound assignment { - Token::Value target_op = Token::AssignmentToBinaryOp(op); - solUnimplementedAssert(_assignment.annotation().type->isValueType(), "Compound operators not implemented for non-value types."); + solAssert(leftType.isValueType(), "Compound operators only available for value types."); unsigned lvalueSize = m_currentLValue->sizeOnStack(); unsigned itemSize = _assignment.annotation().type->sizeOnStack(); if (lvalueSize > 0) @@ -222,11 +237,17 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) // value lvalue_ref value lvalue_ref } m_currentLValue->retrieveValue(_assignment.location(), true); - if (Token::isShiftOp(target_op)) - // shift only cares about the signedness of both sides - appendShiftOperatorCode(target_op, *_assignment.leftHandSide().annotation().type, *_assignment.rightHandSide().annotation().type); + utils().convertType(leftType, leftType, cleanupNeeded); + + Token::Value targetOp = Token::AssignmentToBinaryOp(op); + + if (Token::isShiftOp(targetOp)) + appendShiftOperatorCode(targetOp, leftType, *rightIntermediateType); else - appendOrdinaryBinaryOperatorCode(target_op, *_assignment.annotation().type); + { + solAssert(leftType == *rightIntermediateType, ""); + appendOrdinaryBinaryOperatorCode(targetOp, leftType); + } if (lvalueSize > 0) { solAssert(itemSize + lvalueSize <= 16, "Stack too deep, try removing local variables."); @@ -235,7 +256,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) m_context << swapInstruction(itemSize + lvalueSize) << Instruction::POP; } } - m_currentLValue->storeValue(*type, _assignment.location()); + m_currentLValue->storeValue(*rightIntermediateType, _assignment.location()); m_currentLValue.reset(); return false; } @@ -356,20 +377,19 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) Expression const& leftExpression = _binaryOperation.leftExpression(); Expression const& rightExpression = _binaryOperation.rightExpression(); solAssert(!!_binaryOperation.annotation().commonType, ""); - Type const& commonType = *_binaryOperation.annotation().commonType; + TypePointer const& commonType = _binaryOperation.annotation().commonType; Token::Value const c_op = _binaryOperation.getOperator(); if (c_op == Token::And || c_op == Token::Or) // special case: short-circuiting appendAndOrOperatorCode(_binaryOperation); - else if (commonType.category() == Type::Category::RationalNumber) - m_context << commonType.literalValue(nullptr); + else if (commonType->category() == Type::Category::RationalNumber) + m_context << commonType->literalValue(nullptr); else { - bool cleanupNeeded = false; - if (Token::isCompareOp(c_op) || Token::isShiftOp(c_op)) - cleanupNeeded = true; - if (commonType.category() == Type::Category::Integer && (c_op == Token::Div || c_op == Token::Mod)) - cleanupNeeded = true; + bool cleanupNeeded = cleanupNeededForOp(commonType->category(), c_op); + + TypePointer leftTargetType = commonType; + TypePointer rightTargetType = Token::isShiftOp(c_op) ? rightExpression.annotation().type->mobileType() : commonType; // for commutative operators, push the literal as late as possible to allow improved optimization auto isLiteral = [](Expression const& _e) @@ -380,24 +400,24 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) if (swap) { leftExpression.accept(*this); - utils().convertType(*leftExpression.annotation().type, commonType, cleanupNeeded); + utils().convertType(*leftExpression.annotation().type, *leftTargetType, cleanupNeeded); rightExpression.accept(*this); - utils().convertType(*rightExpression.annotation().type, commonType, cleanupNeeded); + utils().convertType(*rightExpression.annotation().type, *rightTargetType, cleanupNeeded); } else { rightExpression.accept(*this); - utils().convertType(*rightExpression.annotation().type, commonType, cleanupNeeded); + utils().convertType(*rightExpression.annotation().type, *rightTargetType, cleanupNeeded); leftExpression.accept(*this); - utils().convertType(*leftExpression.annotation().type, commonType, cleanupNeeded); + utils().convertType(*leftExpression.annotation().type, *leftTargetType, cleanupNeeded); } if (Token::isShiftOp(c_op)) // shift only cares about the signedness of both sides - appendShiftOperatorCode(c_op, *leftExpression.annotation().type, *rightExpression.annotation().type); + appendShiftOperatorCode(c_op, *leftTargetType, *rightTargetType); else if (Token::isCompareOp(c_op)) - appendCompareOperatorCode(c_op, commonType); + appendCompareOperatorCode(c_op, *commonType); else - appendOrdinaryBinaryOperatorCode(c_op, commonType); + appendOrdinaryBinaryOperatorCode(c_op, *commonType); } // do not visit the child nodes, we already did that explicitly @@ -1396,30 +1416,31 @@ void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator) } } -void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator, Type const& _leftType, Type const& _rightType) +void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator, Type const& _valueType, Type const& _shiftAmountType) { - // stack: rvalue lvalue + // stack: shift_amount value_to_shift - bool c_leftSigned = false; - if (auto leftType = dynamic_cast<IntegerType const*>(&_leftType)) - c_leftSigned = leftType->isSigned(); + bool c_valueSigned = false; + if (auto valueType = dynamic_cast<IntegerType const*>(&_valueType)) + c_valueSigned = valueType->isSigned(); else - solUnimplemented("Only IntegerType can be shifted."); + solAssert(dynamic_cast<FixedBytesType const*>(&_valueType), "Only integer and fixed bytes type supported for shifts."); - // The RValue can be a RationalNumberType too. - bool c_rightSigned = false; - if (auto rightType = dynamic_cast<RationalNumberType const*>(&_rightType)) + // The amount can be a RationalNumberType too. + bool c_amountSigned = false; + if (auto amountType = dynamic_cast<RationalNumberType const*>(&_shiftAmountType)) { - solAssert(rightType->integerType(), "integerType() called for fractional number."); - c_rightSigned = rightType->integerType()->isSigned(); + // This should be handled by the type checker. + solAssert(amountType->integerType(), ""); + solAssert(!amountType->integerType()->isSigned(), ""); } - else if (auto rightType = dynamic_cast<IntegerType const*>(&_rightType)) - c_rightSigned = rightType->isSigned(); + else if (auto amountType = dynamic_cast<IntegerType const*>(&_shiftAmountType)) + c_amountSigned = amountType->isSigned(); else - solUnimplemented("Not implemented yet - FixedPointType."); + solAssert(false, "Invalid shift amount type."); - // shift with negative rvalue throws exception - if (c_rightSigned) + // shift by negative amount throws exception + if (c_amountSigned) { m_context << u256(0) << Instruction::DUP3 << Instruction::SLT; m_context.appendConditionalJumpTo(m_context.errorTag()); @@ -1431,7 +1452,7 @@ void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator, Type co m_context << Instruction::SWAP1 << u256(2) << Instruction::EXP << Instruction::MUL; break; case Token::SAR: - m_context << Instruction::SWAP1 << u256(2) << Instruction::EXP << Instruction::SWAP1 << (c_leftSigned ? Instruction::SDIV : Instruction::DIV); + m_context << Instruction::SWAP1 << u256(2) << Instruction::EXP << Instruction::SWAP1 << (c_valueSigned ? Instruction::SDIV : Instruction::DIV); break; case Token::SHR: default: @@ -1721,6 +1742,16 @@ void ExpressionCompiler::setLValueToStorageItem(Expression const& _expression) setLValue<StorageItem>(_expression, *_expression.annotation().type); } +bool ExpressionCompiler::cleanupNeededForOp(Type::Category _type, Token::Value _op) +{ + if (Token::isCompareOp(_op) || Token::isShiftOp(_op)) + return true; + else if (_type == Type::Category::Integer && (_op == Token::Div || _op == Token::Mod)) + return true; + else + return false; +} + CompilerUtils ExpressionCompiler::utils() { return CompilerUtils(m_context); diff --git a/libsolidity/codegen/ExpressionCompiler.h b/libsolidity/codegen/ExpressionCompiler.h index e6cf382c..d0a8ac15 100644 --- a/libsolidity/codegen/ExpressionCompiler.h +++ b/libsolidity/codegen/ExpressionCompiler.h @@ -91,7 +91,7 @@ private: void appendArithmeticOperatorCode(Token::Value _operator, Type const& _type); void appendBitOperatorCode(Token::Value _operator); - void appendShiftOperatorCode(Token::Value _operator, Type const& _leftType, Type const& _rightType); + void appendShiftOperatorCode(Token::Value _operator, Type const& _valueType, Type const& _shiftAmountType); /// @} /// Appends code to call a function of the given type with the given arguments. @@ -117,6 +117,10 @@ private: template <class _LValueType, class... _Arguments> void setLValue(Expression const& _expression, _Arguments const&... _arguments); + /// @returns true if the operator applied to the given type requires a cleanup prior to the + /// operation. + bool cleanupNeededForOp(Type::Category _type, Token::Value _op); + /// @returns the CompilerUtils object containing the current context. CompilerUtils utils(); -- cgit v1.2.3 From e9d3327ad6883acc6db8306bb7fa5ccbd802af9c Mon Sep 17 00:00:00 2001 From: chriseth <c@ethdev.com> Date: Tue, 13 Dec 2016 16:50:50 +0100 Subject: Use correct type for storing. --- libsolidity/codegen/ExpressionCompiler.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'libsolidity') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index afe91c5c..a7fb8408 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -225,7 +225,9 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) _assignment.leftHandSide().accept(*this); solAssert(!!m_currentLValue, "LValue not retrieved."); - if (op != Token::Assign) // compound assignment + if (op == Token::Assign) + m_currentLValue->storeValue(*rightIntermediateType, _assignment.location()); + else // compound assignment { solAssert(leftType.isValueType(), "Compound operators only available for value types."); unsigned lvalueSize = m_currentLValue->sizeOnStack(); @@ -239,14 +241,12 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) m_currentLValue->retrieveValue(_assignment.location(), true); utils().convertType(leftType, leftType, cleanupNeeded); - Token::Value targetOp = Token::AssignmentToBinaryOp(op); - - if (Token::isShiftOp(targetOp)) - appendShiftOperatorCode(targetOp, leftType, *rightIntermediateType); + if (Token::isShiftOp(binOp)) + appendShiftOperatorCode(binOp, leftType, *rightIntermediateType); else { solAssert(leftType == *rightIntermediateType, ""); - appendOrdinaryBinaryOperatorCode(targetOp, leftType); + appendOrdinaryBinaryOperatorCode(binOp, leftType); } if (lvalueSize > 0) { @@ -255,8 +255,8 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) for (unsigned i = 0; i < itemSize; ++i) m_context << swapInstruction(itemSize + lvalueSize) << Instruction::POP; } + m_currentLValue->storeValue(*_assignment.annotation().type, _assignment.location()); } - m_currentLValue->storeValue(*rightIntermediateType, _assignment.location()); m_currentLValue.reset(); return false; } -- cgit v1.2.3