Merge remote-tracking branch 'origin/develop' into breaking

This commit is contained in:
chriseth
2020-05-12 17:48:53 +02:00
342 changed files with 4644 additions and 1159 deletions
+1 -1
View File
@@ -187,7 +187,7 @@ add_executable(soltest ${sources}
${libsolidity_util_sources}
${yul_phaser_sources}
)
target_link_libraries(soltest PRIVATE libsolc yul solidity yulInterpreter evmasm solutil Boost::boost Boost::program_options Boost::unit_test_framework evmc)
target_link_libraries(soltest PRIVATE libsolc yul solidity yulInterpreter evmasm solutil Boost::boost Boost::filesystem Boost::program_options Boost::unit_test_framework evmc)
# Special compilation flag for Visual Studio (version 2019 at least affected)
+1 -1
View File
@@ -94,7 +94,7 @@ CommonOptions::CommonOptions(std::string _caption):
("evmonepath", po::value<fs::path>(&evmonePath)->default_value(EVMOneEnvOrDefaultPath()), "path to evmone library")
("no-smt", po::bool_switch(&disableSMT), "disable SMT checker")
("optimize", po::bool_switch(&optimize), "enables optimization")
("optimize-yul", po::bool_switch(&optimizeYul), "enables Yul optimization")
("enforce-via-yul", po::bool_switch(&enforceViaYul), "Enforce compiling all tests via yul to see if additional tests can be activated.")
("abiencoderv2", po::bool_switch(&useABIEncoderV2), "enables abi encoder v2")
("show-messages", po::bool_switch(&showMessages), "enables message output")
("show-metadata", po::bool_switch(&showMetadata), "enables metadata output");
+1 -1
View File
@@ -46,7 +46,7 @@ struct CommonOptions: boost::noncopyable
boost::filesystem::path evmonePath;
boost::filesystem::path testPath;
bool optimize = false;
bool optimizeYul = false;
bool enforceViaYul = false;
bool disableSMT = false;
bool useABIEncoderV2 = false;
bool showMessages = false;
+1 -3
View File
@@ -49,9 +49,7 @@ ExecutionFramework::ExecutionFramework(langutil::EVMVersion _evmVersion):
m_showMessages(solidity::test::CommonOptions::get().showMessages),
m_evmHost(make_shared<EVMHost>(m_evmVersion))
{
if (solidity::test::CommonOptions::get().optimizeYul)
m_optimiserSettings = solidity::frontend::OptimiserSettings::full();
else if (solidity::test::CommonOptions::get().optimize)
if (solidity::test::CommonOptions::get().optimize)
m_optimiserSettings = solidity::frontend::OptimiserSettings::standard();
reset();
+5
View File
@@ -40,6 +40,11 @@ void TestCase::printSettings(ostream& _stream, const string& _linePrefix, const
_stream << _linePrefix << "// " << setting.first << ": " << setting.second << endl;
}
void TestCase::printUpdatedSettings(std::ostream& _stream, std::string const& _linePrefix)
{
printSettings(_stream, _linePrefix);
}
bool TestCase::isTestFilename(boost::filesystem::path const& _filename)
{
string extension = _filename.extension().string();
+3
View File
@@ -38,6 +38,7 @@ public:
{
std::string filename;
langutil::EVMVersion evmVersion;
bool enforceCompileViaYul;
};
enum class TestResult { Success, Failure, FatalError };
@@ -59,6 +60,8 @@ public:
virtual void printSource(std::ostream &_stream, std::string const &_linePrefix = "", bool const _formatted = false) const = 0;
/// Outputs settings.
virtual void printSettings(std::ostream &_stream, std::string const &_linePrefix = "", bool const _formatted = false);
/// Outputs updated settings
virtual void printUpdatedSettings(std::ostream& _stream, std::string const& _linePrefix = "");
/// Outputs test expectations to @arg _stream that match the actual results of the test.
/// Each line of output is prefixed with @arg _linePrefix.
virtual void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const = 0;
+9 -2
View File
@@ -64,12 +64,13 @@ int registerTests(
boost::unit_test::test_suite& _suite,
boost::filesystem::path const& _basepath,
boost::filesystem::path const& _path,
bool _enforceViaYul,
TestCase::TestCaseCreator _testCaseCreator
)
{
int numTestsAdded = 0;
fs::path fullpath = _basepath / _path;
TestCase::Config config{fullpath.string(), solidity::test::CommonOptions::get().evmVersion()};
TestCase::Config config{fullpath.string(), solidity::test::CommonOptions::get().evmVersion(), _enforceViaYul};
if (fs::is_directory(fullpath))
{
test_suite* sub_suite = BOOST_TEST_SUITE(_path.filename().string());
@@ -78,7 +79,12 @@ int registerTests(
fs::directory_iterator()
))
if (fs::is_directory(entry.path()) || TestCase::isTestFilename(entry.path().filename()))
numTestsAdded += registerTests(*sub_suite, _basepath, _path / entry.path().filename(), _testCaseCreator);
numTestsAdded += registerTests(
*sub_suite,
_basepath, _path / entry.path().filename(),
_enforceViaYul,
_testCaseCreator
);
_suite.add(sub_suite);
}
else
@@ -164,6 +170,7 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] )
master,
options.testPath / ts.path,
ts.subpath,
options.enforceViaYul,
ts.testCaseCreator
) > 0, std::string("no ") + ts.title + " tests found");
}
+12 -1
View File
@@ -245,7 +245,18 @@ printTask "Running general commandline tests..."
stdoutExpectationFile="${tdir}/output.json"
args="--standard-json "$(cat ${tdir}/args 2>/dev/null || true)
else
inputFile="${tdir}input.sol"
if [[ -e "${tdir}input.yul" && -e "${tdir}input.sol" ]]
then
printError "Ambiguous input. Found both input.sol and input.yul."
exit 1
fi
if [ -e "${tdir}input.yul" ]
then
inputFile="${tdir}input.yul"
else
inputFile="${tdir}input.sol"
fi
stdin=""
stdout="$(cat ${tdir}/output 2>/dev/null || true)"
stdoutExpectationFile="${tdir}/output"
+1 -1
View File
@@ -5,7 +5,7 @@ EVM assembly:
mstore(0x40, 0x80)
/* "optimizer_user_yul/input.sol":72:77 int a */
0x00
/* "optimizer_user_yul/input.sol":38:487 constructor() public payable... */
/* "optimizer_user_yul/input.sol":152:161 let x,y,z */
dup1
0x00
dup1
@@ -65,7 +65,7 @@ object \"C_6\" {
mstore(64, newFreePtr)
}
function fun_f_5() {
function fun_f_5() {
}
@@ -0,0 +1,26 @@
{
"language": "Yul",
"sources":
{
"A":
{
"content": "{ let x := mload(0) sstore(add(x, 0), 0) }"
}
},
"settings":
{
"optimizer": {
"enabled": true,
"details": {
"yul": true,
"yulDetails": {
"optimizerSteps": "dhfoDgvulfnTUtnIf"
}
}
},
"outputSelection":
{
"*": { "*": ["*"], "": [ "*" ] }
}
}
}
@@ -0,0 +1,30 @@
{"contracts":{"A":{"object":{"evm":{"assembly":" /* \"A\":17:18 */
0x00
/* \"A\":11:19 */
mload
/* \"A\":38:39 */
0x00
/* \"A\":34:35 */
0x00
/* \"A\":31:32 */
dup3
/* \"A\":27:36 */
add
/* \"A\":20:40 */
sstore
pop
","bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}},"ir":"object \"object\" {
code {
let x := mload(0)
sstore(add(x, 0), 0)
}
}
","irOptimized":"object \"object\" {
code {
{
let x := mload(0)
sstore(add(x, 0), 0)
}
}
}
"}}},"errors":[{"component":"general","formattedMessage":"Yul is still experimental. Please use the output with care.","message":"Yul is still experimental. Please use the output with care.","severity":"warning","type":"Warning"}]}
@@ -0,0 +1 @@
--strict-assembly --optimize --yul-optimizations dhfoDgvulfnTUtnIf
@@ -0,0 +1 @@
Warning: Yul is still experimental. Please use the output with care.
@@ -0,0 +1,27 @@
object "C_6" {
code {
mstore(64, 128)
if callvalue() { revert(0, 0) }
codecopy(0, dataoffset("C_6_deployed"), datasize("C_6_deployed"))
return(0, datasize("C_6_deployed"))
}
object "C_6_deployed" {
code {
{
mstore(64, 128)
if iszero(lt(calldatasize(), 4))
{
let selector := shift_right_224_unsigned(calldataload(0))
pop(selector)
}
pop(iszero(calldatasize()))
revert(0, 0)
}
function shift_right_224_unsigned(value) -> newValue
{
newValue := shr(224, value)
}
}
}
}
@@ -0,0 +1,88 @@
======= strict_asm_optimizer_steps/input.yul (EVM) =======
Pretty printed source:
object "C_6" {
code {
{
mstore(64, 128)
if callvalue() { revert(0, 0) }
codecopy(0, dataoffset("C_6_deployed"), datasize("C_6_deployed"))
return(0, datasize("C_6_deployed"))
}
}
object "C_6_deployed" {
code {
{
mstore(64, 128)
pop(iszero(lt(calldatasize(), 4)))
revert(0, 0)
}
}
}
}
Binary representation:
60806040523415600f5760006000fd5b6010601d60003960106000f3fe608060405260043610155060006000fd
Text representation:
/* "strict_asm_optimizer_steps/input.yul":45:48 */
0x80
/* "strict_asm_optimizer_steps/input.yul":41:43 */
0x40
/* "strict_asm_optimizer_steps/input.yul":34:49 */
mstore
/* "strict_asm_optimizer_steps/input.yul":61:72 */
callvalue
/* "strict_asm_optimizer_steps/input.yul":58:60 */
iszero
tag_1
jumpi
/* "strict_asm_optimizer_steps/input.yul":85:86 */
0x00
/* "strict_asm_optimizer_steps/input.yul":82:83 */
0x00
/* "strict_asm_optimizer_steps/input.yul":75:87 */
revert
/* "strict_asm_optimizer_steps/input.yul":58:60 */
tag_1:
/* "strict_asm_optimizer_steps/input.yul":98:163 */
dataSize(sub_0)
dataOffset(sub_0)
/* "strict_asm_optimizer_steps/input.yul":107:108 */
0x00
/* "strict_asm_optimizer_steps/input.yul":98:163 */
codecopy
/* "strict_asm_optimizer_steps/input.yul":172:207 */
dataSize(sub_0)
/* "strict_asm_optimizer_steps/input.yul":179:180 */
0x00
/* "strict_asm_optimizer_steps/input.yul":172:207 */
return
stop
sub_0: assembly {
/* "strict_asm_optimizer_steps/input.yul":298:301 */
0x80
/* "strict_asm_optimizer_steps/input.yul":294:296 */
0x40
/* "strict_asm_optimizer_steps/input.yul":287:302 */
mstore
/* "strict_asm_optimizer_steps/input.yul":348:349 */
0x04
/* "strict_asm_optimizer_steps/input.yul":332:346 */
calldatasize
/* "strict_asm_optimizer_steps/input.yul":329:350 */
lt
/* "strict_asm_optimizer_steps/input.yul":322:351 */
iszero
/* "strict_asm_optimizer_steps/input.yul":319:321 */
pop
/* "strict_asm_optimizer_steps/input.yul":570:571 */
0x00
/* "strict_asm_optimizer_steps/input.yul":567:568 */
0x00
/* "strict_asm_optimizer_steps/input.yul":560:572 */
revert
}
@@ -38,7 +38,7 @@ object \"C_10\" {
abi_decode_tuple_(4, calldatasize())
let ret_0 := fun_f_9()
let memPos := allocateMemory(0)
let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0)
let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0)
return(memPos, sub(memEnd, memPos))
}
@@ -107,7 +107,7 @@ object \"C_10\" {
}
}
function fun_f_9() -> vloc__4_mpos {
function fun_f_9() -> vloc__4_mpos {
let zero_value_for_type_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr()
vloc__4_mpos := zero_value_for_type_t_string_memory_ptr_1_mpos
@@ -38,7 +38,7 @@ object \"C_10\" {
abi_decode_tuple_(4, calldatasize())
let ret_0 := fun_f_9()
let memPos := allocateMemory(0)
let memEnd := abi_encode_tuple_t_bytes32__to_t_bytes32__fromStack(memPos , ret_0)
let memEnd := abi_encode_tuple_t_bytes32__to_t_bytes32__fromStack(memPos , ret_0)
return(memPos, sub(memEnd, memPos))
}
@@ -79,7 +79,7 @@ object \"C_10\" {
converted := 0x6162636162630000000000000000000000000000000000000000000000000000
}
function fun_f_9() -> vloc__4 {
function fun_f_9() -> vloc__4 {
let zero_value_for_type_t_bytes32_1 := zero_value_for_split_t_bytes32()
vloc__4 := zero_value_for_type_t_bytes32_1
@@ -38,7 +38,7 @@ object \"C_10\" {
abi_decode_tuple_(4, calldatasize())
let ret_0 := fun_f_9()
let memPos := allocateMemory(0)
let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0)
let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0)
return(memPos, sub(memEnd, memPos))
}
@@ -83,7 +83,7 @@ object \"C_10\" {
converted := shift_left_224(cleanup_t_rational_1633837924_by_1(value))
}
function fun_f_9() -> vloc__4 {
function fun_f_9() -> vloc__4 {
let zero_value_for_type_t_bytes4_1 := zero_value_for_split_t_bytes4()
vloc__4 := zero_value_for_type_t_bytes4_1
@@ -38,7 +38,7 @@ object \"C_10\" {
abi_decode_tuple_(4, calldatasize())
let ret_0 := fun_f_9()
let memPos := allocateMemory(0)
let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0)
let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0)
return(memPos, sub(memEnd, memPos))
}
@@ -111,7 +111,7 @@ object \"C_10\" {
}
}
function fun_f_9() -> vloc__4_mpos {
function fun_f_9() -> vloc__4_mpos {
let zero_value_for_type_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr()
vloc__4_mpos := zero_value_for_type_t_string_memory_ptr_1_mpos
@@ -38,7 +38,7 @@ object \"C_10\" {
abi_decode_tuple_(4, calldatasize())
let ret_0 := fun_f_9()
let memPos := allocateMemory(0)
let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0)
let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0)
return(memPos, sub(memEnd, memPos))
}
@@ -83,7 +83,7 @@ object \"C_10\" {
converted := shift_left_224(cleanup_t_rational_2864434397_by_1(value))
}
function fun_f_9() -> vloc__4 {
function fun_f_9() -> vloc__4 {
let zero_value_for_type_t_bytes4_1 := zero_value_for_split_t_bytes4()
vloc__4 := zero_value_for_type_t_bytes4_1
@@ -0,0 +1,9 @@
// bug #8712
contract B {
uint immutable x;
constructor(function() internal returns(uint) fp) internal {
x = fp(); }
}
// ----
// :B
// []
+2 -2
View File
@@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE(string_storage)
// This is only correct on >=Constantinople.
else if (CommonOptions::get().useABIEncoderV2)
{
if (CommonOptions::get().optimizeYul)
if (CommonOptions::get().optimize)
{
// Costs with 0 are cases which cannot be triggered in tests.
if (evmVersion < EVMVersion::istanbul())
@@ -129,7 +129,7 @@ BOOST_AUTO_TEST_CASE(string_storage)
// This is only correct on >=Constantinople.
else if (CommonOptions::get().useABIEncoderV2)
{
if (CommonOptions::get().optimizeYul)
if (CommonOptions::get().optimize)
{
if (evmVersion < EVMVersion::istanbul())
CHECK_GAS(0, 21567, 20);
+155 -94
View File
@@ -13,6 +13,8 @@
*/
#include <test/libsolidity/SemanticTest.h>
#include <libsolutil/Whiskers.h>
#include <libyul/Exceptions.h>
#include <test/Common.h>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/predicate.hpp>
@@ -27,6 +29,7 @@
using namespace std;
using namespace solidity;
using namespace solidity::yul;
using namespace solidity::util;
using namespace solidity::util::formatting;
using namespace solidity::frontend::test;
@@ -36,9 +39,10 @@ using namespace boost::unit_test;
namespace fs = boost::filesystem;
SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVersion):
SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVersion, bool enforceViaYul):
SolidityExecutionFramework(_evmVersion),
EVMVersionRestrictedTestCase(_filename)
EVMVersionRestrictedTestCase(_filename),
m_enforceViaYul(enforceViaYul)
{
m_source = m_reader.source();
m_lineOffset = m_reader.lineNumber();
@@ -78,112 +82,155 @@ SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVer
TestCase::TestResult SemanticTest::run(ostream& _stream, string const& _linePrefix, bool _formatted)
{
for(bool compileViaYul: set<bool>{!m_runWithoutYul, m_runWithYul})
for (bool compileViaYul: set<bool>{!m_runWithoutYul, m_runWithYul || m_enforceViaYul})
{
reset();
bool success = true;
m_compileViaYul = compileViaYul;
if (compileViaYul)
AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Running via Yul:" << endl;
for (auto& test: m_tests)
test.reset();
map<string, solidity::test::Address> libraries;
bool constructed = false;
for (auto& test: m_tests)
try
{
if (constructed)
{
soltestAssert(!test.call().isLibrary, "Libraries have to be deployed before any other call.");
soltestAssert(!test.call().isConstructor, "Constructor has to be the first function call expect for library deployments.");
}
else if (test.call().isLibrary)
{
soltestAssert(
deploy(test.call().signature, 0, {}, libraries) && m_transactionSuccessful,
"Failed to deploy library " + test.call().signature
);
libraries[test.call().signature] = m_contractAddress;
continue;
}
else
{
if (test.call().isConstructor)
deploy("", test.call().value.value, test.call().arguments.rawBytes(), libraries);
else
soltestAssert(deploy("", 0, bytes(), libraries), "Failed to deploy contract.");
constructed = true;
}
reset();
bool success = true;
if (test.call().isConstructor)
{
if (m_transactionSuccessful == test.call().expectations.failure)
success = false;
m_compileViaYul = compileViaYul;
m_compileViaYulCanBeSet = false;
test.setFailure(!m_transactionSuccessful);
test.setRawBytes(bytes());
}
else
if (compileViaYul)
AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Running via Yul:" << endl;
for (auto& test: m_tests)
test.reset();
map<string, solidity::test::Address> libraries;
bool constructed = false;
for (auto& test: m_tests)
{
bytes output;
if (test.call().useCallWithoutSignature)
output = callLowLevel(test.call().arguments.rawBytes(), test.call().value.value);
else
if (constructed)
{
soltestAssert(!test.call().isLibrary, "Libraries have to be deployed before any other call.");
soltestAssert(!test.call().isConstructor, "Constructor has to be the first function call expect for library deployments.");
}
else if (test.call().isLibrary)
{
soltestAssert(
m_allowNonExistingFunctions || m_compiler.methodIdentifiers(m_compiler.lastContractName()).isMember(test.call().signature),
"The function " + test.call().signature + " is not known to the compiler"
);
output = callContractFunctionWithValueNoEncoding(
test.call().signature,
test.call().value.value,
test.call().arguments.rawBytes()
deploy(test.call().signature, 0, {}, libraries) && m_transactionSuccessful,
"Failed to deploy library " + test.call().signature
);
libraries[test.call().signature] = m_contractAddress;
continue;
}
else
{
if (test.call().isConstructor)
deploy("", test.call().value.value, test.call().arguments.rawBytes(), libraries);
else
soltestAssert(deploy("", 0, bytes(), libraries), "Failed to deploy contract.");
constructed = true;
}
if ((m_transactionSuccessful == test.call().expectations.failure) || (output != test.call().expectations.rawBytes()))
success = false;
if (test.call().isConstructor)
{
if (m_transactionSuccessful == test.call().expectations.failure)
success = false;
test.setFailure(!m_transactionSuccessful);
test.setRawBytes(std::move(output));
test.setContractABI(m_compiler.contractABI(m_compiler.lastContractName()));
test.setFailure(!m_transactionSuccessful);
test.setRawBytes(bytes());
}
else
{
bytes output;
if (test.call().useCallWithoutSignature)
output = callLowLevel(test.call().arguments.rawBytes(), test.call().value.value);
else
{
soltestAssert(
m_allowNonExistingFunctions || m_compiler.methodIdentifiers(m_compiler.lastContractName()).isMember(test.call().signature),
"The function " + test.call().signature + " is not known to the compiler"
);
output = callContractFunctionWithValueNoEncoding(
test.call().signature,
test.call().value.value,
test.call().arguments.rawBytes()
);
}
if ((m_transactionSuccessful == test.call().expectations.failure) || (output != test.call().expectations.rawBytes()))
success = false;
test.setFailure(!m_transactionSuccessful);
test.setRawBytes(std::move(output));
test.setContractABI(m_compiler.contractABI(m_compiler.lastContractName()));
}
}
if (success && !m_runWithYul && compileViaYul)
{
m_compileViaYulCanBeSet = true;
AnsiColorized(_stream, _formatted, {BOLD, YELLOW}) << _linePrefix << endl << _linePrefix
<< "Test can pass via Yul and marked with compileViaYul: false." << endl;
return TestResult::Failure;
}
if (!success && (m_runWithYul || !compileViaYul))
{
AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Expected result:" << endl;
for (auto const& test: m_tests)
{
ErrorReporter errorReporter;
_stream << test.format(errorReporter, _linePrefix, false, _formatted) << endl;
_stream << errorReporter.format(_linePrefix, _formatted);
}
_stream << endl;
AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:" << endl;
for (auto const& test: m_tests)
{
ErrorReporter errorReporter;
_stream << test.format(errorReporter, _linePrefix, true, _formatted) << endl;
_stream << errorReporter.format(_linePrefix, _formatted);
}
AnsiColorized(_stream, _formatted, {BOLD, RED}) << _linePrefix << endl << _linePrefix
<< "Attention: Updates on the test will apply the detected format displayed." << endl;
if (compileViaYul && m_runWithoutYul)
{
_stream << _linePrefix << endl << _linePrefix;
AnsiColorized(_stream, _formatted, {RED_BACKGROUND})
<< "Note that the test passed without Yul.";
_stream << endl;
}
else if (!compileViaYul && m_runWithYul)
AnsiColorized(_stream, _formatted, {BOLD, YELLOW}) << _linePrefix << endl << _linePrefix
<< "Note that the test also has to pass via Yul." << endl;
return TestResult::Failure;
}
}
if (!success)
catch (WhiskersError const&)
{
AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Expected result:" << endl;
for (auto const& test: m_tests)
{
ErrorReporter errorReporter;
_stream << test.format(errorReporter, _linePrefix, false, _formatted) << endl;
_stream << errorReporter.format(_linePrefix, _formatted);
}
_stream << endl;
AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:" << endl;
for (auto const& test: m_tests)
{
ErrorReporter errorReporter;
_stream << test.format(errorReporter, _linePrefix, true, _formatted) << endl;
_stream << errorReporter.format(_linePrefix, _formatted);
}
AnsiColorized(_stream, _formatted, {BOLD, RED}) << _linePrefix << endl << _linePrefix
<< "Attention: Updates on the test will apply the detected format displayed." << endl;
if (compileViaYul && m_runWithoutYul)
{
_stream << _linePrefix << endl << _linePrefix;
AnsiColorized(_stream, _formatted, {RED_BACKGROUND}) << "Note that the test passed without Yul.";
_stream << endl;
}
else if (!compileViaYul && m_runWithYul)
AnsiColorized(_stream, _formatted, {BOLD, YELLOW}) << _linePrefix << endl << _linePrefix
<< "Note that the test also has to pass via Yul." << endl;
return TestResult::Failure;
// this is an error in Whiskers template, so should be thrown anyway
throw;
}
catch (YulException const&)
{
// this should be an error in yul compilation or translation
throw;
}
catch (boost::exception const&)
{
if (compileViaYul && !m_runWithYul)
continue;
throw;
}
catch (std::exception const&)
{
if (compileViaYul && !m_runWithYul)
continue;
throw;
}
catch (...)
{
if (compileViaYul && !m_runWithYul)
continue;
throw;
}
}
@@ -204,6 +251,20 @@ void SemanticTest::printUpdatedExpectations(ostream& _stream, string const&) con
_stream << test.format("", true, false) << endl;
}
void SemanticTest::printUpdatedSettings(ostream& _stream, string const& _linePrefix)
{
auto& settings = m_reader.settings();
if (settings.empty() && !m_compileViaYulCanBeSet)
return;
_stream << _linePrefix << "// ====" << endl;
if (m_compileViaYulCanBeSet)
_stream << _linePrefix << "// compileViaYul: also\n";
for (auto const& setting: settings)
if (!m_compileViaYulCanBeSet || setting.first != "compileViaYul")
_stream << _linePrefix << "// " << setting.first << ": " << setting.second << endl;
}
void SemanticTest::parseExpectations(istream& _stream)
{
TestFileParser parser{_stream};
+5 -2
View File
@@ -40,13 +40,14 @@ class SemanticTest: public SolidityExecutionFramework, public EVMVersionRestrict
{
public:
static std::unique_ptr<TestCase> create(Config const& _options)
{ return std::make_unique<SemanticTest>(_options.filename, _options.evmVersion); }
{ return std::make_unique<SemanticTest>(_options.filename, _options.evmVersion, _options.enforceCompileViaYul); }
explicit SemanticTest(std::string const& _filename, langutil::EVMVersion _evmVersion);
explicit SemanticTest(std::string const& _filename, langutil::EVMVersion _evmVersion, bool _enforceViaYul = false);
TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool _formatted = false) override;
void printSource(std::ostream &_stream, std::string const& _linePrefix = "", bool _formatted = false) const override;
void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix = "") const override;
void printUpdatedSettings(std::ostream& _stream, std::string const& _linePrefix = "") override;
/// Instantiates a test file parser that parses the additional comment section at the end of
/// the input stream \param _stream. Each function call is represented using a `FunctionCallTest`
@@ -64,8 +65,10 @@ private:
std::vector<TestFunctionCall> m_tests;
bool m_runWithYul = false;
bool m_runWithoutYul = true;
bool m_enforceViaYul = false;
bool m_runWithABIEncoderV1Only = false;
bool m_allowNonExistingFunctions = false;
bool m_compileViaYulCanBeSet = false;
};
}
+21
View File
@@ -355,6 +355,27 @@ BOOST_AUTO_TEST_CASE(dev_multiple_functions)
checkNatspec(sourceCode, "test", natspec, false);
}
BOOST_AUTO_TEST_CASE(dev_return_no_params)
{
char const* sourceCode = R"(
contract test {
/// @return d The result of the multiplication
function mul(uint a, uint second) public returns (uint d) { return a * 7 + second; }
}
)";
char const* natspec = R"ABCDEF(
{
"methods": {
"mul(uint256,uint256)": {
"returns": { "d": "The result of the multiplication"
}
}
})ABCDEF";
checkNatspec(sourceCode, "test", natspec, false);
}
BOOST_AUTO_TEST_CASE(dev_return)
{
char const* sourceCode = R"(
@@ -28,6 +28,8 @@ contract C {
}
}
// ====
// compileViaYul: also
// ----
// f0() -> 0x20, 0x0
// f1() -> 0x20, 0x40, 0x1, 0x2
@@ -22,5 +22,7 @@ contract C {
}
}
// ====
// compileViaYul: also
// ----
// f() -> true
@@ -5,5 +5,7 @@ contract C {
}
}
// ====
// compileViaYul: also
// ----
// f() -> 0x20, 0x40, 0x1, -2
@@ -9,5 +9,7 @@ contract C {
}
}
// ====
// compileViaYul: also
// ----
// f() -> 0x40, 0xa0, 0x40, 0x20, 0x0, 0x0
@@ -8,5 +8,7 @@ contract C {
}
}
// ====
// compileViaYul: also
// ----
// f() -> 0x20, 0x40, 0x1, -2
@@ -21,6 +21,7 @@ contract C {
}
}
// ====
// compileViaYul: also
// EVMVersion: >homestead
// ----
// f(uint256[]): 32, 3, 23, 42, 87 -> 32, 160, 32, 3, 23, 42, 87
@@ -21,6 +21,7 @@ contract C {
}
}
// ====
// compileViaYul: also
// EVMVersion: >homestead
// ----
// f(uint256[]): 32, 3, 42, 23, 87 -> 32, 160, 32, 3, 42, 23, 87
@@ -5,6 +5,8 @@ contract C {
return 23;
}
}
// ====
// compileViaYul: also
// ----
// f(uint256[][2][]): 0x20, 0x01, 0x20, 0x40, 0x60, 0x00, 0x00 -> 23 # this is the common encoding for x.length == 1 && x[0][0].length == 0 && x[0][1].length == 0 #
// f(uint256[][2][]): 0x20, 0x01, 0x20, 0x00, 0x00 -> 23 # exotic, but still valid encoding #
@@ -7,6 +7,8 @@ contract C {
return this.f(x);
}
}
// ====
// compileViaYul: also
// ----
// g(uint256[][2][]): 0x20, 0x01, 0x20, 0x40, 0x60, 0x00, 0x00 -> 42
// g(uint256[][2][]): 0x20, 0x01, 0x20, 0x00, 0x00 -> 42
@@ -21,6 +21,7 @@ contract C {
}
}
// ====
// compileViaYul: also
// EVMVersion: >homestead
// ----
// f(uint256[][]): 0x20, 2, 0x40, 0xC0, 3, 13, 17, 23, 4, 27, 31, 37, 41 -> 32, 416, 32, 2, 64, 192, 3, 13, 17, 23, 4, 27, 31, 37, 41
@@ -15,6 +15,7 @@ contract C {
}
}
// ====
// compileViaYul: also
// EVMVersion: >homestead
// ----
// f(uint256[3]): 23, 42, 87 -> 32, 96, 23, 42, 87
@@ -15,6 +15,7 @@ contract C {
}
}
// ====
// compileViaYul: also
// EVMVersion: >homestead
// ----
// f(uint256[3]): 23, 42, 87 -> 32, 96, 23, 42, 87
@@ -10,6 +10,7 @@ contract C {
}
}
// ====
// compileViaYul: also
// EVMVersion: >homestead
// ----
// f((uint256[])[]): 32, 1, 32, 32, 3, 17, 42, 23 -> 32, 256, 32, 1, 32, 32, 3, 17, 42, 23
@@ -12,6 +12,7 @@ contract C {
}
}
// ====
// compileViaYul: also
// EVMVersion: >homestead
// ----
// f(uint256[],uint256[],bool): 0x60, 0xE0, true, 3, 23, 42, 87, 2, 51, 72 -> 32, 160, 0x20, 3, 23, 42, 87
@@ -12,6 +12,7 @@ contract C {
}
}
// ====
// compileViaYul: also
// EVMVersion: >homestead
// ----
// f(uint256[3],uint256[2],bool): 23, 42, 87, 51, 72, true -> 32, 96, 23, 42, 87
@@ -12,6 +12,7 @@ contract C {
}
}
// ====
// compileViaYul: also
// EVMVersion: >homestead
// ----
// f((uint256[])): 0x20, 0x20, 3, 42, 23, 17 -> 32, 192, 0x20, 0x20, 3, 42, 23, 17
@@ -12,6 +12,7 @@ contract C {
}
}
// ====
// compileViaYul: also
// EVMVersion: >homestead
// ----
// f((uint256)): 3 -> 32, 32, 3
@@ -10,6 +10,8 @@ contract C {
return this.g(x);
}
}
// ====
// compileViaYul: also
// ----
// f(uint256): 0 -> 0
// g(address): 0 -> 0 # test validation as well as sanity check #
@@ -10,6 +10,8 @@ contract C {
return this.gggg(x);
}
}
// ====
// compileViaYul: also
// ----
// f(uint256): 0 -> false
// gggg(bool): 0 -> false # test validation as well as sanity check #
@@ -42,6 +42,8 @@ contract C {
return this.g16(x);
}
}
// ====
// compileViaYul: also
// ----
// f1(bytes32): left(0) -> left(0)
// gg1(bytes1): left(0) -> left(0) # test validation as well as sanity check #
@@ -42,6 +42,8 @@ contract C {
return this.g128(x);
}
}
// ====
// compileViaYul: also
// ----
// f8(int256): 0 -> 0
// ggg8(int8): 0 -> 0 # test validation as well as sanity check #
@@ -42,6 +42,8 @@ contract C {
return this.g128(x);
}
}
// ====
// compileViaYul: also
// ----
// f8(uint256): 0 -> 0
// ggg8(uint8): 0 -> 0 # test validation as well as sanity check #
@@ -1,6 +1,7 @@
contract Lotto {
uint256 public constant ticketPrice = 555;
}
// ====
// compileViaYul: also
// ----
// ticketPrice() -> 555
@@ -8,5 +8,7 @@ contract C {
}
}
// ====
// compileViaYul: also
// ----
// test() -> 0
@@ -7,7 +7,8 @@ contract C {
return a % b;
}
}
// ====
// compileViaYul: also
// ----
// div(uint256,uint256): 7, 2 -> 3
// div(uint256,uint256): 7, 0 -> FAILURE # throws #
@@ -11,6 +11,7 @@ contract c {
l = data.length;
}
}
// ====
// compileViaYul: also
// ----
// test() -> 1, 0
@@ -6,6 +6,7 @@ contract c {
return true;
}
}
// ====
// compileViaYul: also
// ----
// test() -> FAILURE
@@ -8,6 +8,7 @@ contract c {
x = 3;
}
}
// ====
// compileViaYul: also
// ----
// test() -> 3
@@ -14,6 +14,7 @@ contract c {
z = data[2];
}
}
// ====
// compileViaYul: also
// ----
// test() -> 5, 4, 3, 3
@@ -9,6 +9,5 @@ contract c {
return true;
}
}
// ----
// test() -> FAILURE
@@ -8,6 +8,7 @@ contract c {
x = 3;
}
}
// ====
// compileViaYul: also
// ----
// test() -> 3
@@ -11,6 +11,7 @@ contract C {
b = s[1];
}
}
// ====
// compileViaYul: also
// ----
// f(uint256[2]): 42, 23 -> 42, 23
@@ -11,7 +11,8 @@ contract C {
return 42;
}
}
// ====
// compileViaYul: also
// ----
// f(uint256[][]): 0x20, 0x0 -> 42 # valid access stub #
// f(uint256[][]): 0x20, 0x1 -> FAILURE # invalid on argument decoding #
@@ -16,7 +16,8 @@ contract C {
return 42;
}
}
// ====
// compileViaYul: also
// ----
// f(uint256[][1][]): 0x20, 0x0 -> 42 # valid access stub #
// f(uint256[][1][]): 0x20, 0x1 -> FAILURE # invalid on argument decoding #
@@ -4,6 +4,7 @@ contract C {
return 7;
}
}
// ====
// compileViaYul: also
// ----
// f() -> 7
@@ -19,6 +19,8 @@ contract C {
y[0] = 23;
return x[2];
}}
// ====
// compileViaYul: also
// ----
// f() -> FAILURE
// g() -> FAILURE
@@ -29,6 +29,7 @@ contract C {
return 0;
}
}
// ====
// compileViaYul: also
// ----
// f() -> 7
@@ -12,7 +12,8 @@ contract A {
return true;
}
}
// ====
// compileViaYul: also
// ----
// test() -> false
// testIt() -> FAILURE
@@ -7,7 +7,8 @@ contract Creator {
ch = s[2];
}
}
// ====
// compileViaYul: also
// ----
// constructor(): 1, 2, 3, 4 ->
// r() -> 4
@@ -5,6 +5,7 @@ contract C {
return (x.length, bytes16(uint128(2)).length, a.length + 7);
}
}
// ====
// compileViaYul: also
// ----
// f(bytes32): "789" -> 32, 16, 8
@@ -30,7 +30,8 @@ contract C {
return arr[i](x);
}
}
// ====
// compileViaYul: also
// ----
// test(uint256,uint256): 10, 0 -> 11
// test(uint256,uint256): 10, 1 -> 12
@@ -10,5 +10,7 @@ contract Test {
return data;
}
}
// ====
// compileViaYul: also
// ----
// f() -> 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07
@@ -11,7 +11,8 @@ contract C {
return rows[n][k - 1];
}
}
// ====
// compileViaYul: also
// ----
// f(uint256,uint256): 3, 1 -> 1
// f(uint256,uint256): 9, 5 -> 70
@@ -19,6 +19,8 @@ contract C {
}
}
// ====
// compileViaYul: also
// ----
// l() -> 0
// lv(uint256): 42 ->
@@ -22,5 +22,7 @@ contract Main {
return map[a];
}
}
// ====
// compileViaYul: also
// ----
// f(uint256): 0x34 -> 0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1
@@ -5,5 +5,7 @@ contract C {
return x;
}
}
// ====
// compileViaYul: also
// ----
// f() -> 0x4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45
@@ -3,5 +3,7 @@ contract c {
d = keccak256(abi.encodePacked(a, b, c));
}
}
// ====
// compileViaYul: also
// ----
// foo(uint256,uint256,uint256): 0xa, 0xc, 0xd -> 0xbc740a98aae5923e8f04c9aa798c9ee82f69e319997699f2782c40828db9fd81
@@ -3,5 +3,7 @@ contract c {
d = keccak256(abi.encodePacked(a, b, uint8(145)));
}
}
// ====
// compileViaYul: also
// ----
// foo(uint256,uint16): 0xa, 0xc -> 0x88acd45f75907e7c560318bc1a5249850a0999c4896717b1167d05d116e6dbad
@@ -7,6 +7,8 @@ contract c {
d = keccak256(abi.encodePacked(a, b, uint8(145), "foo"));
}
}
// ====
// compileViaYul: also
// ----
// foo() -> 0x41b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d
// bar(uint256,uint16): 0xa, 0xc -> 0x6990f36476dc412b1c4baa48e2d9f4aa4bb313f61fda367c8fdbbb2232dc6146
@@ -3,7 +3,5 @@ contract C {
return sha256("");
}
}
// ====
// compileViaYul: also
// ----
// f() -> 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
@@ -11,6 +11,8 @@ contract C {
_out = _in;
}
}
// ====
// compileViaYul: also
// ----
// f(bool): 0x0 -> 0x0
// f(bool): 0x1 -> 0x1
@@ -13,6 +13,8 @@ contract C {
return 0;
}
}
// ====
// compileViaYul: also
// ----
// f(address): 0xffff1234567890123456789012345678901234567890 -> FAILURE # We input longer data on purpose.#
// g(address): 0xffff1234567890123456789012345678901234567890 -> FAILURE
@@ -10,6 +10,7 @@ contract C {
require(y == bytes2(0xffff));
}
}
// ====
// compileViaYul: also
// ----
// f() -> "\xff\xff\xff\xff"
@@ -10,5 +10,7 @@ contract C {
return 0;
}
}
// ====
// compileViaYul: also
// ----
// f(bytes2,uint16): "abc", 0x40102 -> FAILURE # We input longer data on purpose. #
@@ -8,6 +8,7 @@ contract C {
return (x, y);
}
}
// ====
// compileViaYul: also
// ----
// test() -> 0xff, 0xff
@@ -16,6 +16,8 @@ contract C {
}
}
// ====
// compileViaYul: also
// ----
// f() -> 0x20, 3, "\x03\x01\x02"
// g() -> 0x20, 3, "\x03\x01\x02"
@@ -6,5 +6,7 @@ contract Foo {
uint256 constant x = 56;
}
// ====
// compileViaYul: also
// ----
// getX() -> 56
@@ -20,5 +20,7 @@ contract Derived is Base {
}
}
// ====
// compileViaYul: also
// ----
// getA() -> 49
@@ -0,0 +1,41 @@
contract A1 { constructor() public {} }
contract B1 is A1 {}
contract A2 { constructor() public payable {} }
contract B2 is A2 {}
contract B3 {}
contract B4 { constructor() public {} }
contract C {
function createWithValue(bytes memory c, uint256 value) public payable returns (bool) {
uint256 y = 0;
assembly { y := create(value, add(c, 0x20), mload(c)) }
return y != 0;
}
function f(uint256 value) public payable returns (bool) {
return createWithValue(type(B1).creationCode, value);
}
function g(uint256 value) public payable returns (bool) {
return createWithValue(type(B2).creationCode, value);
}
function h(uint256 value) public payable returns (bool) {
return createWithValue(type(B3).creationCode, value);
}
function i(uint256 value) public payable returns (bool) {
return createWithValue(type(B4).creationCode, value);
}
}
// ====
// EVMVersion: >homestead
// compileViaYul: also
// ----
// f(uint256), 2000 ether: 0 -> true
// f(uint256), 2000 ether: 100 -> false
// g(uint256), 2000 ether: 0 -> true
// g(uint256), 2000 ether: 100 -> false
// h(uint256), 2000 ether: 0 -> true
// h(uint256), 2000 ether: 100 -> false
// i(uint256), 2000 ether: 0 -> true
// i(uint256), 2000 ether: 100 -> false
@@ -15,7 +15,8 @@ contract Main {
return flag;
}
}
// ====
// compileViaYul: also
// ----
// constructor(): "abc", true
// getFlag() -> true
@@ -33,6 +33,8 @@ contract Main {
}
}
// ====
// compileViaYul: also
// ----
// getFlag() -> true
// getName() -> "abc"
@@ -14,6 +14,8 @@ contract B {
}
}
// ====
// compileViaYul: also
// ----
// testIt() ->
// test() -> 2
@@ -20,5 +20,7 @@ contract Derived is Base {
}
}
// ====
// compileViaYul: also
// ----
// getA() -> 2
@@ -14,7 +14,8 @@ contract Derived is Base {
return m_derived;
}
}
// ====
// compileViaYul: also
// ----
// getBMember() -> 5
// getDMember() -> 6
@@ -0,0 +1,21 @@
contract A1 {}
contract B1 is A1 { constructor() public payable {} }
contract A2 { constructor() public {} }
contract B2 is A2 { constructor() public payable {} }
contract B3 { constructor() public payable {} }
contract C {
function f() public payable returns (bool) {
// Make sure none of these revert.
new B1{value: 10}();
new B2{value: 10}();
new B3{value: 10}();
return true;
}
}
// ====
// compileViaYul: also
// ----
// f(), 2000 ether -> true
@@ -5,6 +5,8 @@ contract test {
return cond ? x : y;
}
}
// ====
// compileViaYul: also
// ----
// f(bool): true -> 0xcd
// f(bool): false -> 0xabab
@@ -3,5 +3,7 @@ contract test {
return false ? 5 : 10;
}
}
// ====
// compileViaYul: also
// ----
// f() -> 10
@@ -7,6 +7,8 @@ contract test {
return z();
}
}
// ====
// compileViaYul: also
// ----
// f(bool): true -> 1
// f(bool): false -> 2
@@ -6,6 +6,8 @@ contract test {
x > 50 ? 50 : 10;
}
}
// ====
// compileViaYul: also
// ----
// f(uint256): 1001 -> 1000
// f(uint256): 500 -> 100
@@ -3,5 +3,7 @@ contract test {
return true ? 5 : 10;
}
}
// ====
// compileViaYul: also
// ----
// f() -> 5
@@ -3,6 +3,8 @@ contract test {
return cond ? (1, 2) : (3, 4);
}
}
// ====
// compileViaYul: also
// ----
// f(bool): true -> 1, 2
// f(bool): false -> 3, 4
@@ -3,6 +3,8 @@ contract test {
cond ? a = v : b = v;
}
}
// ====
// compileViaYul: also
// ----
// f(bool,uint256): true, 20 -> 20, 0
// f(bool,uint256): false, 20 -> 0, 20
@@ -5,6 +5,8 @@ contract C {
receive () payable external { ++y; }
function f() external returns (uint, uint) { return (x, y); }
}
// ====
// compileViaYul: also
// ----
// f() -> 0, 0
// () ->
@@ -4,6 +4,8 @@ contract A {
function getData() public returns (uint r) { return data; }
}
contract B is A {}
// ====
// compileViaYul: also
// ----
// getData() -> 0
// (): 42 ->

Some files were not shown because too many files have changed in this diff Show More