diff --git a/Changelog.md b/Changelog.md index 58b93972e..e9a9548db 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,8 +3,11 @@ Features: Bugfixes: + * Code Generator: Allow ``block.blockhash`` without being called. * Code Generator: Properly skip unneeded storgae array cleanup when not reducing length. + * Code Generator: Bugfix in modifier lookup in libraries. * Commandline interface: Support ``--evm-version constantinople`` properly. + * DocString Parser: Fix error message for empty descriptions. * Standard JSON: Support ``constantinople`` as ``evmVersion`` properly. * Type System: Make external library functions accessible. diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 0bf88267f..473330466 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -193,14 +193,22 @@ Declaration const* CompilerContext::nextFunctionToCompile() const return m_functionCompilationQueue.nextFunctionToCompile(); } -ModifierDefinition const& CompilerContext::functionModifier(string const& _name) const +ModifierDefinition const& CompilerContext::resolveVirtualFunctionModifier( + ModifierDefinition const& _modifier +) const { + // Libraries do not allow inheritance and their functions can be inlined, so we should not + // search the inheritance hierarchy (which will be the wrong one in case the function + // is inlined). + if (auto scope = dynamic_cast(_modifier.scope())) + if (scope->isLibrary()) + return _modifier; solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set."); for (ContractDefinition const* contract: m_inheritanceHierarchy) for (ModifierDefinition const* modifier: contract->functionModifiers()) - if (modifier->name() == _name) + if (modifier->name() == _modifier.name()) return *modifier; - solAssert(false, "Function modifier " + _name + " not found."); + solAssert(false, "Function modifier " + _modifier.name() + " not found in inheritance hierarchy."); } unsigned CompilerContext::baseStackOffsetOfVariable(Declaration const& _declaration) const diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index cf6266833..7b6632774 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -130,7 +130,7 @@ public: void appendMissingLowLevelFunctions(); ABIFunctions& abiFunctions() { return m_abiFunctions; } - ModifierDefinition const& functionModifier(std::string const& _name) const; + ModifierDefinition const& resolveVirtualFunctionModifier(ModifierDefinition const& _modifier) const; /// Returns the distance of the given local variable from the bottom of the stack (of the current function). unsigned baseStackOffsetOfVariable(Declaration const& _declaration) const; /// If supplied by a value returned by @ref baseStackOffsetOfVariable(variable), returns diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 5a9498f0e..95d6c8b5c 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -1002,7 +1002,10 @@ void ContractCompiler::appendModifierOrFunctionCode() appendModifierOrFunctionCode(); else { - ModifierDefinition const& modifier = m_context.functionModifier(modifierInvocation->name()->name()); + ModifierDefinition const& nonVirtualModifier = dynamic_cast( + *modifierInvocation->name()->annotation().referencedDeclaration + ); + ModifierDefinition const& modifier = m_context.resolveVirtualFunctionModifier(nonVirtualModifier); CompilerContext::LocationSetter locationSetter(m_context, modifier); solAssert(modifier.parameters().size() == modifierInvocation->arguments().size(), ""); for (unsigned i = 0; i < modifier.parameters().size(); ++i) diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 7162cb0dd..f50628ff4 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1147,6 +1147,9 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) else if (member == "sig") m_context << u256(0) << Instruction::CALLDATALOAD << (u256(0xffffffff) << (256 - 32)) << Instruction::AND; + else if (member == "blockhash") + { + } else solAssert(false, "Unknown magic member."); break; diff --git a/libsolidity/parsing/DocStringParser.cpp b/libsolidity/parsing/DocStringParser.cpp index 0409de720..d058d5569 100644 --- a/libsolidity/parsing/DocStringParser.cpp +++ b/libsolidity/parsing/DocStringParser.cpp @@ -119,21 +119,17 @@ DocStringParser::iter DocStringParser::parseDocTagParam(iter _pos, iter _end) return _end; } auto nameEndPos = firstSpaceOrTab(nameStartPos, _end); - if (nameEndPos == _end) - { - appendError("End of param name not found: " + string(nameStartPos, _end)); - return _end; - } auto paramName = string(nameStartPos, nameEndPos); auto descStartPos = skipWhitespace(nameEndPos, _end); - if (descStartPos == _end) + auto nlPos = find(descStartPos, _end, '\n'); + + if (descStartPos == nlPos) { appendError("No description given for param " + paramName); return _end; } - auto nlPos = find(descStartPos, _end, '\n'); auto paramDesc = string(descStartPos, nlPos); newTag("param"); m_lastTag->paramName = paramName; diff --git a/scripts/soltest.sh b/scripts/soltest.sh new file mode 100755 index 000000000..00f484a14 --- /dev/null +++ b/scripts/soltest.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +set -e + +REPO_ROOT="$(dirname "$0")"/.. +USE_DEBUGGER=0 +DEBUGGER="gdb --args" +BOOST_OPTIONS= +SOLTEST_OPTIONS= + +while [ $# -gt 0 ] +do + case "$1" in + --debugger) + shift + DEBUGGER="$1" + USE_DEBUGGER=1 + ;; + --debug) + USE_DEBUGGER=1 + ;; + --boost-options) + shift + BOOST_OPTIONS="${BOOST_OPTIONS} $1" + ;; + -t) + shift + BOOST_OPTIONS="${BOOST_OPTIONS} -t $1" + ;; + --show-progress | -p) + BOOST_OPTIONS="${BOOST_OPTIONS} $1" + ;; + *) + SOLTEST_OPTIONS="${SOLTEST_OPTIONS} $1" + ;; + esac + shift +done +if [ "$USE_DEBUGGER" -ne "0" ]; then + DEBUG_PREFIX=${DEBUGGER} +fi + +exec ${DEBUG_PREFIX} ${REPO_ROOT}/build/test/soltest ${BOOST_OPTIONS} -- --testpath ${REPO_ROOT}/test ${SOLTEST_OPTIONS} diff --git a/test/ExecutionFramework.h b/test/ExecutionFramework.h index a7971b810..ee8da3226 100644 --- a/test/ExecutionFramework.h +++ b/test/ExecutionFramework.h @@ -22,7 +22,7 @@ #pragma once -#include +#include #include #include diff --git a/test/TestHelper.cpp b/test/Options.cpp similarity index 85% rename from test/TestHelper.cpp rename to test/Options.cpp index 77fa204fb..ff4a7c988 100644 --- a/test/TestHelper.cpp +++ b/test/Options.cpp @@ -19,9 +19,10 @@ * @date 2014 */ -#include +#include #include +#include #include @@ -71,6 +72,19 @@ Options::Options() testPath = path; } +void Options::validate() const +{ + solAssert( + !dev::test::Options::get().testPath.empty(), + "No test path specified. The --testpath argument is required." + ); + if (!disableIPC) + solAssert( + !dev::test::Options::get().ipcPath.empty(), + "No ipc path specified. The --ipcpath argument is required, unless --no-ipc is used." + ); +} + dev::solidity::EVMVersion Options::evmVersion() const { if (!evmVersionString.empty()) diff --git a/test/TestHelper.h b/test/Options.h similarity index 98% rename from test/TestHelper.h rename to test/Options.h index f7b1d94c8..9bc698762 100644 --- a/test/TestHelper.h +++ b/test/Options.h @@ -41,6 +41,7 @@ struct Options: boost::noncopyable bool disableIPC = false; bool disableSMT = false; + void validate() const; solidity::EVMVersion evmVersion() const; static Options const& get(); diff --git a/test/RPCSession.cpp b/test/RPCSession.cpp index 54871057f..03b1341cb 100644 --- a/test/RPCSession.cpp +++ b/test/RPCSession.cpp @@ -21,7 +21,7 @@ #include -#include +#include #include diff --git a/test/boostTest.cpp b/test/boostTest.cpp index e557ff95a..f16973b53 100644 --- a/test/boostTest.cpp +++ b/test/boostTest.cpp @@ -35,7 +35,7 @@ #pragma GCC diagnostic pop -#include +#include #include using namespace boost::unit_test; @@ -55,6 +55,7 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] ) { master_test_suite_t& master = framework::master_test_suite(); master.p_name.value = "SolidityTests"; + dev::test::Options::get().validate(); solAssert(dev::solidity::test::SyntaxTest::registerTests( master, dev::test::Options::get().testPath / "libsolidity", diff --git a/test/libdevcore/Checksum.cpp b/test/libdevcore/Checksum.cpp index 4eedbd999..95066b69f 100644 --- a/test/libdevcore/Checksum.cpp +++ b/test/libdevcore/Checksum.cpp @@ -22,7 +22,7 @@ #include -#include "../TestHelper.h" +#include using namespace std; diff --git a/test/libdevcore/IndentedWriter.cpp b/test/libdevcore/IndentedWriter.cpp index a694aa1b9..916c99d09 100644 --- a/test/libdevcore/IndentedWriter.cpp +++ b/test/libdevcore/IndentedWriter.cpp @@ -20,7 +20,7 @@ #include -#include "../TestHelper.h" +#include using namespace std; diff --git a/test/libdevcore/JSON.cpp b/test/libdevcore/JSON.cpp index 39d71b42b..39d958f5f 100644 --- a/test/libdevcore/JSON.cpp +++ b/test/libdevcore/JSON.cpp @@ -21,7 +21,7 @@ #include -#include "../TestHelper.h" +#include using namespace std; diff --git a/test/libdevcore/StringUtils.cpp b/test/libdevcore/StringUtils.cpp index 597457cca..9ee93d02a 100644 --- a/test/libdevcore/StringUtils.cpp +++ b/test/libdevcore/StringUtils.cpp @@ -20,7 +20,7 @@ #include -#include "../TestHelper.h" +#include using namespace std; diff --git a/test/libdevcore/SwarmHash.cpp b/test/libdevcore/SwarmHash.cpp index 1ed1da181..913586f89 100644 --- a/test/libdevcore/SwarmHash.cpp +++ b/test/libdevcore/SwarmHash.cpp @@ -20,7 +20,7 @@ #include -#include "../TestHelper.h" +#include using namespace std; diff --git a/test/libdevcore/UTF8.cpp b/test/libdevcore/UTF8.cpp index 719ada720..6de4570fe 100644 --- a/test/libdevcore/UTF8.cpp +++ b/test/libdevcore/UTF8.cpp @@ -21,7 +21,7 @@ #include #include -#include "../TestHelper.h" +#include using namespace std; diff --git a/test/libdevcore/Whiskers.cpp b/test/libdevcore/Whiskers.cpp index 84149173e..b12acdd70 100644 --- a/test/libdevcore/Whiskers.cpp +++ b/test/libdevcore/Whiskers.cpp @@ -20,7 +20,7 @@ #include -#include "../TestHelper.h" +#include using namespace std; diff --git a/test/libevmasm/Optimiser.cpp b/test/libevmasm/Optimiser.cpp index e6abcb531..f630b3048 100644 --- a/test/libevmasm/Optimiser.cpp +++ b/test/libevmasm/Optimiser.cpp @@ -20,7 +20,7 @@ * Tests for the Solidity optimizer. */ -#include +#include #include #include diff --git a/test/libevmasm/SourceLocation.cpp b/test/libevmasm/SourceLocation.cpp index 6889b3e67..764da3cd6 100644 --- a/test/libevmasm/SourceLocation.cpp +++ b/test/libevmasm/SourceLocation.cpp @@ -22,7 +22,7 @@ #include -#include "../TestHelper.h" +#include namespace dev { diff --git a/test/libjulia/Common.cpp b/test/libjulia/Common.cpp index 41f5d3206..24519b015 100644 --- a/test/libjulia/Common.cpp +++ b/test/libjulia/Common.cpp @@ -21,7 +21,7 @@ #include -#include +#include #include diff --git a/test/libjulia/Parser.cpp b/test/libjulia/Parser.cpp index df905dd68..9d66658e1 100644 --- a/test/libjulia/Parser.cpp +++ b/test/libjulia/Parser.cpp @@ -19,7 +19,7 @@ * Unit tests for parsing Julia. */ -#include "../TestHelper.h" +#include #include diff --git a/test/liblll/Compiler.cpp b/test/liblll/Compiler.cpp index 6c6eae3f9..ebdea1858 100644 --- a/test/liblll/Compiler.cpp +++ b/test/liblll/Compiler.cpp @@ -20,7 +20,7 @@ * Unit tests for the LLL compiler. */ -#include +#include #include diff --git a/test/liblll/EndToEndTest.cpp b/test/liblll/EndToEndTest.cpp index e5e70cf8c..fd8099f20 100644 --- a/test/liblll/EndToEndTest.cpp +++ b/test/liblll/EndToEndTest.cpp @@ -21,7 +21,7 @@ */ #include -#include +#include #include diff --git a/test/libsolidity/ASTJSON.cpp b/test/libsolidity/ASTJSON.cpp index 9bf60b647..b44dd331a 100644 --- a/test/libsolidity/ASTJSON.cpp +++ b/test/libsolidity/ASTJSON.cpp @@ -20,7 +20,7 @@ * Tests for the json ast output. */ -#include +#include #include #include diff --git a/test/libsolidity/AnalysisFramework.cpp b/test/libsolidity/AnalysisFramework.cpp index 7c335a482..4538757de 100644 --- a/test/libsolidity/AnalysisFramework.cpp +++ b/test/libsolidity/AnalysisFramework.cpp @@ -20,7 +20,7 @@ #include -#include +#include #include #include diff --git a/test/libsolidity/Assembly.cpp b/test/libsolidity/Assembly.cpp index aff610a48..5519ae0d9 100644 --- a/test/libsolidity/Assembly.cpp +++ b/test/libsolidity/Assembly.cpp @@ -20,7 +20,7 @@ * Unit tests for Assembly Items from evmasm/Assembly.h */ -#include +#include #include #include diff --git a/test/libsolidity/Imports.cpp b/test/libsolidity/Imports.cpp index bc81b3b1c..1b5dd4a5b 100644 --- a/test/libsolidity/Imports.cpp +++ b/test/libsolidity/Imports.cpp @@ -21,7 +21,7 @@ */ #include -#include +#include #include #include diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp index a4dcc4d5f..34ca33e3c 100644 --- a/test/libsolidity/InlineAssembly.cpp +++ b/test/libsolidity/InlineAssembly.cpp @@ -20,7 +20,7 @@ * Unit tests for inline assembly. */ -#include "../TestHelper.h" +#include #include #include diff --git a/test/libsolidity/JSONCompiler.cpp b/test/libsolidity/JSONCompiler.cpp index 285c56049..aed0a3706 100644 --- a/test/libsolidity/JSONCompiler.cpp +++ b/test/libsolidity/JSONCompiler.cpp @@ -25,8 +25,8 @@ #include #include -#include "../Metadata.h" -#include "../TestHelper.h" +#include +#include using namespace std; diff --git a/test/libsolidity/Metadata.cpp b/test/libsolidity/Metadata.cpp index f1edeeb72..808bd1e15 100644 --- a/test/libsolidity/Metadata.cpp +++ b/test/libsolidity/Metadata.cpp @@ -19,8 +19,8 @@ * Unit tests for the metadata output. */ -#include "../Metadata.h" -#include "../TestHelper.h" +#include +#include #include #include #include diff --git a/test/libsolidity/SemVerMatcher.cpp b/test/libsolidity/SemVerMatcher.cpp index 08ef5277f..07f8fba62 100644 --- a/test/libsolidity/SemVerMatcher.cpp +++ b/test/libsolidity/SemVerMatcher.cpp @@ -25,7 +25,7 @@ #include #include #include -#include "../TestHelper.h" +#include using namespace std; diff --git a/test/libsolidity/SolidityABIJSON.cpp b/test/libsolidity/SolidityABIJSON.cpp index 0d471b32f..107abc26a 100644 --- a/test/libsolidity/SolidityABIJSON.cpp +++ b/test/libsolidity/SolidityABIJSON.cpp @@ -20,7 +20,7 @@ * Unit tests for the solidity compiler JSON Interface output. */ -#include "../TestHelper.h" +#include #include #include diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index d8c8b8ade..44dc40f73 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -23,7 +23,7 @@ #include -#include +#include #include #include @@ -1788,6 +1788,23 @@ BOOST_AUTO_TEST_CASE(transfer_ether) ABI_CHECK(callContractFunction("b(address,uint256)", oogRecipient, 10), encodeArgs()); } +BOOST_AUTO_TEST_CASE(uncalled_blockhash) +{ + char const* code = R"( + contract C { + function f() public view returns (bytes32) + { + var x = block.blockhash; + return x(block.number - 1); + } + } + )"; + compileAndRun(code, 0, "C"); + bytes result = callContractFunction("f()"); + BOOST_REQUIRE_EQUAL(result.size(), 32); + BOOST_CHECK(result[0] != 0 || result[1] != 0 || result[2] != 0); +} + BOOST_AUTO_TEST_CASE(log0) { char const* sourceCode = R"( @@ -2879,6 +2896,58 @@ BOOST_AUTO_TEST_CASE(function_modifier_multiple_times_local_vars) ABI_CHECK(callContractFunction("a()"), encodeArgs(0)); } +BOOST_AUTO_TEST_CASE(function_modifier_library) +{ + char const* sourceCode = R"( + library L { + struct S { uint v; } + modifier mod(S storage s) { s.v++; _; } + function libFun(S storage s) mod(s) internal { s.v += 0x100; } + } + + contract Test { + using L for *; + L.S s; + + function f() public returns (uint) { + s.libFun(); + L.libFun(s); + return s.v; + } + } + )"; + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("f()"), encodeArgs(0x202)); +} + +BOOST_AUTO_TEST_CASE(function_modifier_library_inheritance) +{ + // Tests that virtual lookup for modifiers in libraries does not consider + // the current inheritance hierarchy. + + char const* sourceCode = R"( + library L { + struct S { uint v; } + modifier mod(S storage s) { s.v++; _; } + function libFun(S storage s) mod(s) internal { s.v += 0x100; } + } + + contract Test { + using L for *; + L.S s; + modifier mod(L.S storage) { revert(); _; } + + function f() public returns (uint) { + s.libFun(); + L.libFun(s); + return s.v; + } + } + )"; + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("f()"), encodeArgs(0x202)); +} + BOOST_AUTO_TEST_CASE(crazy_elementary_typenames_on_stack) { char const* sourceCode = R"( diff --git a/test/libsolidity/SolidityExpressionCompiler.cpp b/test/libsolidity/SolidityExpressionCompiler.cpp index 5f044b44c..c8adfc6ed 100644 --- a/test/libsolidity/SolidityExpressionCompiler.cpp +++ b/test/libsolidity/SolidityExpressionCompiler.cpp @@ -30,7 +30,7 @@ #include #include #include -#include "../TestHelper.h" +#include using namespace std; diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 1f76c01b5..c757037c7 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -22,7 +22,7 @@ #include -#include +#include #include diff --git a/test/libsolidity/SolidityNatspecJSON.cpp b/test/libsolidity/SolidityNatspecJSON.cpp index 49a725e04..eeebeb745 100644 --- a/test/libsolidity/SolidityNatspecJSON.cpp +++ b/test/libsolidity/SolidityNatspecJSON.cpp @@ -20,7 +20,7 @@ * Unit tests for the solidity compiler JSON Interface output. */ -#include "../TestHelper.h" +#include #include #include #include diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp index f03b30e13..4e862f608 100644 --- a/test/libsolidity/SolidityParser.cpp +++ b/test/libsolidity/SolidityParser.cpp @@ -25,8 +25,8 @@ #include #include #include -#include "../TestHelper.h" -#include "ErrorCheck.h" +#include +#include using namespace std; diff --git a/test/libsolidity/SyntaxTest.cpp b/test/libsolidity/SyntaxTest.cpp index f1c60458a..45a851b60 100644 --- a/test/libsolidity/SyntaxTest.cpp +++ b/test/libsolidity/SyntaxTest.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include using namespace dev; @@ -188,6 +189,9 @@ int SyntaxTest::registerTests( } else { + static vector> filenames; + + filenames.emplace_back(new string(_path.string())); _suite.add(make_test_case( [fullpath] { @@ -196,7 +200,7 @@ int SyntaxTest::registerTests( BOOST_ERROR("Test expectation mismatch.\n" + errorStream.str()); }, _path.stem().string(), - _path.string(), + *filenames.back(), 0 )); numTestsAdded = 1; diff --git a/test/libsolidity/ViewPureChecker.cpp b/test/libsolidity/ViewPureChecker.cpp index 26ff461c6..a6ce6d917 100644 --- a/test/libsolidity/ViewPureChecker.cpp +++ b/test/libsolidity/ViewPureChecker.cpp @@ -20,7 +20,7 @@ #include -#include +#include #include diff --git a/test/libsolidity/syntaxTests/docstring_empty_description.sol b/test/libsolidity/syntaxTests/docstring_empty_description.sol new file mode 100644 index 000000000..0caa1b232 --- /dev/null +++ b/test/libsolidity/syntaxTests/docstring_empty_description.sol @@ -0,0 +1,6 @@ +contract C { + /// @param id + function vote(uint id) public; +} +// ---- +// DocstringParsingError: No description given for param id diff --git a/test/libsolidity/syntaxTests/virtualLookup/modifiers_in_libraries.sol b/test/libsolidity/syntaxTests/virtualLookup/modifiers_in_libraries.sol new file mode 100644 index 000000000..b033fd0c7 --- /dev/null +++ b/test/libsolidity/syntaxTests/virtualLookup/modifiers_in_libraries.sol @@ -0,0 +1,14 @@ +library WithModifier { + modifier mod() { require(msg.value > 10 ether); _; } + function withMod(uint self) mod() internal view { require(self > 0); } +} + +contract Test { + using WithModifier for *; + + function f(uint _value) public payable { + _value.withMod(); + WithModifier.withMod(_value); + } +} +// ----