aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchriseth <chris@ethereum.org>2018-09-06 03:40:49 +0800
committerGitHub <noreply@github.com>2018-09-06 03:40:49 +0800
commit08a7a51f071e2ef30db011fb36d505c7615785ec (patch)
tree603e8a79d31e552c9e308a87e3d90f3fcccb854d
parent9cb72fe6ca0260e465ed3a1700cc4a890480df4f (diff)
parent87804b6419a5894601441efe511015adda5fb119 (diff)
downloaddexon-solidity-08a7a51f071e2ef30db011fb36d505c7615785ec.tar.gz
dexon-solidity-08a7a51f071e2ef30db011fb36d505c7615785ec.tar.zst
dexon-solidity-08a7a51f071e2ef30db011fb36d505c7615785ec.zip
Merge pull request #4887 from ethereum/addressSplit
Split IntegerType into IntegerType and AddressType.
-rw-r--r--Changelog.md1
-rw-r--r--libsolidity/analysis/TypeChecker.cpp4
-rw-r--r--libsolidity/analysis/ViewPureChecker.cpp2
-rw-r--r--libsolidity/ast/Types.cpp131
-rw-r--r--libsolidity/ast/Types.h44
-rw-r--r--libsolidity/codegen/ABIFunctions.cpp27
-rw-r--r--libsolidity/codegen/CompilerUtils.cpp27
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp15
-rw-r--r--libsolidity/formal/SMTChecker.cpp5
-rw-r--r--libsolidity/formal/SSAVariable.cpp2
-rw-r--r--libsolidity/formal/SymbolicIntVariable.cpp14
-rw-r--r--test/compilationTests/zeppelin/token/VestedToken.sol4
12 files changed, 174 insertions, 102 deletions
diff --git a/Changelog.md b/Changelog.md
index 8760b818..14a362be 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -86,6 +86,7 @@ Compiler Features:
* C API (``libsolc``): Export the ``solidity_license``, ``solidity_version`` and ``solidity_compile`` methods.
* Type Checker: Nicer error message when trying to reference overloaded identifiers in inline assembly.
* Type Checker: Show named argument in case of error.
+ * Type System: IntegerType is split into IntegerType and AddressType internally.
* Tests: Determine transaction status during IPC calls.
* Code Generator: Allocate and free local variables according to their scope.
* Removed ``pragma experimental "v0.5.0";``.
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index a2b72896..a3f4459e 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -2103,7 +2103,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
"after argument-dependent lookup in " + exprType->toString() +
(memberName == "value" ? " - did you forget the \"payable\" modifier?" : ".");
if (exprType->category() == Type::Category::Contract)
- for (auto const& addressMember: IntegerType(160, IntegerType::Modifier::Address).nativeMembers(nullptr))
+ for (auto const& addressMember: AddressType().nativeMembers(nullptr))
if (addressMember.name == memberName)
{
Identifier const* var = dynamic_cast<Identifier const*>(&_memberAccess.expression());
@@ -2353,7 +2353,7 @@ void TypeChecker::endVisit(Literal const& _literal)
if (_literal.looksLikeAddress())
{
// Assign type here if it even looks like an address. This prevents double errors for invalid addresses
- _literal.annotation().type = make_shared<IntegerType>(160, IntegerType::Modifier::Address);
+ _literal.annotation().type = make_shared<AddressType>();
string msg;
if (_literal.value().length() != 42) // "0x" + 40 hex digits
diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp
index be6b7ef7..113a3177 100644
--- a/libsolidity/analysis/ViewPureChecker.cpp
+++ b/libsolidity/analysis/ViewPureChecker.cpp
@@ -323,7 +323,7 @@ void ViewPureChecker::endVisit(MemberAccess const& _memberAccess)
ASTString const& member = _memberAccess.memberName();
switch (_memberAccess.expression().annotation().type->category())
{
- case Type::Category::Integer:
+ case Type::Category::Address:
if (member == "balance")
mutability = StateMutability::View;
break;
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index a6867dcb..a302203b 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -299,7 +299,7 @@ TypePointer Type::fromElementaryTypeName(ElementaryTypeNameToken const& _type)
case Token::Byte:
return make_shared<FixedBytesType>(1);
case Token::Address:
- return make_shared<IntegerType>(160, IntegerType::Modifier::Address);
+ return make_shared<AddressType>();
case Token::Bool:
return make_shared<BoolType>();
case Token::Bytes:
@@ -439,6 +439,59 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition
return members;
}
+string AddressType::richIdentifier() const
+{
+ return "t_address";
+}
+
+bool AddressType::isExplicitlyConvertibleTo(Type const& _convertTo) const
+{
+ return isImplicitlyConvertibleTo(_convertTo) ||
+ _convertTo.category() == Category::Contract ||
+ _convertTo.category() == Category::Integer ||
+ (_convertTo.category() == Category::FixedBytes && 160 == dynamic_cast<FixedBytesType const&>(_convertTo).numBytes() * 8);
+}
+
+string AddressType::toString(bool) const
+{
+ return "address";
+}
+
+u256 AddressType::literalValue(Literal const* _literal) const
+{
+ solAssert(_literal, "");
+ solAssert(_literal->value().substr(0, 2) == "0x", "");
+ return u256(_literal->value());
+}
+
+TypePointer AddressType::unaryOperatorResult(Token::Value _operator) const
+{
+ return _operator == Token::Delete ? make_shared<TupleType>() : TypePointer();
+}
+
+
+TypePointer AddressType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
+{
+ // Addresses can only be compared.
+ if (!Token::isCompareOp(_operator))
+ return TypePointer();
+
+ return Type::commonType(shared_from_this(), _other);
+}
+
+MemberList::MemberMap AddressType::nativeMembers(ContractDefinition const*) const
+{
+ return {
+ {"balance", make_shared<IntegerType>(256)},
+ {"call", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCall, false, StateMutability::Payable)},
+ {"callcode", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCallCode, false, StateMutability::Payable)},
+ {"delegatecall", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareDelegateCall, false)},
+ {"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send)},
+ {"staticcall", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareStaticCall, false, StateMutability::View)},
+ {"transfer", make_shared<FunctionType>(strings{"uint"}, strings(), FunctionType::Kind::Transfer)}
+ };
+}
+
namespace
{
@@ -448,7 +501,7 @@ bool isValidShiftAndAmountType(Token::Value _operator, Type const& _shiftAmountT
if (_operator == Token::SHR)
return false;
else if (IntegerType const* otherInt = dynamic_cast<decltype(otherInt)>(&_shiftAmountType))
- return !otherInt->isAddress();
+ return true;
else if (RationalNumberType const* otherRat = dynamic_cast<decltype(otherRat)>(&_shiftAmountType))
return !otherRat->isFractional() && otherRat->integerType() && !otherRat->integerType()->isSigned();
else
@@ -460,8 +513,6 @@ bool isValidShiftAndAmountType(Token::Value _operator, Type const& _shiftAmountT
IntegerType::IntegerType(unsigned _bits, IntegerType::Modifier _modifier):
m_bits(_bits), m_modifier(_modifier)
{
- if (isAddress())
- solAssert(m_bits == 160, "");
solAssert(
m_bits > 0 && m_bits <= 256 && m_bits % 8 == 0,
"Invalid bit number for integer type: " + dev::toString(m_bits)
@@ -470,10 +521,7 @@ IntegerType::IntegerType(unsigned _bits, IntegerType::Modifier _modifier):
string IntegerType::richIdentifier() const
{
- if (isAddress())
- return "t_address";
- else
- return "t_" + string(isSigned() ? "" : "u") + "int" + to_string(numBits());
+ return "t_" + string(isSigned() ? "" : "u") + "int" + to_string(numBits());
}
bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
@@ -483,8 +531,6 @@ bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
IntegerType const& convertTo = dynamic_cast<IntegerType const&>(_convertTo);
if (convertTo.m_bits < m_bits)
return false;
- if (isAddress())
- return convertTo.isAddress();
else if (isSigned())
return convertTo.isSigned();
else
@@ -493,11 +539,7 @@ bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
else if (_convertTo.category() == Category::FixedPoint)
{
FixedPointType const& convertTo = dynamic_cast<FixedPointType const&>(_convertTo);
-
- if (isAddress())
- return false;
- else
- return maxValue() <= convertTo.maxIntegerValue() && minValue() >= convertTo.minIntegerValue();
+ return maxValue() <= convertTo.maxIntegerValue() && minValue() >= convertTo.minIntegerValue();
}
else
return false;
@@ -506,6 +548,7 @@ bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
return _convertTo.category() == category() ||
+ _convertTo.category() == Category::Address ||
_convertTo.category() == Category::Contract ||
_convertTo.category() == Category::Enum ||
(_convertTo.category() == Category::FixedBytes && numBits() == dynamic_cast<FixedBytesType const&>(_convertTo).numBytes() * 8) ||
@@ -517,10 +560,7 @@ TypePointer IntegerType::unaryOperatorResult(Token::Value _operator) const
// "delete" is ok for all integer types
if (_operator == Token::Delete)
return make_shared<TupleType>();
- // no further unary operators for addresses
- else if (isAddress())
- return TypePointer();
- // for non-address integers, we allow +, -, ++ and --
+ // we allow +, -, ++ and --
else if (_operator == Token::Add || _operator == Token::Sub ||
_operator == Token::Inc || _operator == Token::Dec ||
_operator == Token::BitNot)
@@ -539,20 +579,10 @@ bool IntegerType::operator==(Type const& _other) const
string IntegerType::toString(bool) const
{
- if (isAddress())
- return "address";
string prefix = isSigned() ? "int" : "uint";
return prefix + dev::toString(m_bits);
}
-u256 IntegerType::literalValue(Literal const* _literal) const
-{
- solAssert(m_modifier == Modifier::Address, "");
- solAssert(_literal, "");
- solAssert(_literal->value().substr(0, 2) == "0x", "");
- return u256(_literal->value());
-}
-
bigint IntegerType::minValue() const
{
if (isSigned())
@@ -580,8 +610,6 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe
if (Token::isShiftOp(_operator))
{
// Shifts are not symmetric with respect to the type
- if (isAddress())
- return TypePointer();
if (isValidShiftAndAmountType(_operator, *_other))
return shared_from_this();
else
@@ -599,9 +627,6 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe
return TypePointer();
if (auto intType = dynamic_pointer_cast<IntegerType const>(commonType))
{
- // Nothing else can be done with addresses
- if (intType->isAddress())
- return TypePointer();
// Signed EXP is not allowed
if (Token::Exp == _operator && intType->isSigned())
return TypePointer();
@@ -612,22 +637,6 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe
return commonType;
}
-MemberList::MemberMap IntegerType::nativeMembers(ContractDefinition const*) const
-{
- if (isAddress())
- return {
- {"balance", make_shared<IntegerType>(256)},
- {"call", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCall, false, StateMutability::Payable)},
- {"callcode", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCallCode, false, StateMutability::Payable)},
- {"delegatecall", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareDelegateCall, false)},
- {"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send)},
- {"staticcall", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareStaticCall, false, StateMutability::View)},
- {"transfer", make_shared<FunctionType>(strings{"uint"}, strings(), FunctionType::Kind::Transfer)}
- };
- else
- return MemberList::MemberMap();
-}
-
FixedPointType::FixedPointType(unsigned _totalBits, unsigned _fractionalDigits, FixedPointType::Modifier _modifier):
m_totalBits(_totalBits), m_fractionalDigits(_fractionalDigits), m_modifier(_modifier)
{
@@ -658,8 +667,7 @@ bool FixedPointType::isImplicitlyConvertibleTo(Type const& _convertTo) const
bool FixedPointType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
- return _convertTo.category() == category() ||
- (_convertTo.category() == Category::Integer && !dynamic_cast<IntegerType const&>(_convertTo).isAddress());
+ return _convertTo.category() == category() || _convertTo.category() == Category::Integer;
}
TypePointer FixedPointType::unaryOperatorResult(Token::Value _operator) const
@@ -912,8 +920,6 @@ bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const
if (isFractional())
return false;
IntegerType const& targetType = dynamic_cast<IntegerType const&>(_convertTo);
- if (targetType.isAddress())
- return false;
if (m_value == rational(0))
return true;
unsigned forSignBit = (targetType.isSigned() ? 1 : 0);
@@ -1368,6 +1374,7 @@ bool FixedBytesType::isImplicitlyConvertibleTo(Type const& _convertTo) const
bool FixedBytesType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
return (_convertTo.category() == Category::Integer && numBytes() * 8 == dynamic_cast<IntegerType const&>(_convertTo).numBits()) ||
+ (_convertTo.category() == Category::Address && numBytes() == 20) ||
_convertTo.category() == Category::FixedPoint ||
_convertTo.category() == category();
}
@@ -1469,9 +1476,7 @@ bool ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const
bool ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
- return
- isImplicitlyConvertibleTo(_convertTo) ||
- _convertTo == IntegerType(160, IntegerType::Modifier::Address);
+ return isImplicitlyConvertibleTo(_convertTo) || _convertTo.category() == Category::Address;
}
bool ContractType::isPayable() const
@@ -2584,12 +2589,8 @@ bool FunctionType::operator==(Type const& _other) const
bool FunctionType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
- if (m_kind == Kind::External && _convertTo.category() == Category::Integer)
- {
- IntegerType const& convertTo = dynamic_cast<IntegerType const&>(_convertTo);
- if (convertTo.isAddress())
+ if (m_kind == Kind::External && _convertTo.category() == Category::Address)
return true;
- }
return _convertTo.category() == category();
}
@@ -3274,7 +3275,7 @@ MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const
{
case Kind::Block:
return MemberList::MemberMap({
- {"coinbase", make_shared<IntegerType>(160, IntegerType::Modifier::Address)},
+ {"coinbase", make_shared<AddressType>()},
{"timestamp", make_shared<IntegerType>(256)},
{"blockhash", make_shared<FunctionType>(strings{"uint"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)},
{"difficulty", make_shared<IntegerType>(256)},
@@ -3283,7 +3284,7 @@ MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const
});
case Kind::Message:
return MemberList::MemberMap({
- {"sender", make_shared<IntegerType>(160, IntegerType::Modifier::Address)},
+ {"sender", make_shared<AddressType>()},
{"gas", make_shared<IntegerType>(256)},
{"value", make_shared<IntegerType>(256)},
{"data", make_shared<ArrayType>(DataLocation::CallData)},
@@ -3291,7 +3292,7 @@ MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const
});
case Kind::Transaction:
return MemberList::MemberMap({
- {"origin", make_shared<IntegerType>(160, IntegerType::Modifier::Address)},
+ {"origin", make_shared<AddressType>()},
{"gasprice", make_shared<IntegerType>(256)}
});
case Kind::ABI:
diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h
index b860bf6a..7ee66838 100644
--- a/libsolidity/ast/Types.h
+++ b/libsolidity/ast/Types.h
@@ -141,7 +141,7 @@ public:
virtual ~Type() = default;
enum class Category
{
- Integer, RationalNumber, StringLiteral, Bool, FixedPoint, Array,
+ Address, Integer, RationalNumber, StringLiteral, Bool, FixedPoint, Array,
FixedBytes, Contract, Struct, Function, Enum, Tuple,
Mapping, TypeType, Modifier, Magic, Module,
InaccessibleDynamic
@@ -314,14 +314,45 @@ protected:
};
/**
- * Any kind of integer type (signed, unsigned, address).
+ * Type for addresses.
+ */
+class AddressType: public Type
+{
+public:
+ virtual Category category() const override { return Category::Address; }
+
+ explicit AddressType()
+ {
+ }
+
+ virtual std::string richIdentifier() const override;
+ virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
+ virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override;
+
+ virtual unsigned calldataEncodedSize(bool _padded = true) const override { return _padded ? 32 : 160 / 8; }
+ virtual unsigned storageBytes() const override { return 160 / 8; }
+ virtual bool isValueType() const override { return true; }
+
+ virtual MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
+
+ virtual std::string toString(bool _short) const override;
+
+ virtual u256 literalValue(Literal const* _literal) const override;
+
+ virtual TypePointer encodingType() const override { return shared_from_this(); }
+ virtual TypePointer interfaceType(bool) const override { return shared_from_this(); }
+};
+
+/**
+ * Any kind of integer type (signed, unsigned).
*/
class IntegerType: public Type
{
public:
enum class Modifier
{
- Unsigned, Signed, Address
+ Unsigned, Signed
};
virtual Category category() const override { return Category::Integer; }
@@ -339,17 +370,12 @@ public:
virtual unsigned storageBytes() const override { return m_bits / 8; }
virtual bool isValueType() const override { return true; }
- virtual MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
-
virtual std::string toString(bool _short) const override;
- virtual u256 literalValue(Literal const* _literal) const override;
-
virtual TypePointer encodingType() const override { return shared_from_this(); }
virtual TypePointer interfaceType(bool) const override { return shared_from_this(); }
unsigned numBits() const { return m_bits; }
- bool isAddress() const { return m_modifier == Modifier::Address; }
bool isSigned() const { return m_modifier == Modifier::Signed; }
bigint minValue() const;
@@ -729,7 +755,7 @@ public:
{
if (isSuper())
return TypePointer{};
- return std::make_shared<IntegerType>(160, IntegerType::Modifier::Address);
+ return std::make_shared<AddressType>();
}
virtual TypePointer interfaceType(bool _inLibrary) const override
{
diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp
index dda77958..5e5fe84a 100644
--- a/libsolidity/codegen/ABIFunctions.cpp
+++ b/libsolidity/codegen/ABIFunctions.cpp
@@ -197,6 +197,9 @@ string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure)
templ("functionName", functionName);
switch (_type.category())
{
+ case Type::Category::Address:
+ templ("body", "cleaned := " + cleanupFunction(IntegerType(160)) + "(value)");
+ break;
case Type::Category::Integer:
{
IntegerType const& type = dynamic_cast<IntegerType const&>(_type);
@@ -239,7 +242,7 @@ string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure)
break;
}
case Type::Category::Contract:
- templ("body", "cleaned := " + cleanupFunction(IntegerType(160, IntegerType::Modifier::Address)) + "(value)");
+ templ("body", "cleaned := " + cleanupFunction(AddressType()) + "(value)");
break;
case Type::Category::Enum:
{
@@ -284,6 +287,12 @@ string ABIFunctions::conversionFunction(Type const& _from, Type const& _to)
auto fromCategory = _from.category();
switch (fromCategory)
{
+ case Type::Category::Address:
+ body =
+ Whiskers("converted := <convert>(value)")
+ ("convert", conversionFunction(IntegerType(160), _to))
+ .render();
+ break;
case Type::Category::Integer:
case Type::Category::RationalNumber:
case Type::Category::Contract:
@@ -314,16 +323,19 @@ string ABIFunctions::conversionFunction(Type const& _from, Type const& _to)
.render();
}
else if (toCategory == Type::Category::FixedPoint)
- {
solUnimplemented("Not yet implemented - FixedPointType.");
- }
+ else if (toCategory == Type::Category::Address)
+ body =
+ Whiskers("converted := <convert>(value)")
+ ("convert", conversionFunction(_from, IntegerType(160)))
+ .render();
else
{
solAssert(
toCategory == Type::Category::Integer ||
toCategory == Type::Category::Contract,
"");
- IntegerType const addressType(160, IntegerType::Modifier::Address);
+ IntegerType const addressType(160);
IntegerType const& to =
toCategory == Type::Category::Integer ?
dynamic_cast<IntegerType const&>(_to) :
@@ -375,6 +387,11 @@ string ABIFunctions::conversionFunction(Type const& _from, Type const& _to)
("shift", shiftRightFunction(256 - from.numBytes() * 8))
("convert", conversionFunction(IntegerType(from.numBytes() * 8), _to))
.render();
+ else if (toCategory == Type::Category::Address)
+ body =
+ Whiskers("converted := <convert>(value)")
+ ("convert", conversionFunction(_from, IntegerType(160)))
+ .render();
else
{
// clear for conversion to longer bytes
@@ -410,7 +427,7 @@ string ABIFunctions::conversionFunction(Type const& _from, Type const& _to)
solAssert(false, "");
}
- solAssert(!body.empty(), "");
+ solAssert(!body.empty(), _from.canonicalName() + " to " + _to.canonicalName());
templ("body", body);
return templ.render();
});
diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp
index b30851fb..e6ad6d9c 100644
--- a/libsolidity/codegen/CompilerUtils.cpp
+++ b/libsolidity/codegen/CompilerUtils.cpp
@@ -657,6 +657,11 @@ void CompilerUtils::convertType(
if (targetIntegerType.numBits() < typeOnStack.numBytes() * 8)
convertType(IntegerType(typeOnStack.numBytes() * 8), _targetType, _cleanupNeeded);
}
+ else if (targetTypeCategory == Type::Category::Address)
+ {
+ solAssert(typeOnStack.numBytes() * 8 == 160, "");
+ rightShiftNumberOnStack(256 - 160);
+ }
else
{
// clear for conversion to longer bytes
@@ -690,23 +695,33 @@ void CompilerUtils::convertType(
break;
case Type::Category::FixedPoint:
solUnimplemented("Not yet implemented - FixedPointType.");
+ case Type::Category::Address:
case Type::Category::Integer:
case Type::Category::Contract:
case Type::Category::RationalNumber:
if (targetTypeCategory == Type::Category::FixedBytes)
{
- solAssert(stackTypeCategory == Type::Category::Integer || stackTypeCategory == Type::Category::RationalNumber,
- "Invalid conversion to FixedBytesType requested.");
+ solAssert(
+ stackTypeCategory == Type::Category::Address ||
+ stackTypeCategory == Type::Category::Integer ||
+ stackTypeCategory == Type::Category::RationalNumber,
+ "Invalid conversion to FixedBytesType requested."
+ );
// conversion from bytes to string. no need to clean the high bit
// only to shift left because of opposite alignment
FixedBytesType const& targetBytesType = dynamic_cast<FixedBytesType const&>(_targetType);
if (auto typeOnStack = dynamic_cast<IntegerType const*>(&_typeOnStack))
+ {
if (targetBytesType.numBytes() * 8 > typeOnStack->numBits())
cleanHigherOrderBits(*typeOnStack);
+ }
+ else if (stackTypeCategory == Type::Category::Address)
+ solAssert(targetBytesType.numBytes() * 8 == 160, "");
leftShiftNumberOnStack(256 - targetBytesType.numBytes() * 8);
}
else if (targetTypeCategory == Type::Category::Enum)
{
+ solAssert(stackTypeCategory != Type::Category::Address, "Invalid conversion to EnumType requested.");
solAssert(_typeOnStack.mobileType(), "");
// just clean
convertType(_typeOnStack, *_typeOnStack.mobileType(), true);
@@ -733,8 +748,8 @@ void CompilerUtils::convertType(
}
else
{
- solAssert(targetTypeCategory == Type::Category::Integer || targetTypeCategory == Type::Category::Contract, "");
- IntegerType addressType(160, IntegerType::Modifier::Address);
+ solAssert(targetTypeCategory == Type::Category::Integer || targetTypeCategory == Type::Category::Contract || targetTypeCategory == Type::Category::Address, "");
+ IntegerType addressType(160);
IntegerType const& targetType = targetTypeCategory == Type::Category::Integer
? dynamic_cast<IntegerType const&>(_targetType) : addressType;
if (stackTypeCategory == Type::Category::RationalNumber)
@@ -996,10 +1011,8 @@ void CompilerUtils::convertType(
m_context << Instruction::ISZERO << Instruction::ISZERO;
break;
default:
- if (stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Integer)
+ if (stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Address)
{
- IntegerType const& targetType = dynamic_cast<IntegerType const&>(_targetType);
- solAssert(targetType.isAddress(), "Function type can only be converted to address.");
FunctionType const& typeOnStack = dynamic_cast<FunctionType const&>(_typeOnStack);
solAssert(typeOnStack.kind() == FunctionType::Kind::External, "Only external function type can be converted.");
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index 4cc4ba53..4150bc11 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -1259,7 +1259,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
identifier = FunctionType(*function).externalIdentifier();
else
solAssert(false, "Contract member is neither variable nor function.");
- utils().convertType(type, IntegerType(160, IntegerType::Modifier::Address), true);
+ utils().convertType(type, AddressType(), true);
m_context << identifier;
}
else
@@ -1268,11 +1268,16 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
}
case Type::Category::Integer:
{
+ solAssert(false, "Invalid member access to integer");
+ break;
+ }
+ case Type::Category::Address:
+ {
if (member == "balance")
{
utils().convertType(
*_memberAccess.expression().annotation().type,
- IntegerType(160, IntegerType::Modifier::Address),
+ AddressType(),
true
);
m_context << Instruction::BALANCE;
@@ -1280,11 +1285,11 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
else if ((set<string>{"send", "transfer", "call", "callcode", "delegatecall", "staticcall"}).count(member))
utils().convertType(
*_memberAccess.expression().annotation().type,
- IntegerType(160, IntegerType::Modifier::Address),
+ AddressType(),
true
);
else
- solAssert(false, "Invalid member access to integer");
+ solAssert(false, "Invalid member access to address");
break;
}
case Type::Category::Function:
@@ -1578,7 +1583,7 @@ void ExpressionCompiler::endVisit(Literal const& _literal)
{
case Type::Category::RationalNumber:
case Type::Category::Bool:
- case Type::Category::Integer:
+ case Type::Category::Address:
m_context << type->literalValue(&_literal);
break;
case Type::Category::StringLiteral:
diff --git a/libsolidity/formal/SMTChecker.cpp b/libsolidity/formal/SMTChecker.cpp
index 88c1e56a..49c90405 100644
--- a/libsolidity/formal/SMTChecker.cpp
+++ b/libsolidity/formal/SMTChecker.cpp
@@ -394,7 +394,7 @@ void SMTChecker::endVisit(Identifier const& _identifier)
void SMTChecker::endVisit(Literal const& _literal)
{
Type const& type = *_literal.annotation().type;
- if (type.category() == Type::Category::Integer || type.category() == Type::Category::RationalNumber)
+ if (type.category() == Type::Category::Integer || type.category() == Type::Category::Address || type.category() == Type::Category::RationalNumber)
{
if (RationalNumberType const* rational = dynamic_cast<RationalNumberType const*>(&type))
solAssert(!rational->isFractional(), "");
@@ -540,6 +540,8 @@ void SMTChecker::assignment(VariableDeclaration const& _variable, smt::Expressio
TypePointer type = _variable.type();
if (auto const* intType = dynamic_cast<IntegerType const*>(type.get()))
checkUnderOverflow(_value, *intType, _location);
+ else if (dynamic_cast<AddressType const*>(type.get()))
+ checkUnderOverflow(_value, IntegerType(160), _location);
m_interface->addAssertion(newValue(_variable) == _value);
}
@@ -862,6 +864,7 @@ void SMTChecker::createExpr(Expression const& _e)
m_expressions.emplace(&_e, m_interface->newInteger(uniqueSymbol(_e)));
break;
}
+ case Type::Category::Address:
case Type::Category::Integer:
m_expressions.emplace(&_e, m_interface->newInteger(uniqueSymbol(_e)));
break;
diff --git a/libsolidity/formal/SSAVariable.cpp b/libsolidity/formal/SSAVariable.cpp
index f3213e03..4fc2dd45 100644
--- a/libsolidity/formal/SSAVariable.cpp
+++ b/libsolidity/formal/SSAVariable.cpp
@@ -50,7 +50,7 @@ bool SSAVariable::isSupportedType(Type::Category _category)
bool SSAVariable::isInteger(Type::Category _category)
{
- return _category == Type::Category::Integer;
+ return _category == Type::Category::Integer || _category == Type::Category::Address;
}
bool SSAVariable::isBool(Type::Category _category)
diff --git a/libsolidity/formal/SymbolicIntVariable.cpp b/libsolidity/formal/SymbolicIntVariable.cpp
index 5e71fdcc..4f65b1fd 100644
--- a/libsolidity/formal/SymbolicIntVariable.cpp
+++ b/libsolidity/formal/SymbolicIntVariable.cpp
@@ -29,7 +29,11 @@ SymbolicIntVariable::SymbolicIntVariable(
):
SymbolicVariable(_decl, _interface)
{
- solAssert(m_declaration.type()->category() == Type::Category::Integer, "");
+ solAssert(
+ m_declaration.type()->category() == Type::Category::Integer ||
+ m_declaration.type()->category() == Type::Category::Address,
+ ""
+ );
}
smt::Expression SymbolicIntVariable::valueAtSequence(int _seq) const
@@ -44,9 +48,11 @@ void SymbolicIntVariable::setZeroValue(int _seq)
void SymbolicIntVariable::setUnknownValue(int _seq)
{
- auto const& intType = dynamic_cast<IntegerType const&>(*m_declaration.type());
- m_interface.addAssertion(valueAtSequence(_seq) >= minValue(intType));
- m_interface.addAssertion(valueAtSequence(_seq) <= maxValue(intType));
+ auto intType = dynamic_pointer_cast<IntegerType const>(m_declaration.type());
+ if (!intType)
+ intType = make_shared<IntegerType>(160);
+ m_interface.addAssertion(valueAtSequence(_seq) >= minValue(*intType));
+ m_interface.addAssertion(valueAtSequence(_seq) <= maxValue(*intType));
}
smt::Expression SymbolicIntVariable::minValue(IntegerType const& _t)
diff --git a/test/compilationTests/zeppelin/token/VestedToken.sol b/test/compilationTests/zeppelin/token/VestedToken.sol
index 7edc7d16..2cd607bc 100644
--- a/test/compilationTests/zeppelin/token/VestedToken.sol
+++ b/test/compilationTests/zeppelin/token/VestedToken.sol
@@ -53,7 +53,7 @@ contract VestedToken is StandardToken, LimitedTransferToken {
uint256 count = grants[_to].push(
TokenGrant(
- _revokable ? msg.sender : 0, // avoid storing an extra 20 bytes when it is non-revokable
+ _revokable ? msg.sender : 0x0000000000000000000000000000000000000000, // avoid storing an extra 20 bytes when it is non-revokable
_value,
_cliff,
_vesting,
@@ -84,7 +84,7 @@ contract VestedToken is StandardToken, LimitedTransferToken {
revert();
}
- address receiver = grant.burnsOnRevoke ? 0xdead : msg.sender;
+ address receiver = grant.burnsOnRevoke ? 0x000000000000000000000000000000000000dEaD : msg.sender;
uint256 nonVested = nonVestedTokens(grant, uint64(now));