mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge remote-tracking branch 'origin/develop' into breaking
This commit is contained in:
commit
14ed67ac4b
@ -58,7 +58,7 @@ public:
|
|||||||
std::pair<CheckResult, std::vector<std::string>> check(std::vector<Expression> const& _expressionsToEvaluate) override;
|
std::pair<CheckResult, std::vector<std::string>> check(std::vector<Expression> const& _expressionsToEvaluate) override;
|
||||||
|
|
||||||
std::vector<std::string> unhandledQueries() override;
|
std::vector<std::string> unhandledQueries() override;
|
||||||
unsigned solvers() override { return m_solvers.size(); }
|
size_t solvers() override { return m_solvers.size(); }
|
||||||
private:
|
private:
|
||||||
static bool solverAnswered(CheckResult result);
|
static bool solverAnswered(CheckResult result);
|
||||||
|
|
||||||
|
@ -402,7 +402,7 @@ public:
|
|||||||
virtual std::vector<std::string> unhandledQueries() { return {}; }
|
virtual std::vector<std::string> unhandledQueries() { return {}; }
|
||||||
|
|
||||||
/// @returns how many SMT solvers this interface has.
|
/// @returns how many SMT solvers this interface has.
|
||||||
virtual unsigned solvers() { return 1; }
|
virtual size_t solvers() { return 1; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::optional<unsigned> m_queryTimeout;
|
std::optional<unsigned> m_queryTimeout;
|
||||||
|
@ -217,7 +217,7 @@ z3::expr Z3Interface::toZ3Expr(Expression const& _expr)
|
|||||||
else if (n == "int2bv")
|
else if (n == "int2bv")
|
||||||
{
|
{
|
||||||
size_t size = std::stoul(_expr.arguments[1].name);
|
size_t size = std::stoul(_expr.arguments[1].name);
|
||||||
return z3::int2bv(size, arguments[0]);
|
return z3::int2bv(static_cast<unsigned>(size), arguments[0]);
|
||||||
}
|
}
|
||||||
else if (n == "bv2int")
|
else if (n == "bv2int")
|
||||||
{
|
{
|
||||||
@ -240,7 +240,7 @@ z3::expr Z3Interface::toZ3Expr(Expression const& _expr)
|
|||||||
else if (n == "tuple_get")
|
else if (n == "tuple_get")
|
||||||
{
|
{
|
||||||
size_t index = stoul(_expr.arguments[1].name);
|
size_t index = stoul(_expr.arguments[1].name);
|
||||||
return z3::func_decl(m_context, Z3_get_tuple_sort_field_decl(m_context, z3Sort(*_expr.arguments[0].sort), index))(arguments[0]);
|
return z3::func_decl(m_context, Z3_get_tuple_sort_field_decl(m_context, z3Sort(*_expr.arguments[0].sort), static_cast<unsigned>(index)))(arguments[0]);
|
||||||
}
|
}
|
||||||
else if (n == "tuple_constructor")
|
else if (n == "tuple_constructor")
|
||||||
{
|
{
|
||||||
@ -367,7 +367,7 @@ z3::sort Z3Interface::z3Sort(Sort const& _sort)
|
|||||||
z3::func_decl_vector projs(m_context);
|
z3::func_decl_vector projs(m_context);
|
||||||
z3::func_decl tupleConstructor = m_context.tuple_sort(
|
z3::func_decl tupleConstructor = m_context.tuple_sort(
|
||||||
tupleSort.name.c_str(),
|
tupleSort.name.c_str(),
|
||||||
tupleSort.members.size(),
|
static_cast<unsigned>(tupleSort.members.size()),
|
||||||
cMembers.data(),
|
cMembers.data(),
|
||||||
sorts.data(),
|
sorts.data(),
|
||||||
projs
|
projs
|
||||||
|
@ -208,7 +208,9 @@ void IRGeneratorForStatements::initializeLocalVar(VariableDeclaration const& _va
|
|||||||
solAssert(m_context.isLocalVariable(_varDecl), "Must be a local variable.");
|
solAssert(m_context.isLocalVariable(_varDecl), "Must be a local variable.");
|
||||||
|
|
||||||
auto const* type = _varDecl.type();
|
auto const* type = _varDecl.type();
|
||||||
if (auto const* refType = dynamic_cast<ReferenceType const*>(type))
|
if (dynamic_cast<MappingType const*>(type))
|
||||||
|
return;
|
||||||
|
else if (auto const* refType = dynamic_cast<ReferenceType const*>(type))
|
||||||
if (refType->dataStoredIn(DataLocation::Storage) && refType->isPointer())
|
if (refType->dataStoredIn(DataLocation::Storage) && refType->isPointer())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -1356,10 +1358,13 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
datacopy(<memPos>, dataoffset("<object>"), datasize("<object>"))
|
datacopy(<memPos>, dataoffset("<object>"), datasize("<object>"))
|
||||||
<memEnd> := <abiEncode>(<memEnd><constructorParams>)
|
<memEnd> := <abiEncode>(<memEnd><constructorParams>)
|
||||||
<?saltSet>
|
<?saltSet>
|
||||||
let <retVars> := create2(<value>, <memPos>, sub(<memEnd>, <memPos>), <salt>)
|
let <address> := create2(<value>, <memPos>, sub(<memEnd>, <memPos>), <salt>)
|
||||||
<!saltSet>
|
<!saltSet>
|
||||||
let <retVars> := create(<value>, <memPos>, sub(<memEnd>, <memPos>))
|
let <address> := create(<value>, <memPos>, sub(<memEnd>, <memPos>))
|
||||||
</saltSet>
|
</saltSet>
|
||||||
|
<?isTryCall>
|
||||||
|
let <success> := iszero(iszero(<address>))
|
||||||
|
</isTryCall>
|
||||||
<releaseTemporaryMemory>()
|
<releaseTemporaryMemory>()
|
||||||
)");
|
)");
|
||||||
t("memPos", m_context.newYulVariable());
|
t("memPos", m_context.newYulVariable());
|
||||||
@ -1376,7 +1381,11 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
t("saltSet", functionType->saltSet());
|
t("saltSet", functionType->saltSet());
|
||||||
if (functionType->saltSet())
|
if (functionType->saltSet())
|
||||||
t("salt", IRVariable(_functionCall.expression()).part("salt").name());
|
t("salt", IRVariable(_functionCall.expression()).part("salt").name());
|
||||||
t("retVars", IRVariable(_functionCall).commaSeparatedList());
|
solAssert(IRVariable(_functionCall).stackSlots().size() == 1, "");
|
||||||
|
t("address", IRVariable(_functionCall).commaSeparatedList());
|
||||||
|
t("isTryCall", _functionCall.annotation().tryCall);
|
||||||
|
if (_functionCall.annotation().tryCall)
|
||||||
|
t("success", IRNames::trySuccessConditionVariable(_functionCall));
|
||||||
m_code << t.render();
|
m_code << t.render();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -1993,28 +2002,27 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess)
|
|||||||
}
|
}
|
||||||
case DataLocation::CallData:
|
case DataLocation::CallData:
|
||||||
{
|
{
|
||||||
IRVariable var(m_context.newYulVariable(), *arrayType.baseType());
|
string const indexAccessFunctionCall =
|
||||||
define(var) <<
|
m_utils.calldataArrayIndexAccessFunction(arrayType) +
|
||||||
m_utils.calldataArrayIndexAccessFunction(arrayType) <<
|
"(" +
|
||||||
"(" <<
|
IRVariable(_indexAccess.baseExpression()).commaSeparatedList() +
|
||||||
IRVariable(_indexAccess.baseExpression()).commaSeparatedList() <<
|
", " +
|
||||||
", " <<
|
expressionAsType(*_indexAccess.indexExpression(), *TypeProvider::uint256()) +
|
||||||
expressionAsType(*_indexAccess.indexExpression(), *TypeProvider::uint256()) <<
|
|
||||||
")\n";
|
")\n";
|
||||||
if (arrayType.isByteArray())
|
if (arrayType.isByteArray())
|
||||||
define(_indexAccess) <<
|
define(_indexAccess) <<
|
||||||
m_utils.cleanupFunction(*arrayType.baseType()) <<
|
m_utils.cleanupFunction(*arrayType.baseType()) <<
|
||||||
"(calldataload(" <<
|
"(calldataload(" <<
|
||||||
var.name() <<
|
indexAccessFunctionCall <<
|
||||||
"))\n";
|
"))\n";
|
||||||
else if (arrayType.baseType()->isValueType())
|
else if (arrayType.baseType()->isValueType())
|
||||||
define(_indexAccess) <<
|
define(_indexAccess) <<
|
||||||
m_utils.readFromCalldata(*arrayType.baseType()) <<
|
m_utils.readFromCalldata(*arrayType.baseType()) <<
|
||||||
"(" <<
|
"(" <<
|
||||||
var.commaSeparatedList() <<
|
indexAccessFunctionCall <<
|
||||||
")\n";
|
")\n";
|
||||||
else
|
else
|
||||||
define(_indexAccess, var);
|
define(_indexAccess) << indexAccessFunctionCall;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ public:
|
|||||||
void pushSolver();
|
void pushSolver();
|
||||||
void popSolver();
|
void popSolver();
|
||||||
void addAssertion(smtutil::Expression const& _e);
|
void addAssertion(smtutil::Expression const& _e);
|
||||||
unsigned solverStackHeigh() { return m_assertions.size(); } const
|
size_t solverStackHeigh() { return m_assertions.size(); } const
|
||||||
smtutil::SolverInterface* solver()
|
smtutil::SolverInterface* solver()
|
||||||
{
|
{
|
||||||
solAssert(m_solver, "");
|
solAssert(m_solver, "");
|
||||||
|
@ -349,7 +349,7 @@ bool Predicate::fillArray(smtutil::Expression const& _expr, vector<string>& _arr
|
|||||||
return false;
|
return false;
|
||||||
// Sometimes the solver assigns huge lengths that are not related,
|
// Sometimes the solver assigns huge lengths that are not related,
|
||||||
// we should catch and ignore those.
|
// we should catch and ignore those.
|
||||||
unsigned index;
|
unsigned long index;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
index = stoul(*indexStr);
|
index = stoul(*indexStr);
|
||||||
|
@ -41,7 +41,7 @@ BlockchainVariable::BlockchainVariable(
|
|||||||
{
|
{
|
||||||
members.emplace_back(component);
|
members.emplace_back(component);
|
||||||
sorts.emplace_back(sort);
|
sorts.emplace_back(sort);
|
||||||
m_componentIndices[component] = members.size() - 1;
|
m_componentIndices[component] = static_cast<unsigned>(members.size() - 1);
|
||||||
}
|
}
|
||||||
m_tuple = make_unique<SymbolicTupleVariable>(
|
m_tuple = make_unique<SymbolicTupleVariable>(
|
||||||
make_shared<smtutil::TupleSort>(m_name + "_type", members, sorts),
|
make_shared<smtutil::TupleSort>(m_name + "_type", members, sorts),
|
||||||
|
@ -256,11 +256,11 @@ printTask "Running general commandline tests..."
|
|||||||
do
|
do
|
||||||
printTask " - ${tdir}"
|
printTask " - ${tdir}"
|
||||||
|
|
||||||
# Strip trailing slash from $tdir. `find` on MacOS X won't strip it and will produce double slashes.
|
# Strip trailing slash from $tdir.
|
||||||
tdir=$(basename "${tdir}")
|
tdir=$(basename "${tdir}")
|
||||||
|
|
||||||
inputFiles="$(find "${tdir}" -name 'input.*' -type f -exec printf "%s\n" "{}" \;)"
|
inputFiles="$(ls -1 ${tdir}/input.* 2> /dev/null || true)"
|
||||||
inputCount="$(echo "${inputFiles}" | wc -l)"
|
inputCount="$(echo ${inputFiles} | wc -w)"
|
||||||
if (( ${inputCount} > 1 ))
|
if (( ${inputCount} > 1 ))
|
||||||
then
|
then
|
||||||
printError "Ambiguous input. Found input files in multiple formats:"
|
printError "Ambiguous input. Found input files in multiple formats:"
|
||||||
|
@ -73,117 +73,6 @@ BOOST_AUTO_TEST_CASE(value_types)
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(cleanup)
|
|
||||||
{
|
|
||||||
string sourceCode = R"(
|
|
||||||
contract C {
|
|
||||||
function f(uint16 a, int16 b, address c, bytes3 d, bool e)
|
|
||||||
public pure returns (uint v, uint w, uint x, uint y, uint z) {
|
|
||||||
assembly { v := a w := b x := c y := d z := e}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
bool newDecoder = solidity::test::CommonOptions::get().useABIEncoderV2;
|
|
||||||
BOTH_ENCODERS(
|
|
||||||
compileAndRun(sourceCode);
|
|
||||||
ABI_CHECK(
|
|
||||||
callContractFunction("f(uint16,int16,address,bytes3,bool)", 1, 2, 3, "a", true),
|
|
||||||
encodeArgs(u256(1), u256(2), u256(3), string("a"), true)
|
|
||||||
);
|
|
||||||
ABI_CHECK(
|
|
||||||
callContractFunction(
|
|
||||||
"f(uint16,int16,address,bytes3,bool)",
|
|
||||||
u256(0xffffff), u256(0x1ffff), u256(-1), string("abcd"), u256(1)
|
|
||||||
),
|
|
||||||
newDecoder ? bytes{} : encodeArgs(u256(0xffff), u256(-1), (u256(1) << 160) - 1, string("abc"), true)
|
|
||||||
);
|
|
||||||
ABI_CHECK(
|
|
||||||
callContractFunction(
|
|
||||||
"f(uint16,int16,address,bytes3,bool)",
|
|
||||||
u256(0xffffff), u256(0), u256(0), string("bcd"), u256(1)
|
|
||||||
),
|
|
||||||
newDecoder ? bytes{} : encodeArgs(u256(0xffff), u256(0), 0, string("bcd"), true)
|
|
||||||
);
|
|
||||||
ABI_CHECK(
|
|
||||||
callContractFunction(
|
|
||||||
"f(uint16,int16,address,bytes3,bool)",
|
|
||||||
u256(0), u256(0x1ffff), u256(0), string("ab"), u256(1)
|
|
||||||
),
|
|
||||||
newDecoder ? bytes{} : encodeArgs(u256(0), u256(-1), 0, string("ab"), true)
|
|
||||||
);
|
|
||||||
ABI_CHECK(
|
|
||||||
callContractFunction(
|
|
||||||
"f(uint16,int16,address,bytes3,bool)",
|
|
||||||
u256(0), u256(0), u256(-1), string("ad"), u256(1)
|
|
||||||
),
|
|
||||||
newDecoder ? bytes{} : encodeArgs(u256(0), u256(0), (u256(1) << 160) - 1, string("ad"), true)
|
|
||||||
);
|
|
||||||
ABI_CHECK(
|
|
||||||
callContractFunction(
|
|
||||||
"f(uint16,int16,address,bytes3,bool)",
|
|
||||||
u256(0), u256(0), u256(0), string("abcd"), u256(1)
|
|
||||||
),
|
|
||||||
newDecoder ? bytes{} : encodeArgs(u256(0), u256(0), 0, string("abc"), true)
|
|
||||||
);
|
|
||||||
ABI_CHECK(
|
|
||||||
callContractFunction(
|
|
||||||
"f(uint16,int16,address,bytes3,bool)",
|
|
||||||
u256(0), u256(0), u256(0), string("abc"), u256(2)
|
|
||||||
),
|
|
||||||
newDecoder ? bytes{} : encodeArgs(u256(0), u256(0), 0, string("abc"), true)
|
|
||||||
);
|
|
||||||
newDecoder = true;
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(fixed_arrays)
|
|
||||||
{
|
|
||||||
string sourceCode = R"(
|
|
||||||
contract C {
|
|
||||||
function f(uint16[3] memory a, uint16[2][3] memory b, uint i, uint j, uint k)
|
|
||||||
public pure returns (uint, uint) {
|
|
||||||
return (a[i], b[j][k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
BOTH_ENCODERS(
|
|
||||||
compileAndRun(sourceCode);
|
|
||||||
bytes args = encodeArgs(
|
|
||||||
1, 2, 3,
|
|
||||||
11, 12,
|
|
||||||
21, 22,
|
|
||||||
31, 32,
|
|
||||||
1, 2, 1
|
|
||||||
);
|
|
||||||
ABI_CHECK(
|
|
||||||
callContractFunction("f(uint16[3],uint16[2][3],uint256,uint256,uint256)", args),
|
|
||||||
encodeArgs(u256(2), u256(32))
|
|
||||||
);
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(calldata_arrays_too_large)
|
|
||||||
{
|
|
||||||
string sourceCode = R"(
|
|
||||||
contract C {
|
|
||||||
function f(uint a, uint[] calldata b, uint c) external pure returns (uint) {
|
|
||||||
return 7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
BOTH_ENCODERS(
|
|
||||||
compileAndRun(sourceCode);
|
|
||||||
bytes args = encodeArgs(
|
|
||||||
6, 0x60, 9,
|
|
||||||
(u256(1) << 255) + 2, 1, 2
|
|
||||||
);
|
|
||||||
ABI_CHECK(
|
|
||||||
callContractFunction("f(uint256,uint256[],uint256)", args),
|
|
||||||
encodeArgs()
|
|
||||||
);
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(decode_from_memory_simple)
|
BOOST_AUTO_TEST_CASE(decode_from_memory_simple)
|
||||||
{
|
{
|
||||||
string sourceCode = R"(
|
string sourceCode = R"(
|
||||||
@ -463,121 +352,6 @@ BOOST_AUTO_TEST_CASE(validation_function_type)
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(validation_function_type_inside_struct)
|
|
||||||
{
|
|
||||||
string sourceCode = R"(
|
|
||||||
contract C {
|
|
||||||
struct S { function () external x; }
|
|
||||||
function f(S memory) public pure returns (uint r) { r = 1; }
|
|
||||||
function g(S calldata) external pure returns (uint r) { r = 2; }
|
|
||||||
function h(S calldata s) external pure returns (uint r) { s.x; r = 3; }
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
string validFun{"01234567890123456789abcd"};
|
|
||||||
string invalidFun{"01234567890123456789abcdX"};
|
|
||||||
NEW_ENCODER(
|
|
||||||
compileAndRun(sourceCode);
|
|
||||||
ABI_CHECK(callContractFunction("f((function))", validFun), encodeArgs(1));
|
|
||||||
// Error because we copy to memory
|
|
||||||
ABI_CHECK(callContractFunction("f((function))", invalidFun), encodeArgs());
|
|
||||||
ABI_CHECK(callContractFunction("g((function))", validFun), encodeArgs(2));
|
|
||||||
// No error because x is not accessed.
|
|
||||||
ABI_CHECK(callContractFunction("g((function))", invalidFun), encodeArgs(2));
|
|
||||||
ABI_CHECK(callContractFunction("h((function))", validFun), encodeArgs(3));
|
|
||||||
// Error on access.
|
|
||||||
ABI_CHECK(callContractFunction("h((function))", invalidFun), encodeArgs());
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(storage_ptr)
|
|
||||||
{
|
|
||||||
string sourceCode = R"(
|
|
||||||
library L {
|
|
||||||
struct S { uint x; uint y; }
|
|
||||||
function f(uint[] storage r, S storage s) public returns (uint, uint, uint, uint) {
|
|
||||||
r[2] = 8;
|
|
||||||
s.x = 7;
|
|
||||||
return (r[0], r[1], s.x, s.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
contract C {
|
|
||||||
uint8 x = 3;
|
|
||||||
L.S s;
|
|
||||||
uint[] r;
|
|
||||||
function f() public returns (uint, uint, uint, uint, uint, uint) {
|
|
||||||
r = new uint[](6);
|
|
||||||
r[0] = 1;
|
|
||||||
r[1] = 2;
|
|
||||||
r[2] = 3;
|
|
||||||
s.x = 11;
|
|
||||||
s.y = 12;
|
|
||||||
(uint a, uint b, uint c, uint d) = L.f(r, s);
|
|
||||||
return (r[2], s.x, a, b, c, d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
BOTH_ENCODERS(
|
|
||||||
compileAndRun(sourceCode, 0, "L");
|
|
||||||
compileAndRun(sourceCode, 0, "C", bytes(), map<string, Address>{{"L", m_contractAddress}});
|
|
||||||
ABI_CHECK(callContractFunction("f()"), encodeArgs(8, 7, 1, 2, 7, 12));
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(struct_simple)
|
|
||||||
{
|
|
||||||
string sourceCode = R"(
|
|
||||||
contract C {
|
|
||||||
struct S { uint a; uint8 b; uint8 c; bytes2 d; }
|
|
||||||
function f(S memory s) public pure returns (uint a, uint b, uint c, uint d) {
|
|
||||||
a = s.a;
|
|
||||||
b = s.b;
|
|
||||||
c = s.c;
|
|
||||||
d = uint16(s.d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
NEW_ENCODER(
|
|
||||||
compileAndRun(sourceCode, 0, "C");
|
|
||||||
ABI_CHECK(callContractFunction("f((uint256,uint8,uint8,bytes2))", 1, 2, 3, "ab"), encodeArgs(1, 2, 3, 'a' * 0x100 + 'b'));
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(struct_validation)
|
|
||||||
{
|
|
||||||
string sourceCode = R"(
|
|
||||||
contract C {
|
|
||||||
struct S { int16 a; uint8 b; bytes2 c; }
|
|
||||||
function f(S memory s) public pure returns (uint a, uint b, uint c) {
|
|
||||||
assembly {
|
|
||||||
a := mload(s)
|
|
||||||
b := mload(add(s, 0x20))
|
|
||||||
c := mload(add(s, 0x40))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
u256 largeNeg("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01");
|
|
||||||
NEW_ENCODER(
|
|
||||||
compileAndRun(sourceCode, 0, "C");
|
|
||||||
ABI_CHECK(
|
|
||||||
callContractFunction("f((int16,uint8,bytes2))", largeNeg, 0xff, "ab"),
|
|
||||||
encodeArgs(largeNeg, 0xff, "ab")
|
|
||||||
);
|
|
||||||
ABI_CHECK(
|
|
||||||
callContractFunction("f((int16,uint8,bytes2))", 0xff010, 0xff, "ab"),
|
|
||||||
encodeArgs()
|
|
||||||
);
|
|
||||||
ABI_CHECK(
|
|
||||||
callContractFunction("f((int16,uint8,bytes2))", largeNeg, 0xff0002, "ab"),
|
|
||||||
encodeArgs()
|
|
||||||
);
|
|
||||||
ABI_CHECK(
|
|
||||||
callContractFunction("f((int16,uint8,bytes2))", largeNeg, 0xff, "abcd"),
|
|
||||||
encodeArgs()
|
|
||||||
);
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(struct_short)
|
BOOST_AUTO_TEST_CASE(struct_short)
|
||||||
{
|
{
|
||||||
string sourceCode = R"(
|
string sourceCode = R"(
|
||||||
@ -605,73 +379,6 @@ BOOST_AUTO_TEST_CASE(struct_short)
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(struct_function)
|
|
||||||
{
|
|
||||||
string sourceCode = R"(
|
|
||||||
contract C {
|
|
||||||
struct S { function () external returns (uint) f; uint b; }
|
|
||||||
function f(S memory s) public returns (uint, uint) {
|
|
||||||
return (s.f(), s.b);
|
|
||||||
}
|
|
||||||
function test() public returns (uint, uint) {
|
|
||||||
return this.f(S(this.g, 3));
|
|
||||||
}
|
|
||||||
function g() public returns (uint) { return 7; }
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
NEW_ENCODER(
|
|
||||||
compileAndRun(sourceCode, 0, "C");
|
|
||||||
ABI_CHECK(callContractFunction("test()"), encodeArgs(7, 3));
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(mediocre_struct)
|
|
||||||
{
|
|
||||||
string sourceCode = R"(
|
|
||||||
contract C {
|
|
||||||
struct S { C c; }
|
|
||||||
function f(uint a, S[2] memory s1, uint b) public returns (uint r1, C r2, uint r3) {
|
|
||||||
r1 = a;
|
|
||||||
r2 = s1[0].c;
|
|
||||||
r3 = b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
NEW_ENCODER(
|
|
||||||
compileAndRun(sourceCode, 0, "C");
|
|
||||||
string sig = "f(uint256,(address)[2],uint256)";
|
|
||||||
ABI_CHECK(callContractFunction(sig,
|
|
||||||
7, u256(u160(m_contractAddress)), 0, 8
|
|
||||||
), encodeArgs(7, u256(u160(m_contractAddress)), 8));
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(mediocre2_struct)
|
|
||||||
{
|
|
||||||
string sourceCode = R"(
|
|
||||||
contract C {
|
|
||||||
struct S { C c; uint[] x; }
|
|
||||||
function f(uint a, S[2] memory s1, uint b) public returns (uint r1, C r2, uint r3) {
|
|
||||||
r1 = a;
|
|
||||||
r2 = s1[0].c;
|
|
||||||
r3 = b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
NEW_ENCODER(
|
|
||||||
compileAndRun(sourceCode, 0, "C");
|
|
||||||
string sig = "f(uint256,(address,uint256[])[2],uint256)";
|
|
||||||
ABI_CHECK(callContractFunction(sig,
|
|
||||||
7, 0x60, 8,
|
|
||||||
0x40, 7 * 0x20,
|
|
||||||
u256(u160(m_contractAddress)), 0x40,
|
|
||||||
2, 0x11, 0x12,
|
|
||||||
0x99, 0x40,
|
|
||||||
4, 0x31, 0x32, 0x34, 0x35
|
|
||||||
), encodeArgs(7, u256(u160(m_contractAddress)), 8));
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(complex_struct)
|
BOOST_AUTO_TEST_CASE(complex_struct)
|
||||||
{
|
{
|
||||||
string sourceCode = R"(
|
string sourceCode = R"(
|
||||||
@ -731,108 +438,6 @@ BOOST_AUTO_TEST_CASE(complex_struct)
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(return_dynamic_types_cross_call_simple)
|
|
||||||
{
|
|
||||||
if (m_evmVersion == langutil::EVMVersion::homestead())
|
|
||||||
return;
|
|
||||||
|
|
||||||
string sourceCode = R"(
|
|
||||||
contract C {
|
|
||||||
function dyn() public returns (bytes memory) {
|
|
||||||
return "1234567890123456789012345678901234567890";
|
|
||||||
}
|
|
||||||
function f() public returns (bytes memory) {
|
|
||||||
return this.dyn();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
BOTH_ENCODERS(
|
|
||||||
compileAndRun(sourceCode, 0, "C");
|
|
||||||
ABI_CHECK(callContractFunction("f()"), encodeArgs(0x20, 40, string("1234567890123456789012345678901234567890")));
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(return_dynamic_types_cross_call_advanced)
|
|
||||||
{
|
|
||||||
if (m_evmVersion == langutil::EVMVersion::homestead())
|
|
||||||
return;
|
|
||||||
|
|
||||||
string sourceCode = R"(
|
|
||||||
contract C {
|
|
||||||
function dyn() public returns (bytes memory a, uint b, bytes20[] memory c, uint d) {
|
|
||||||
a = "1234567890123456789012345678901234567890";
|
|
||||||
b = type(uint).max;
|
|
||||||
c = new bytes20[](4);
|
|
||||||
c[0] = bytes20(uint160(1234));
|
|
||||||
c[3] = bytes20(uint160(6789));
|
|
||||||
d = 0x1234;
|
|
||||||
}
|
|
||||||
function f() public returns (bytes memory, uint, bytes20[] memory, uint) {
|
|
||||||
return this.dyn();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
BOTH_ENCODERS(
|
|
||||||
compileAndRun(sourceCode, 0, "C");
|
|
||||||
ABI_CHECK(callContractFunction("f()"), encodeArgs(
|
|
||||||
0x80, u256(-1), 0xe0, 0x1234,
|
|
||||||
40, string("1234567890123456789012345678901234567890"),
|
|
||||||
4, u256(1234) << (8 * (32 - 20)), 0, 0, u256(6789) << (8 * (32 - 20))
|
|
||||||
));
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(return_dynamic_types_cross_call_out_of_range)
|
|
||||||
{
|
|
||||||
string sourceCode = R"(
|
|
||||||
contract C {
|
|
||||||
function dyn(uint x) public returns (bytes memory a) {
|
|
||||||
assembly {
|
|
||||||
mstore(0, 0x20)
|
|
||||||
mstore(0x20, 0x21)
|
|
||||||
return(0, x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function f(uint x) public returns (bool) {
|
|
||||||
this.dyn(x);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
BOTH_ENCODERS(
|
|
||||||
compileAndRun(sourceCode, 0, "C");
|
|
||||||
if (m_evmVersion == langutil::EVMVersion::homestead())
|
|
||||||
{
|
|
||||||
ABI_CHECK(callContractFunction("f(uint256)", 0x60), encodeArgs(true));
|
|
||||||
ABI_CHECK(callContractFunction("f(uint256)", 0x7f), encodeArgs(true));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ABI_CHECK(callContractFunction("f(uint256)", 0x60), encodeArgs());
|
|
||||||
ABI_CHECK(callContractFunction("f(uint256)", 0x61), encodeArgs(true));
|
|
||||||
}
|
|
||||||
ABI_CHECK(callContractFunction("f(uint256)", 0x80), encodeArgs(true));
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(out_of_bounds_bool_value)
|
|
||||||
{
|
|
||||||
string sourceCode = R"(
|
|
||||||
contract C {
|
|
||||||
function f(bool b) public pure returns (bool) { return b; }
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
bool newDecoder = solidity::test::CommonOptions::get().useABIEncoderV2;
|
|
||||||
BOTH_ENCODERS(
|
|
||||||
compileAndRun(sourceCode);
|
|
||||||
ABI_CHECK(callContractFunction("f(bool)", true), encodeArgs(true));
|
|
||||||
ABI_CHECK(callContractFunction("f(bool)", false), encodeArgs(false));
|
|
||||||
ABI_CHECK(callContractFunctionNoEncoding("f(bool)", bytes(32, 0)), encodeArgs(0));
|
|
||||||
ABI_CHECK(callContractFunctionNoEncoding("f(bool)", bytes(32, 0xff)), newDecoder ? encodeArgs() : encodeArgs(1));
|
|
||||||
newDecoder = true;
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
} // end namespaces
|
} // end namespaces
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
contract C {
|
||||||
|
function f(uint16[3] memory a, uint16[2][3] memory b, uint i, uint j, uint k)
|
||||||
|
public pure returns (uint, uint) {
|
||||||
|
return (a[i], b[j][k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// f(uint16[3],uint16[2][3],uint256,uint256,uint256): 1, 2, 3, 11, 12, 21, 22, 31, 32, 1, 2, 1 -> 2, 32
|
@ -0,0 +1,10 @@
|
|||||||
|
contract C {
|
||||||
|
function f(bool b) public pure returns (bool) { return b; }
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// ABIEncoderV1Only: true
|
||||||
|
// ----
|
||||||
|
// f(bool): true -> true
|
||||||
|
// f(bool): false -> false
|
||||||
|
// f(bool): 0x000000 -> false
|
||||||
|
// f(bool): 0xffffff -> true
|
@ -0,0 +1,9 @@
|
|||||||
|
contract C {
|
||||||
|
function f(uint a, uint[] calldata b, uint c) external pure returns (uint) {
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// f(uint256,uint256[],uint256): 6, 0x60, 9, 0x8000000000000000000000000000000000000000000000000000000000000002, 1, 2 -> FAILURE
|
@ -0,0 +1,16 @@
|
|||||||
|
contract C {
|
||||||
|
function f(uint16 a, int16 b, address c, bytes3 d, bool e)
|
||||||
|
public pure returns (uint v, uint w, uint x, uint y, uint z) {
|
||||||
|
assembly { v := a w := b x := c y := d z := e}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// ABIEncoderV1Only: true
|
||||||
|
// ----
|
||||||
|
// f(uint16,int16,address,bytes3,bool): 1, 2, 3, "a", true -> 1, 2, 3, "a", true
|
||||||
|
// f(uint16,int16,address,bytes3,bool): 0xffffff, 0x1ffff, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, "abcd", 1 -> 0xffff, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffffffffffffff, "abc", true
|
||||||
|
// f(uint16,int16,address,bytes3,bool): 0xffffff, 0, 0, "bcd", 1 -> 0xffff, 0, 0, "bcd", true
|
||||||
|
// f(uint16,int16,address,bytes3,bool): 0, 0x1ffff, 0, "ab", 1 -> 0, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 0, "ab", true
|
||||||
|
// f(uint16,int16,address,bytes3,bool): 0, 0, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, "ad", 1 -> 0, 0, 0xffffffffffffffffffffffffffffffffffffffff, "ad", true
|
||||||
|
// f(uint16,int16,address,bytes3,bool): 0, 0, 0, "abcd", 1 -> 0, 0, 0, "abc", true
|
||||||
|
// f(uint16,int16,address,bytes3,bool): 0, 0, 0, "abc", 2 -> 0, 0, 0, "abc", true
|
@ -0,0 +1,18 @@
|
|||||||
|
contract C {
|
||||||
|
function dyn() public returns (bytes memory a, uint b, bytes20[] memory c, uint d) {
|
||||||
|
a = "1234567890123456789012345678901234567890";
|
||||||
|
b = type(uint).max;
|
||||||
|
c = new bytes20[](4);
|
||||||
|
c[0] = bytes20(uint160(1234));
|
||||||
|
c[3] = bytes20(uint160(6789));
|
||||||
|
d = 0x1234;
|
||||||
|
}
|
||||||
|
function f() public returns (bytes memory, uint, bytes20[] memory, uint) {
|
||||||
|
return this.dyn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// EVMVersion: >homestead
|
||||||
|
// ----
|
||||||
|
// f() -> 0x80, -1, 0xe0, 0x1234, 40, "12345678901234567890123456789012", "34567890", 4, 97767552542602192590433234714624, 0, 0, 537879995309340587922569878831104
|
@ -0,0 +1,20 @@
|
|||||||
|
contract C {
|
||||||
|
function dyn(uint x) public returns (bytes memory a) {
|
||||||
|
assembly {
|
||||||
|
mstore(0, 0x20)
|
||||||
|
mstore(0x20, 0x21)
|
||||||
|
return(0, x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function f(uint x) public returns (bool) {
|
||||||
|
this.dyn(x);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// EVMVersion: =homestead
|
||||||
|
// ----
|
||||||
|
// f(uint256): 0x60 -> true
|
||||||
|
// f(uint256): 0x7f -> true
|
||||||
|
// f(uint256): 0x80 -> true
|
@ -0,0 +1,20 @@
|
|||||||
|
contract C {
|
||||||
|
function dyn(uint x) public returns (bytes memory a) {
|
||||||
|
assembly {
|
||||||
|
mstore(0, 0x20)
|
||||||
|
mstore(0x20, 0x21)
|
||||||
|
return(0, x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function f(uint x) public returns (bool) {
|
||||||
|
this.dyn(x);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// EVMVersion: >homestead
|
||||||
|
// ----
|
||||||
|
// f(uint256): 0x60 -> FAILURE
|
||||||
|
// f(uint256): 0x61 -> true
|
||||||
|
// f(uint256): 0x80 -> true
|
@ -0,0 +1,13 @@
|
|||||||
|
contract C {
|
||||||
|
function dyn() public returns (bytes memory) {
|
||||||
|
return "1234567890123456789012345678901234567890";
|
||||||
|
}
|
||||||
|
function f() public returns (bytes memory) {
|
||||||
|
return this.dyn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// EVMVersion: >homestead
|
||||||
|
// ----
|
||||||
|
// f() -> 0x20, 40, "12345678901234567890123456789012", "34567890"
|
@ -0,0 +1,26 @@
|
|||||||
|
library L {
|
||||||
|
struct S { uint x; uint y; }
|
||||||
|
function f(uint[] storage r, S storage s) public returns (uint, uint, uint, uint) {
|
||||||
|
r[2] = 8;
|
||||||
|
s.x = 7;
|
||||||
|
return (r[0], r[1], s.x, s.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contract C {
|
||||||
|
uint8 x = 3;
|
||||||
|
L.S s;
|
||||||
|
uint[] r;
|
||||||
|
function f() public returns (uint, uint, uint, uint, uint, uint) {
|
||||||
|
r = new uint[](6);
|
||||||
|
r[0] = 1;
|
||||||
|
r[1] = 2;
|
||||||
|
r[2] = 3;
|
||||||
|
s.x = 11;
|
||||||
|
s.y = 12;
|
||||||
|
(uint a, uint b, uint c, uint d) = L.f(r, s);
|
||||||
|
return (r[2], s.x, a, b, c, d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// library: L
|
||||||
|
// f() -> 8, 7, 1, 2, 7, 12
|
@ -0,0 +1,12 @@
|
|||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
function f(bool b) public pure returns (bool) { return b; }
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// f(bool): true -> true
|
||||||
|
// f(bool): false -> false
|
||||||
|
// f(bool): 0x000000 -> false
|
||||||
|
// f(bool): 0xffffff -> FAILURE
|
@ -25,6 +25,8 @@ contract C {
|
|||||||
return reenc ? this.f_reenc(a) : this.f(a);
|
return reenc ? this.f_reenc(a) : this.f(a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// g(bool): false -> 23, 37, 71
|
// g(bool): false -> 23, 37, 71
|
||||||
// g(bool): true -> 23, 37, 71
|
// g(bool): true -> 23, 37, 71
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
function f(uint16 a, int16 b, address c, bytes3 d, bool e)
|
||||||
|
public pure returns (uint v, uint w, uint x, uint y, uint z) {
|
||||||
|
assembly { v := a w := b x := c y := d z := e}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// f(uint16,int16,address,bytes3,bool): 1, 2, 3, "a", true -> 1, 2, 3, "a", true
|
||||||
|
// f(uint16,int16,address,bytes3,bool): 0xffffff, 0x1ffff, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, "abcd", 1 -> FAILURE
|
||||||
|
// f(uint16,int16,address,bytes3,bool): 0xffffff, 0, 0, "bcd", 1 -> FAILURE
|
||||||
|
// f(uint16,int16,address,bytes3,bool): 0, 0x1ffff, 0, "ab", 1 -> FAILURE
|
||||||
|
// f(uint16,int16,address,bytes3,bool): 0, 0, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, "ad", 1 -> FAILURE
|
||||||
|
// f(uint16,int16,address,bytes3,bool): 0, 0, 0, "abcd", 1 -> FAILURE
|
||||||
|
// f(uint16,int16,address,bytes3,bool): 0, 0, 0, "abc", 2 -> FAILURE
|
@ -0,0 +1,14 @@
|
|||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
struct S { C c; uint[] x; }
|
||||||
|
function f(uint a, S[2] memory s1, uint b) public returns (uint r1, C r2, uint r3) {
|
||||||
|
r1 = a;
|
||||||
|
r2 = s1[0].c;
|
||||||
|
r3 = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// f(uint256,(address,uint256[])[2],uint256): 7, 0x60, 8, 0x40, 0xE0, 0x0, 0x40, 2, 0x11, 0x12, 0x99, 0x40, 4, 0x31, 0x32, 0x34, 0x35 -> 7, 0x0, 8
|
@ -0,0 +1,14 @@
|
|||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
struct S { C c; }
|
||||||
|
function f(uint a, S[2] memory s1, uint b) public returns (uint r1, C r2, uint r3) {
|
||||||
|
r1 = a;
|
||||||
|
r2 = s1[0].c;
|
||||||
|
r3 = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// f(uint256,(address)[2],uint256): 7, 0, 0, 8 -> 7, 0, 8
|
@ -0,0 +1,16 @@
|
|||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
struct S { function () external returns (uint) f; uint b; }
|
||||||
|
function f(S memory s) public returns (uint, uint) {
|
||||||
|
return (s.f(), s.b);
|
||||||
|
}
|
||||||
|
function test() public returns (uint, uint) {
|
||||||
|
return this.f(S(this.g, 3));
|
||||||
|
}
|
||||||
|
function g() public returns (uint) { return 7; }
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// test() -> 7, 3
|
@ -0,0 +1,13 @@
|
|||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
struct S { int a; uint b; bytes16 c; }
|
||||||
|
function f(S memory s) public pure returns (S memory q) {
|
||||||
|
q = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// f((int256,uint256,bytes16)): 0xff010, 0xff0002, "abcd" -> 0xff010, 0xff0002, "abcd"
|
||||||
|
// f((int256,uint256,bytes16)): 0xff010, 0xff0002, 0x1111222233334444555566667777888800000000000000000000000000000000 -> 0xff010, 0xff0002, left(0x11112222333344445555666677778888)
|
@ -0,0 +1,15 @@
|
|||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
struct S { uint a; uint8 b; uint8 c; bytes2 d; }
|
||||||
|
function f(S memory s) public pure returns (uint a, uint b, uint c, uint d) {
|
||||||
|
a = s.a;
|
||||||
|
b = s.b;
|
||||||
|
c = s.c;
|
||||||
|
d = uint16(s.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// f((uint256,uint8,uint8,bytes2)): 1, 2, 3, "ab" -> 1, 2, 3, 0x6162
|
@ -0,0 +1,19 @@
|
|||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
struct S { int16 a; uint8 b; bytes2 c; }
|
||||||
|
function f(S memory s) public pure returns (uint a, uint b, uint c) {
|
||||||
|
assembly {
|
||||||
|
a := mload(s)
|
||||||
|
b := mload(add(s, 0x20))
|
||||||
|
c := mload(add(s, 0x40))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// f((int16,uint8,bytes2)): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01, 0xff, "ab" -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01, 0xff, "ab"
|
||||||
|
// f((int16,uint8,bytes2)): 0xff010, 0xff, "ab" -> FAILURE
|
||||||
|
// f((int16,uint8,bytes2)): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01, 0xff0002, "ab" -> FAILURE
|
||||||
|
// f((int16,uint8,bytes2)): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01, 0xff, "abcd" -> FAILURE
|
@ -0,0 +1,17 @@
|
|||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
struct S { function () external x; }
|
||||||
|
function f(S memory) public pure returns (uint r) { r = 1; }
|
||||||
|
function g(S calldata) external pure returns (uint r) { r = 2; }
|
||||||
|
function h(S calldata s) external pure returns (uint r) { s.x; r = 3; }
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// f((function)): "01234567890123456789abcd" -> 1
|
||||||
|
// f((function)): "01234567890123456789abcdX" -> FAILURE
|
||||||
|
// g((function)): "01234567890123456789abcd" -> 2
|
||||||
|
// g((function)): "01234567890123456789abcdX" -> 2
|
||||||
|
// h((function)): "01234567890123456789abcd" -> 3
|
||||||
|
// h((function)): "01234567890123456789abcdX" -> FAILURE
|
@ -17,6 +17,8 @@ contract test {
|
|||||||
return (a[0], a[1], a[2], b[0], b[1], b[2]);
|
return (a[0], a[1], a[2], b[0], b[1], b[2]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// g() -> 0, 42, 0, 0, 84, 21
|
// g() -> 0, 42, 0, 0, 84, 21
|
||||||
// h() -> 0, 42, 0, 0, 84, 17
|
// h() -> 0, 42, 0, 0, 84, 17
|
||||||
|
@ -12,6 +12,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// EVMVersion: >=tangerineWhistle
|
// EVMVersion: >=tangerineWhistle
|
||||||
// ----
|
// ----
|
||||||
// f() -> true
|
// f() -> true
|
||||||
|
@ -17,6 +17,7 @@ contract A {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// EVMVersion: >=constantinople
|
// EVMVersion: >=constantinople
|
||||||
// ----
|
// ----
|
||||||
// different_salt() -> true
|
// different_salt() -> true
|
||||||
|
@ -26,6 +26,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// EVMVersion: >=byzantium
|
// EVMVersion: >=byzantium
|
||||||
// ----
|
// ----
|
||||||
// f() -> 0, 0, 96, 13, "test message."
|
// f() -> 0, 0, 96, 13, "test message."
|
||||||
|
Loading…
Reference in New Issue
Block a user