Merge pull request #10017 from ethereum/develop

Merge develop into breaking.
This commit is contained in:
chriseth 2020-10-13 12:58:23 +02:00 committed by GitHub
commit 0ea4bdafcd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 804 additions and 42 deletions

View File

@ -12,13 +12,14 @@ Language Features:
Compiler Features:
* SMTChecker: Support inline arrays.
Bugfixes:
* Code generator: Fix internal compiler error when referencing members via module name but not using the reference.
* Code generator: Fix ``ABIEncoderV2`` pragma from the current module affecting inherited functions and applied modifiers.
* Type Checker: Fix internal compiler error caused by storage parameters with nested mappings in libraries.
* Name Resolver: Fix shadowing/same-name warnings for later declarations.
* Contract Level Checker: Add missing check against inheriting functions with ABIEncoderV2 return types in ABIEncoderV1 contracts.
### 0.7.3 (2020-10-07)

View File

@ -85,7 +85,7 @@ else:
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build', 'contracts', 'types', 'examples', 'grammar']
exclude_patterns = ['_build', 'contracts', 'types', 'examples', 'grammar', 'ir']
# The reST default role (used for this markup: `text`) to use for all
# documents.

View File

@ -0,0 +1,6 @@
********************************
Solidity IR-based Codegen Changes
********************************
This section highlights the main differences between the old and the IR-based codegen,
along with the reasoning behind the changes and how to update affected code.

View File

@ -119,6 +119,13 @@ decoding types only supported by the new encoder. The compiler can detect this
and will issue an error. Simply enabling ``ABIEncoderV2`` for your contract is
enough to make the error go away.
.. note::
This pragma applies to all the code defined in the file where it is activated,
regardless of where that code ends up eventually. This means that a contract
without the ``ABIEncoderV2`` pragma can still contain code that uses the new encoder
by inheriting it from another contract. This is allowed if the new types are only
used internally and not in external function signatures.
.. _smt_checker:
SMTChecker

View File

