mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #4887 from ethereum/addressSplit
Split IntegerType into IntegerType and AddressType.
This commit is contained in:
		
						commit
						08a7a51f07
					
				| @ -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";``. | ||||
|  | ||||
| @ -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
 | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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: | ||||
|  | ||||
| @ -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 | ||||
| 	{ | ||||
|  | ||||
| @ -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(); | ||||
| 	}); | ||||
|  | ||||
| @ -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."); | ||||
| 
 | ||||
|  | ||||
| @ -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 | ||||
| @ -1267,12 +1267,17 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) | ||||
| 		break; | ||||
| 	} | ||||
| 	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: | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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)); | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user