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