@ -474,7 +474,7 @@ void ContractLevelChecker::checkBaseABICompatibility(ContractDefinition const& _
auto const& currentLoc = func.second->declaration().location();
for (TypePointer const& paramType: func.second->parameterTypes() + func.second->parameterTypes())
for (TypePointer const& paramType: func.second->parameterTypes() + func.second->returnParameterTypes())
if (!TypeChecker::typeSupportedByOldABIEncoder(*paramType, false))
{
errors.append("Type only supported by ABIEncoderV2", currentLoc);

View File

@ -29,6 +29,7 @@
#include <libsolutil/Algorithms.h>
#include <libsolutil/CommonData.h>
#include <libsolutil/CommonIO.h>
#include <libsolutil/FunctionSelector.h>
#include <libsolutil/Keccak256.h>
#include <libsolutil/UTF8.h>
@ -3596,7 +3597,7 @@ string FunctionType::externalSignature() const
u256 FunctionType::externalIdentifier() const
{
return util::FixedHash<4>::Arith(util::FixedHash<4>(util::keccak256(externalSignature())));
return util::selectorFromSignature32(externalSignature());
}
string FunctionType::externalIdentifierHex() const

View File

@ -28,6 +28,7 @@
#include <libsolidity/codegen/ABIFunctions.h>
#include <libsolidity/codegen/ArrayUtils.h>
#include <libsolidity/codegen/LValue.h>
#include <libsolutil/FunctionSelector.h>
#include <libevmasm/Instruction.h>
#include <libsolutil/Whiskers.h>
@ -93,7 +94,7 @@ void CompilerUtils::revertWithStringData(Type const& _argumentType)
{
solAssert(_argumentType.isImplicitlyConvertibleTo(*TypeProvider::fromElementaryTypeName("string memory")), "");
fetchFreeMemoryPointer();
m_context << (u256(util::FixedHash<4>::Arith(util::FixedHash<4>(util::keccak256("Error(string)")))) << (256 - 32));
m_context << util::selectorFromSignature("Error(string)");
m_context << Instruction::DUP2 << Instruction::MSTORE;
m_context << u256(4) << Instruction::ADD;
// Stack: <string data> <mem pos of encoding start>
@ -916,7 +917,7 @@ void CompilerUtils::convertType(
{
unsigned const numBytes = dynamic_cast<FixedBytesType const&>(_targetType).numBytes();
solAssert(data.size() <= 32, "");
m_context << (h256::Arith(h256(data, h256::AlignLeft)) & (~(u256(-1) >> (8 * numBytes))));
m_context << (u256(h256(data, h256::AlignLeft)) & (~(u256(-1) >> (8 * numBytes))));
}
else if (targetTypeCategory == Type::Category::Array)
{
@ -1421,7 +1422,7 @@ void CompilerUtils::storeStringData(bytesConstRef _data)
{
for (unsigned i = 0; i < _data.size(); i += 32)
{
m_context << h256::Arith(h256(_data.cropped(i), h256::AlignLeft));
m_context << u256(h256(_data.cropped(i), h256::AlignLeft));
storeInMemoryDynamic(*TypeProvider::uint256());
}
m_context << Instruction::POP;

View File

@ -953,8 +953,6 @@ void ContractCompiler::handleCatch(vector<ASTPointer<TryCatchClause>> const& _ca
);
solAssert(m_context.evmVersion().supportsReturndata(), "");
string errorHash = FixedHash<4>(util::keccak256("Error(string)")).hex();
// Try to decode the error message.
// If this fails, leaves 0 on the stack, otherwise the pointer to the data string.
m_context.callYulFunction(m_context.utilFunctions().tryDecodeErrorMessageFunction(), 0, 1);

View File

@ -33,6 +33,7 @@
#include <libevmasm/GasMeter.h>
#include <libsolutil/Common.h>
#include <libsolutil/FunctionSelector.h>
#include <libsolutil/Keccak256.h>
#include <libsolutil/Whiskers.h>
@ -1187,8 +1188,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
// hash the signature
if (auto const* stringType = dynamic_cast<StringLiteralType const*>(selectorType))
{
FixedHash<4> hash(keccak256(stringType->value()));
m_context << (u256(FixedHash<4>::Arith(hash)) << (256 - 32));
m_context << util::selectorFromSignature(stringType->value());
dataOnStack = TypeProvider::fixedBytes(4);
}
else

View File

@ -26,6 +26,7 @@
#include <libsolidity/codegen/CompilerUtils.h>
#include <libsolutil/CommonData.h>
#include <libsolutil/FunctionSelector.h>
#include <libsolutil/Whiskers.h>
#include <libsolutil/StringUtils.h>
@ -126,11 +127,7 @@ string YulUtilFunctions::requireOrAssertFunction(bool _assert, Type const* _mess
.render();
int const hashHeaderSize = 4;
int const byteSize = 8;
u256 const errorHash =
u256(FixedHash<hashHeaderSize>::Arith(
FixedHash<hashHeaderSize>(keccak256("Error(string)"))
)) << (256 - hashHeaderSize * byteSize);
u256 const errorHash = util::selectorFromSignature("Error(string)");
string const encodeFunc = ABIFunctions(m_evmVersion, m_revertStrings, m_functionCollector)
.tupleEncoder(
@ -635,6 +632,119 @@ string YulUtilFunctions::overflowCheckedIntExpFunction(
});
}
string YulUtilFunctions::overflowCheckedIntLiteralExpFunction(
RationalNumberType const& _baseType,
IntegerType const& _exponentType,
IntegerType const& _commonType
)
{
solAssert(!_exponentType.isSigned(), "");
solAssert(_baseType.isNegative() == _commonType.isSigned(), "");
solAssert(_commonType.numBits() == 256, "");
string functionName = "checked_exp_" + _baseType.richIdentifier() + "_" + _exponentType.identifier();
return m_functionCollector.createFunction(functionName, [&]()
{
// Converts a bigint number into u256 (negative numbers represented in two's complement form.)
// We assume that `_v` fits in 256 bits.
auto bigint2u = [&](bigint const& _v) -> u256
{
if (_v < 0)
return s2u(s256(_v));
return u256(_v);
};
// Calculates the upperbound for exponentiation, that is, calculate `b`, such that
// _base**b <= _maxValue and _base**(b + 1) > _maxValue
auto findExponentUpperbound = [](bigint const _base, bigint const _maxValue) -> unsigned
{
// There is no overflow for these cases
if (_base == 0 || _base == -1 || _base == 1)
return 0;
unsigned first = 0;
unsigned last = 255;
unsigned middle;
while (first < last)
{
middle = (first + last) / 2;
if (
// The condition on msb is a shortcut that avoids computing large powers in
// arbitrary precision.
boost::multiprecision::msb(_base) * middle <= boost::multiprecision::msb(_maxValue) &&
boost::multiprecision::pow(_base, middle) <= _maxValue
)
{
if (boost::multiprecision::pow(_base, middle + 1) > _maxValue)
return middle;
else
first = middle + 1;
}
else
last = middle;
}
return last;
};
bigint baseValue = _baseType.isNegative() ?
u2s(_baseType.literalValue(nullptr)) :
_baseType.literalValue(nullptr);
bool needsOverflowCheck = !((baseValue == 0) || (baseValue == -1) || (baseValue == 1));
unsigned exponentUpperbound;
if (_baseType.isNegative())
{
// Only checks for underflow. The only case where this can be a problem is when, for a
// negative base, say `b`, and an even exponent, say `e`, `b**e = 2**255` (which is an
// overflow.) But this never happens because, `255 = 3*5*17`, and therefore there is no even
// number `e` such that `b**e = 2**255`.
exponentUpperbound = findExponentUpperbound(abs(baseValue), abs(_commonType.minValue()));
bigint power = boost::multiprecision::pow(baseValue, exponentUpperbound);
bigint overflowedPower = boost::multiprecision::pow(baseValue, exponentUpperbound + 1);
if (needsOverflowCheck)
solAssert(
(power <= _commonType.maxValue()) && (power >= _commonType.minValue()) &&
!((overflowedPower <= _commonType.maxValue()) && (overflowedPower >= _commonType.minValue())),
"Incorrect exponent upper bound calculated."
);
}
else
{
exponentUpperbound = findExponentUpperbound(baseValue, _commonType.maxValue());
if (needsOverflowCheck)
solAssert(
boost::multiprecision::pow(baseValue, exponentUpperbound) <= _commonType.maxValue() &&
boost::multiprecision::pow(baseValue, exponentUpperbound + 1) > _commonType.maxValue(),
"Incorrect exponent upper bound calculated."
);
}
return Whiskers(R"(
function <functionName>(exponent) -> power {
exponent := <exponentCleanupFunction>(exponent)
<?needsOverflowCheck>
if gt(exponent, <exponentUpperbound>) { <panic>() }
</needsOverflowCheck>
power := exp(<base>, exponent)
}
)")
("functionName", functionName)
("exponentCleanupFunction", cleanupFunction(_exponentType))
("needsOverflowCheck", needsOverflowCheck)
("exponentUpperbound", to_string(exponentUpperbound))
("panic", panicFunction())
("base", bigint2u(baseValue).str())
.render();
});
}
string YulUtilFunctions::overflowCheckedUnsignedExpFunction()
{
// Checks for the "small number specialization" below.
@ -3079,7 +3189,7 @@ string YulUtilFunctions::revertReasonIfDebug(RevertStrings revertStrings, string
</word>
revert(0, add(reasonPos, <end>))
})");
templ("sig", (u256(util::FixedHash<4>::Arith(util::FixedHash<4>(util::keccak256("Error(string)")))) << (256 - 32)).str());
templ("sig", util::selectorFromSignature("Error(string)").str());
templ("length", to_string(_message.length()));
size_t words = (_message.length() + 31) / 32;

View File

@ -128,6 +128,14 @@ public:
/// signature: (base, exponent) -> power
std::string overflowCheckedIntExpFunction(IntegerType const& _type, IntegerType const& _exponentType);
/// @returns the name of the exponentiation function, specialized for literal base.
/// signature: exponent -> power
std::string overflowCheckedIntLiteralExpFunction(
RationalNumberType const& _baseType,
IntegerType const& _exponentType,
IntegerType const& _commonType
);
/// Generic unsigned checked exponentiation function.
/// Reverts if the result is larger than max.
/// signature: (base, exponent, max) -> power

View File

@ -43,6 +43,7 @@
#include <libsolutil/Whiskers.h>
#include <libsolutil/StringUtils.h>
#include <libsolutil/Keccak256.h>
#include <libsolutil/FunctionSelector.h>
#include <libsolutil/Visitor.h>
#include <boost/range/adaptor/transformed.hpp>
@ -695,17 +696,34 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
solAssert(false, "Unknown comparison operator.");
define(_binOp) << expr << "\n";
}
else if (TokenTraits::isShiftOp(op) || op == Token::Exp)
else if (op == Token::Exp)
{
IRVariable left = convert(_binOp.leftExpression(), *commonType);
IRVariable right = convert(_binOp.rightExpression(), *type(_binOp.rightExpression()).mobileType());
if (op == Token::Exp)
if (auto rationalNumberType = dynamic_cast<RationalNumberType const*>(_binOp.leftExpression().annotation().type))
{
solAssert(rationalNumberType->integerType(), "Invalid literal as the base for exponentiation.");
solAssert(dynamic_cast<IntegerType const*>(commonType), "");
define(_binOp) << m_utils.overflowCheckedIntLiteralExpFunction(
*rationalNumberType,
dynamic_cast<IntegerType const&>(right.type()),
dynamic_cast<IntegerType const&>(*commonType)
) << "(" << right.name() << ")\n";
}
else
define(_binOp) << m_utils.overflowCheckedIntExpFunction(
dynamic_cast<IntegerType const&>(left.type()),
dynamic_cast<IntegerType const&>(right.type())
) << "(" << left.name() << ", " << right.name() << ")\n";
else
define(_binOp) << shiftOperation(_binOp.getOperator(), left, right) << "\n";
}
else if (TokenTraits::isShiftOp(op))
{
IRVariable left = convert(_binOp.leftExpression(), *commonType);
IRVariable right = convert(_binOp.rightExpression(), *type(_binOp.rightExpression()).mobileType());
define(_binOp) << shiftOperation(_binOp.getOperator(), left, right) << "\n";
}
else
{
@ -1020,10 +1038,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
// hash the signature
Type const& selectorType = type(*arguments.front());
if (auto const* stringType = dynamic_cast<StringLiteralType const*>(&selectorType))
{
FixedHash<4> hash(keccak256(stringType->value()));
selector = formatNumber(u256(FixedHash<4>::Arith(hash)) << (256 - 32));
}
selector = formatNumber(util::selectorFromSignature(stringType->value()));
else
{
// Used to reset the free memory pointer later.
@ -1140,10 +1155,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
})");
templ("pos", m_context.newYulVariable());
templ("end", m_context.newYulVariable());
templ(
"hash",
(u256(util::FixedHash<4>::Arith(util::FixedHash<4>(util::keccak256("Error(string)")))) << (256 - 32)).str()
);
templ("hash", util::selectorFromSignature("Error(string)").str());
templ("allocateTemporary", m_utils.allocationTemporaryMemoryFunction());
templ(
"argumentVars",

View File

@ -391,11 +391,13 @@ void SMTEncoder::endVisit(TupleExpression const& _tuple)
createExpr(_tuple);
if (_tuple.isInlineArray())
m_errorReporter.warning(
2177_error,
_tuple.location(),
"Assertion checker does not yet implement inline arrays."
);
{
// Add constraints for the length and values as it is known.
auto symbArray = dynamic_pointer_cast<smt::SymbolicArrayVariable>(m_context.expression(_tuple));
solAssert(symbArray, "");
addArrayLiteralAssertions(*symbArray, applyMap(_tuple.components(), [&](auto const& c) { return expr(*c); }));
}
else if (_tuple.components().size() == 1)
defineExpr(_tuple, expr(*_tuple.components().front()));
else
@ -965,12 +967,10 @@ void SMTEncoder::endVisit(Literal const& _literal)
auto symbArray = dynamic_pointer_cast<smt::SymbolicArrayVariable>(m_context.expression(_literal));
solAssert(symbArray, "");
auto value = _literal.value();
m_context.addAssertion(symbArray->length() == value.length());
for (size_t i = 0; i < value.length(); i++)
m_context.addAssertion(
smtutil::Expression::select(symbArray->elements(), i) == size_t(value[i])
);
addArrayLiteralAssertions(
*symbArray,
applyMap(_literal.value(), [&](auto const& c) { return smtutil::Expression{size_t(c)}; })
);
}
else
{
@ -984,6 +984,16 @@ void SMTEncoder::endVisit(Literal const& _literal)
}
}
void SMTEncoder::addArrayLiteralAssertions(
smt::SymbolicArrayVariable& _symArray,
vector<smtutil::Expression> const& _elementValues
)
{
m_context.addAssertion(_symArray.length() == _elementValues.size());
for (size_t i = 0; i < _elementValues.size(); i++)
m_context.addAssertion(smtutil::Expression::select(_symArray.elements(), i) == _elementValues[i]);
}
void SMTEncoder::endVisit(Return const& _return)
{
if (_return.expression() && m_context.knownExpression(*_return.expression()))

View File

@ -169,6 +169,11 @@ protected:
/// an empty array.
virtual void makeArrayPopVerificationTarget(FunctionCall const&) {}
void addArrayLiteralAssertions(
smt::SymbolicArrayVariable& _symArray,
std::vector<smtutil::Expression> const& _elementValues
);
/// Division expression in the given type. Requires special treatment because
/// of rounding for signed division.
smtutil::Expression division(smtutil::Expression _left, smtutil::Expression _right, IntegerType const& _type);

View File

@ -10,6 +10,7 @@ set(sources
Exceptions.cpp
Exceptions.h
FixedHash.h
FunctionSelector.h
IndentedWriter.cpp
IndentedWriter.h
InvertibleMap.h

View File

@ -0,0 +1,42 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
#pragma once
#include <libsolutil/Keccak256.h>
#include <libsolutil/FixedHash.h>
#include <string>
namespace solidity::util
{
/// @returns the ABI selector for a given function signature, as a 32 bit number.
inline uint32_t selectorFromSignature32(std::string const& _signature)
{
return uint32_t(FixedHash<4>::Arith(util::FixedHash<4>(util::keccak256(_signature))));
}
/// @returns the ABI selector for a given function signature, as a u256 (left aligned) number.
inline u256 selectorFromSignature(std::string const& _signature)
{
return u256(selectorFromSignature32(_signature)) << (256 - 32);
}
}

View File

@ -0,0 +1 @@
--ir

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@
0

View File

@ -0,0 +1,18 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity > 0.7.1;
contract C {
function f(uint a, uint b, uint c, uint d) public pure returns (uint, int, uint, uint) {
uint w = 2**a;
int x = (-2)**b;
uint y = 10**c;
uint z = (2**256 -1 )**d;
// Special cases: 0, 1, and -1
w = (0)**a;
x = (-1)**b;
y = 1**c;
return (w, x, y, z);
}
}

View File

@ -0,0 +1,304 @@
IR:
/*******************************************************
* WARNING *
* Solidity to Yul compilation is still EXPERIMENTAL *
* It can result in LOSS OF FUNDS or worse *
* !USE AT YOUR OWN RISK! *
*******************************************************/
object "C_80" {
code {
mstore(64, memoryguard(128))
if callvalue() { revert(0, 0) }
constructor_C_80()
codecopy(0, dataoffset("C_80_deployed"), datasize("C_80_deployed"))
return(0, datasize("C_80_deployed"))
function constructor_C_80() {
}
}
object "C_80_deployed" {
code {
mstore(64, memoryguard(128))
if iszero(lt(calldatasize(), 4))
{
let selector := shift_right_224_unsigned(calldataload(0))
switch selector
case 0x70cb9605
{
// f(uint256,uint256,uint256,uint256)
if callvalue() { revert(0, 0) }
let param_0, param_1, param_2, param_3 := abi_decode_tuple_t_uint256t_uint256t_uint256t_uint256(4, calldatasize())
let ret_0, ret_1, ret_2, ret_3 := fun_f_79(param_0, param_1, param_2, param_3)
let memPos := allocateMemory(0)
let memEnd := abi_encode_tuple_t_uint256_t_int256_t_uint256_t_uint256__to_t_uint256_t_int256_t_uint256_t_uint256__fromStack(memPos , ret_0, ret_1, ret_2, ret_3)
return(memPos, sub(memEnd, memPos))
}
default {}
}
if iszero(calldatasize()) { }
revert(0, 0)
function abi_decode_t_uint256(offset, end) -> value {
value := calldataload(offset)
validator_revert_t_uint256(value)
}
function abi_decode_tuple_t_uint256t_uint256t_uint256t_uint256(headStart, dataEnd) -> value0, value1, value2, value3 {
if slt(sub(dataEnd, headStart), 128) { revert(0, 0) }
{
let offset := 0
value0 := abi_decode_t_uint256(add(headStart, offset), dataEnd)
}
{
let offset := 32
value1 := abi_decode_t_uint256(add(headStart, offset), dataEnd)
}
{
let offset := 64
value2 := abi_decode_t_uint256(add(headStart, offset), dataEnd)
}
{
let offset := 96
value3 := abi_decode_t_uint256(add(headStart, offset), dataEnd)
}
}
function abi_encode_t_int256_to_t_int256_fromStack(value, pos) {
mstore(pos, cleanup_t_int256(value))
}
function abi_encode_t_uint256_to_t_uint256_fromStack(value, pos) {
mstore(pos, cleanup_t_uint256(value))
}
function abi_encode_tuple_t_uint256_t_int256_t_uint256_t_uint256__to_t_uint256_t_int256_t_uint256_t_uint256__fromStack(headStart , value0, value1, value2, value3) -> tail {
tail := add(headStart, 128)
abi_encode_t_uint256_to_t_uint256_fromStack(value0, add(headStart, 0))
abi_encode_t_int256_to_t_int256_fromStack(value1, add(headStart, 32))
abi_encode_t_uint256_to_t_uint256_fromStack(value2, add(headStart, 64))
abi_encode_t_uint256_to_t_uint256_fromStack(value3, add(headStart, 96))
}
function allocateMemory(size) -> memPtr {
memPtr := mload(64)
let newFreePtr := add(memPtr, size)
// protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error() }
mstore(64, newFreePtr)
}
function checked_exp_t_rational_0_by_1_t_uint256(exponent) -> power {
exponent := cleanup_t_uint256(exponent)
power := exp(0, exponent)
}
function checked_exp_t_rational_10_by_1_t_uint256(exponent) -> power {
exponent := cleanup_t_uint256(exponent)
if gt(exponent, 77) { panic_error() }
power := exp(10, exponent)
}
function checked_exp_t_rational_115792089237316195423570985008687907853269984665640564039457584007913129639935_by_1_t_uint256(exponent) -> power {
exponent := cleanup_t_uint256(exponent)
if gt(exponent, 1) { panic_error() }
power := exp(115792089237316195423570985008687907853269984665640564039457584007913129639935, exponent)
}
function checked_exp_t_rational_1_by_1_t_uint256(exponent) -> power {
exponent := cleanup_t_uint256(exponent)
power := exp(1, exponent)
}
function checked_exp_t_rational_2_by_1_t_uint256(exponent) -> power {
exponent := cleanup_t_uint256(exponent)
if gt(exponent, 255) { panic_error() }
power := exp(2, exponent)
}
function checked_exp_t_rational_minus_1_by_1_t_uint256(exponent) -> power {
exponent := cleanup_t_uint256(exponent)
power := exp(115792089237316195423570985008687907853269984665640564039457584007913129639935, exponent)
}
function checked_exp_t_rational_minus_2_by_1_t_uint256(exponent) -> power {
exponent := cleanup_t_uint256(exponent)
if gt(exponent, 255) { panic_error() }
power := exp(115792089237316195423570985008687907853269984665640564039457584007913129639934, exponent)
}
function cleanup_t_int256(value) -> cleaned {
cleaned := value
}
function cleanup_t_uint256(value) -> cleaned {
cleaned := value
}
function convert_t_rational_0_by_1_to_t_uint256(value) -> converted {
converted := cleanup_t_uint256(value)
}
function convert_t_rational_10_by_1_to_t_uint256(value) -> converted {
converted := cleanup_t_uint256(value)
}
function convert_t_rational_115792089237316195423570985008687907853269984665640564039457584007913129639935_by_1_to_t_uint256(value) -> converted {
converted := cleanup_t_uint256(value)
}
function convert_t_rational_1_by_1_to_t_uint256(value) -> converted {
converted := cleanup_t_uint256(value)
}
function convert_t_rational_2_by_1_to_t_uint256(value) -> converted {
converted := cleanup_t_uint256(value)
}
function convert_t_rational_minus_1_by_1_to_t_int256(value) -> converted {
converted := cleanup_t_int256(value)
}
function convert_t_rational_minus_2_by_1_to_t_int256(value) -> converted {
converted := cleanup_t_int256(value)
}
function fun_f_79(vloc_a_3, vloc_b_5, vloc_c_7, vloc_d_9) -> vloc__12, vloc__14, vloc__16, vloc__18 {
let zero_value_for_type_t_uint256_1 := zero_value_for_split_t_uint256()
vloc__12 := zero_value_for_type_t_uint256_1
let zero_value_for_type_t_int256_2 := zero_value_for_split_t_int256()
vloc__14 := zero_value_for_type_t_int256_2
let zero_value_for_type_t_uint256_3 := zero_value_for_split_t_uint256()
vloc__16 := zero_value_for_type_t_uint256_3
let zero_value_for_type_t_uint256_4 := zero_value_for_split_t_uint256()
vloc__18 := zero_value_for_type_t_uint256_4
let expr_22 := 0x02
let _5 := vloc_a_3
let expr_23 := _5
let _6 := convert_t_rational_2_by_1_to_t_uint256(expr_22)
let expr_24 := checked_exp_t_rational_2_by_1_t_uint256(expr_23)
let vloc_w_21 := expr_24
let expr_28 := 0x02
let expr_29 := 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe
let expr_30 := expr_29
let _7 := vloc_b_5
let expr_31 := _7
let _8 := convert_t_rational_minus_2_by_1_to_t_int256(expr_30)
let expr_32 := checked_exp_t_rational_minus_2_by_1_t_uint256(expr_31)
let vloc_x_27 := expr_32
let expr_36 := 0x0a
let _9 := vloc_c_7
let expr_37 := _9
let _10 := convert_t_rational_10_by_1_to_t_uint256(expr_36)
let expr_38 := checked_exp_t_rational_10_by_1_t_uint256(expr_37)
let vloc_y_35 := expr_38
let expr_46 := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
let expr_47 := expr_46
let _11 := vloc_d_9
let expr_48 := _11
let _12 := convert_t_rational_115792089237316195423570985008687907853269984665640564039457584007913129639935_by_1_to_t_uint256(expr_47)
let expr_49 := checked_exp_t_rational_115792089237316195423570985008687907853269984665640564039457584007913129639935_by_1_t_uint256(expr_48)
let vloc_z_41 := expr_49
let expr_52 := 0x00
let expr_53 := expr_52
let _13 := vloc_a_3
let expr_54 := _13
let _14 := convert_t_rational_0_by_1_to_t_uint256(expr_53)
let expr_55 := checked_exp_t_rational_0_by_1_t_uint256(expr_54)
vloc_w_21 := expr_55
let expr_56 := expr_55
let expr_59 := 0x01
let expr_60 := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
let expr_61 := expr_60
let _15 := vloc_b_5
let expr_62 := _15
let _16 := convert_t_rational_minus_1_by_1_to_t_int256(expr_61)
let expr_63 := checked_exp_t_rational_minus_1_by_1_t_uint256(expr_62)
vloc_x_27 := expr_63
let expr_64 := expr_63
let expr_67 := 0x01
let _17 := vloc_c_7
let expr_68 := _17
let _18 := convert_t_rational_1_by_1_to_t_uint256(expr_67)
let expr_69 := checked_exp_t_rational_1_by_1_t_uint256(expr_68)
vloc_y_35 := expr_69
let expr_70 := expr_69
let _19 := vloc_w_21
let expr_72 := _19
let expr_76_component_1 := expr_72
let _20 := vloc_x_27
let expr_73 := _20
let expr_76_component_2 := expr_73
let _21 := vloc_y_35
let expr_74 := _21
let expr_76_component_3 := expr_74
let _22 := vloc_z_41
let expr_75 := _22
let expr_76_component_4 := expr_75
vloc__12 := expr_76_component_1
vloc__14 := expr_76_component_2
vloc__16 := expr_76_component_3
vloc__18 := expr_76_component_4
leave
}
function panic_error() {
invalid()
}
function shift_right_224_unsigned(value) -> newValue {
newValue :=
shr(224, value)
}
function validator_revert_t_uint256(value) {
if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) }
}
function zero_value_for_split_t_int256() -> ret {
ret := 0
}
function zero_value_for_split_t_uint256() -> ret {
ret := 0
}
}
}
}

View File

@ -0,0 +1,49 @@
contract C {
function exp_2(uint y) public returns (uint) {
return 2**y;
}
function exp_minus_2(uint y) public returns (int) {
return (-2)**y;
}
function exp_uint_max(uint y) public returns (uint) {
return (2**256 - 1)**y;
}
function exp_int_max(uint y) public returns (int) {
return ((-2)**255)**y;
}
function exp_5(uint y) public returns (uint) {
return 5**y;
}
function exp_minus_5(uint y) public returns (int) {
return (-5)**y;
}
function exp_256(uint y) public returns (uint) {
return 256**y;
}
function exp_minus_256(uint y) public returns (int) {
return (-256)**y;
}
}
// ====
// compileViaYul: true
// ----
// exp_2(uint256): 255 -> 57896044618658097711785492504343953926634992332820282019728792003956564819968
// exp_2(uint256): 256 -> FAILURE
// exp_minus_2(uint256): 255 -> -57896044618658097711785492504343953926634992332820282019728792003956564819968
// exp_minus_2(uint256): 256 -> FAILURE
// exp_uint_max(uint256): 1 -> 115792089237316195423570985008687907853269984665640564039457584007913129639935
// exp_uint_max(uint256): 2 -> FAILURE
// exp_int_max(uint256): 1 -> -57896044618658097711785492504343953926634992332820282019728792003956564819968
// exp_int_max(uint256): 2 -> FAILURE
// exp_5(uint256): 110 -> 77037197775489434122239117703397092741524065928615527809597551822662353515625
// exp_5(uint256): 111 -> FAILURE
// exp_minus_5(uint256): 109 -> -15407439555097886824447823540679418548304813185723105561919510364532470703125
// exp_minus_5(uint256): 110 -> FAILURE
// exp_256(uint256): 31 -> 452312848583266388373324160190187140051835877600158453279131187530910662656
// exp_256(uint256): 32 -> FAILURE
// exp_minus_256(uint256): 31 -> -452312848583266388373324160190187140051835877600158453279131187530910662656
// exp_minus_256(uint256): 32 -> FAILURE

View File

@ -0,0 +1,41 @@
contract C {
function exp_2(uint y) public returns (uint) {
return 2**y;
}
function exp_minus_2(uint y) public returns (int) {
return (-2)**y;
}
function exp_uint_max(uint y) public returns (uint) {
return (2**256 - 1)**y;
}
function exp_int_max(uint y) public returns (int) {
return ((-2)**255)**y;
}
function exp_5(uint y) public returns (uint) {
return 5**y;
}
function exp_minus_5(uint y) public returns (int) {
return (-5)**y;
}
function exp_256(uint y) public returns (uint) {
return 256**y;
}
function exp_minus_256(uint y) public returns (int) {
return (-256)**y;
}
}
// ====
// compileViaYul: also
// ----
// exp_2(uint256): 255 -> 57896044618658097711785492504343953926634992332820282019728792003956564819968
// exp_minus_2(uint256): 255 -> -57896044618658097711785492504343953926634992332820282019728792003956564819968
// exp_uint_max(uint256): 1 -> 115792089237316195423570985008687907853269984665640564039457584007913129639935
// exp_int_max(uint256): 1 -> -57896044618658097711785492504343953926634992332820282019728792003956564819968
// exp_5(uint256): 110 -> 77037197775489434122239117703397092741524065928615527809597551822662353515625
// exp_minus_5(uint256): 109 -> -15407439555097886824447823540679418548304813185723105561919510364532470703125
// exp_256(uint256): 31 -> 452312848583266388373324160190187140051835877600158453279131187530910662656
// exp_minus_256(uint256): 31 -> -452312848583266388373324160190187140051835877600158453279131187530910662656

View File

@ -4,8 +4,9 @@ contract C
{
function f() public pure {
uint[3] memory array = [uint(1), 2, 3];
assert(array[0] == 1);
assert(array[1] == 2);
assert(array[2] == 3);
}
}
// ----
// Warning 2072: (76-96): Unused local variable.
// Warning 2177: (99-114): Assertion checker does not yet implement inline arrays.

View File

@ -0,0 +1,14 @@
pragma experimental SMTChecker;
contract C
{
function f() public pure {
uint[3] memory a = [uint(1), 2, 3];
uint[3] memory b = [uint(1), 2, 4];
assert(a[0] == b[0]);
assert(a[1] == b[1]);
assert(a[2] == b[2]); // fails
}
}
// ----
// Warning 6328: (200-220): CHC: Assertion violation happens here.

View File

@ -0,0 +1,13 @@
pragma experimental SMTChecker;
contract C
{
function f() public pure {
(uint[3] memory a, uint[3] memory b) = ([uint(1), 2, 3], [uint(1), 2, 4]);
assert(a[0] == b[0]);
assert(a[1] == b[1]);
assert(a[2] == b[2]); // fails
}
}
// ----
// Warning 6328: (201-221): CHC: Assertion violation happens here.

View File

@ -0,0 +1,13 @@
pragma experimental SMTChecker;
contract C
{
function f(bool c) public pure {
uint[3] memory a = c ? [uint(1), 2, 3] : [uint(1), 2, 4];
uint[3] memory b = [uint(1), 2, c ? 3 : 4];
assert(a[0] == b[0]);
assert(a[1] == b[1]);
assert(a[2] == b[2]);
}
}
// ----

View File

@ -0,0 +1,16 @@
pragma experimental SMTChecker;
contract C
{
uint[] s;
function f() public {
uint[3] memory a = [uint(1), 2, 3];
s = a;
assert(s.length == a.length);
assert(s[0] == a[0]);
assert(s[1] == a[1]);
assert(s[2] != a[2]); // fails
}
}
// ----
// Warning 6328: (209-229): CHC: Assertion violation happens here.

View File

@ -0,0 +1,18 @@
pragma experimental SMTChecker;
contract C
{
function f() public pure {
uint[3] memory a = [uint(1), 2, 3];
uint[4] memory b = [uint(1), 2, 4, 3];
uint[4] memory c = b;
assert(a.length == c.length); // fails
assert(a[0] == c[0]);
assert(a[1] == c[1]);
assert(a[2] == c[2]); // fails
assert(a[2] == c[3]);
}
}
// ----
// Warning 6328: (179-207): CHC: Assertion violation happens here.
// Warning 6328: (268-288): CHC: Assertion violation happens here.

View File

@ -0,0 +1,23 @@
pragma experimental SMTChecker;
contract C
{
uint[] s;
function f() public {
uint[3] memory a = [uint(1), 2, 3];
uint[4] memory b = [uint(1), 2, 4, 3];
uint[4] memory c = b;
assert(c.length == b.length);
s = a;
assert(s.length == a.length);
assert(s.length == c.length); // fails
assert(s[0] == c[0]);
assert(s[1] == c[1]);
assert(s[2] == c[2]); // fails
assert(s[2] == c[3]);
}
}
// ----
// Warning 6328: (259-287): CHC: Assertion violation happens here.
// Warning 6328: (348-368): CHC: Assertion violation happens here.

View File

@ -0,0 +1,15 @@
==== Source: A ====
pragma experimental ABIEncoderV2;
struct Item {
uint x;
}
contract C {
event Ev(Item);
}
==== Source: B ====
import "A";
contract D is C {}
// ----

View File

@ -0,0 +1,16 @@
==== Source: A ====
pragma experimental ABIEncoderV2;
contract C {
struct Item {
uint x;
}
function get(Item memory) external view {}
}
==== Source: B ====
import "A";
contract D is C {}
// ----
// TypeError 6594: (B:13-31): Contract "D" does not use ABIEncoderV2 but wants to inherit from a contract which uses types that require it. Use "pragma experimental ABIEncoderV2;" for the inheriting contract as well to enable the feature.

View File

@ -0,0 +1,16 @@
==== Source: A ====
pragma experimental ABIEncoderV2;
contract C {
struct Item {
uint x;
}
function get() external view returns(Item memory) {}
}
==== Source: B ====
import "A";
contract D is C {}
// ----
// TypeError 6594: (B:13-31): Contract "D" does not use ABIEncoderV2 but wants to inherit from a contract which uses types that require it. Use "pragma experimental ABIEncoderV2;" for the inheriting contract as well to enable the feature.