Merge branch 'develop' into externalFunctionsInLibraries

This commit is contained in:
chriseth 2018-03-14 18:07:55 +01:00 committed by GitHub
commit 78abe81f08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 213 additions and 48 deletions

View File

@ -3,8 +3,11 @@
Features: Features:
Bugfixes: Bugfixes:
* Code Generator: Allow ``block.blockhash`` without being called.
* Code Generator: Properly skip unneeded storgae array cleanup when not reducing length. * 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. * Commandline interface: Support ``--evm-version constantinople`` properly.
* DocString Parser: Fix error message for empty descriptions.
* Standard JSON: Support ``constantinople`` as ``evmVersion`` properly. * Standard JSON: Support ``constantinople`` as ``evmVersion`` properly.
* Type System: Make external library functions accessible. * Type System: Make external library functions accessible.

View File

@ -193,14 +193,22 @@ Declaration const* CompilerContext::nextFunctionToCompile() const
return m_functionCompilationQueue.nextFunctionToCompile(); 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<ContractDefinition const*>(_modifier.scope()))
if (scope->isLibrary())
return _modifier;
solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set."); solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set.");
for (ContractDefinition const* contract: m_inheritanceHierarchy) for (ContractDefinition const* contract: m_inheritanceHierarchy)
for (ModifierDefinition const* modifier: contract->functionModifiers()) for (ModifierDefinition const* modifier: contract->functionModifiers())
if (modifier->name() == _name) if (modifier->name() == _modifier.name())
return *modifier; 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 unsigned CompilerContext::baseStackOffsetOfVariable(Declaration const& _declaration) const

View File

@ -130,7 +130,7 @@ public:
void appendMissingLowLevelFunctions(); void appendMissingLowLevelFunctions();
ABIFunctions& abiFunctions() { return m_abiFunctions; } 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). /// Returns the distance of the given local variable from the bottom of the stack (of the current function).
unsigned baseStackOffsetOfVariable(Declaration const& _declaration) const; unsigned baseStackOffsetOfVariable(Declaration const& _declaration) const;
/// If supplied by a value returned by @ref baseStackOffsetOfVariable(variable), returns /// If supplied by a value returned by @ref baseStackOffsetOfVariable(variable), returns

View File

@ -1002,7 +1002,10 @@ void ContractCompiler::appendModifierOrFunctionCode()
appendModifierOrFunctionCode(); appendModifierOrFunctionCode();
else else
{ {
ModifierDefinition const& modifier = m_context.functionModifier(modifierInvocation->name()->name()); ModifierDefinition const& nonVirtualModifier = dynamic_cast<ModifierDefinition const&>(
*modifierInvocation->name()->annotation().referencedDeclaration
);
ModifierDefinition const& modifier = m_context.resolveVirtualFunctionModifier(nonVirtualModifier);
CompilerContext::LocationSetter locationSetter(m_context, modifier); CompilerContext::LocationSetter locationSetter(m_context, modifier);
solAssert(modifier.parameters().size() == modifierInvocation->arguments().size(), ""); solAssert(modifier.parameters().size() == modifierInvocation->arguments().size(), "");
for (unsigned i = 0; i < modifier.parameters().size(); ++i) for (unsigned i = 0; i < modifier.parameters().size(); ++i)

View File

@ -1147,6 +1147,9 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
else if (member == "sig") else if (member == "sig")
m_context << u256(0) << Instruction::CALLDATALOAD m_context << u256(0) << Instruction::CALLDATALOAD
<< (u256(0xffffffff) << (256 - 32)) << Instruction::AND; << (u256(0xffffffff) << (256 - 32)) << Instruction::AND;
else if (member == "blockhash")
{
}
else else
solAssert(false, "Unknown magic member."); solAssert(false, "Unknown magic member.");
break; break;

View File

@ -119,21 +119,17 @@ DocStringParser::iter DocStringParser::parseDocTagParam(iter _pos, iter _end)
return _end; return _end;
} }
auto nameEndPos = firstSpaceOrTab(nameStartPos, _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 paramName = string(nameStartPos, nameEndPos);
auto descStartPos = skipWhitespace(nameEndPos, _end); auto descStartPos = skipWhitespace(nameEndPos, _end);
if (descStartPos == _end) auto nlPos = find(descStartPos, _end, '\n');
if (descStartPos == nlPos)
{ {
appendError("No description given for param " + paramName); appendError("No description given for param " + paramName);
return _end; return _end;
} }
auto nlPos = find(descStartPos, _end, '\n');
auto paramDesc = string(descStartPos, nlPos); auto paramDesc = string(descStartPos, nlPos);
newTag("param"); newTag("param");
m_lastTag->paramName = paramName; m_lastTag->paramName = paramName;

43
scripts/soltest.sh Executable file
View File

@ -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}

View File

@ -22,7 +22,7 @@
#pragma once #pragma once
#include <test/TestHelper.h> #include <test/Options.h>
#include <test/RPCSession.h> #include <test/RPCSession.h>
#include <libsolidity/interface/EVMVersion.h> #include <libsolidity/interface/EVMVersion.h>

View File

@ -19,9 +19,10 @@
* @date 2014 * @date 2014
*/ */
#include <test/TestHelper.h> #include <test/Options.h>
#include <libsolidity/interface/EVMVersion.h> #include <libsolidity/interface/EVMVersion.h>
#include <libsolidity/interface/Exceptions.h>
#include <boost/test/framework.hpp> #include <boost/test/framework.hpp>
@ -71,6 +72,19 @@ Options::Options()
testPath = path; 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 dev::solidity::EVMVersion Options::evmVersion() const
{ {
if (!evmVersionString.empty()) if (!evmVersionString.empty())

View File

@ -41,6 +41,7 @@ struct Options: boost::noncopyable
bool disableIPC = false; bool disableIPC = false;
bool disableSMT = false; bool disableSMT = false;
void validate() const;
solidity::EVMVersion evmVersion() const; solidity::EVMVersion evmVersion() const;
static Options const& get(); static Options const& get();

View File

@ -21,7 +21,7 @@
#include <test/RPCSession.h> #include <test/RPCSession.h>
#include <test/TestHelper.h> #include <test/Options.h>
#include <libsolidity/interface/EVMVersion.h> #include <libsolidity/interface/EVMVersion.h>

View File

@ -35,7 +35,7 @@
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#include <test/TestHelper.h> #include <test/Options.h>
#include <test/libsolidity/SyntaxTest.h> #include <test/libsolidity/SyntaxTest.h>
using namespace boost::unit_test; 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_test_suite_t& master = framework::master_test_suite();
master.p_name.value = "SolidityTests"; master.p_name.value = "SolidityTests";
dev::test::Options::get().validate();
solAssert(dev::solidity::test::SyntaxTest::registerTests( solAssert(dev::solidity::test::SyntaxTest::registerTests(
master, master,
dev::test::Options::get().testPath / "libsolidity", dev::test::Options::get().testPath / "libsolidity",

View File

@ -22,7 +22,7 @@
#include <libdevcore/Exceptions.h> #include <libdevcore/Exceptions.h>
#include "../TestHelper.h" #include <test/Options.h>
using namespace std; using namespace std;

View File

@ -20,7 +20,7 @@
#include <libdevcore/IndentedWriter.h> #include <libdevcore/IndentedWriter.h>
#include "../TestHelper.h" #include <test/Options.h>
using namespace std; using namespace std;

View File

@ -21,7 +21,7 @@
#include <libdevcore/JSON.h> #include <libdevcore/JSON.h>
#include "../TestHelper.h" #include <test/Options.h>
using namespace std; using namespace std;

View File

@ -20,7 +20,7 @@
#include <libdevcore/StringUtils.h> #include <libdevcore/StringUtils.h>
#include "../TestHelper.h" #include <test/Options.h>
using namespace std; using namespace std;

View File

@ -20,7 +20,7 @@
#include <libdevcore/SwarmHash.h> #include <libdevcore/SwarmHash.h>
#include "../TestHelper.h" #include <test/Options.h>
using namespace std; using namespace std;

View File

@ -21,7 +21,7 @@
#include <libdevcore/CommonData.h> #include <libdevcore/CommonData.h>
#include <libdevcore/UTF8.h> #include <libdevcore/UTF8.h>
#include "../TestHelper.h" #include <test/Options.h>
using namespace std; using namespace std;

View File

@ -20,7 +20,7 @@
#include <libdevcore/Whiskers.h> #include <libdevcore/Whiskers.h>
#include "../TestHelper.h" #include <test/Options.h>
using namespace std; using namespace std;

View File

@ -20,7 +20,7 @@
* Tests for the Solidity optimizer. * Tests for the Solidity optimizer.
*/ */
#include <test/TestHelper.h> #include <test/Options.h>
#include <libevmasm/CommonSubexpressionEliminator.h> #include <libevmasm/CommonSubexpressionEliminator.h>
#include <libevmasm/PeepholeOptimiser.h> #include <libevmasm/PeepholeOptimiser.h>

View File

@ -22,7 +22,7 @@
#include <libevmasm/SourceLocation.h> #include <libevmasm/SourceLocation.h>
#include "../TestHelper.h" #include <test/Options.h>
namespace dev namespace dev
{ {

View File

@ -21,7 +21,7 @@
#include <test/libjulia/Common.h> #include <test/libjulia/Common.h>
#include <test/TestHelper.h> #include <test/Options.h>
#include <libjulia/optimiser/Disambiguator.h> #include <libjulia/optimiser/Disambiguator.h>

View File

@ -19,7 +19,7 @@
* Unit tests for parsing Julia. * Unit tests for parsing Julia.
*/ */
#include "../TestHelper.h" #include <test/Options.h>
#include <test/libsolidity/ErrorCheck.h> #include <test/libsolidity/ErrorCheck.h>

View File

@ -20,7 +20,7 @@
* Unit tests for the LLL compiler. * Unit tests for the LLL compiler.
*/ */
#include <test/TestHelper.h> #include <test/Options.h>
#include <libdevcore/FixedHash.h> #include <libdevcore/FixedHash.h>

View File

@ -21,7 +21,7 @@
*/ */
#include <test/liblll/ExecutionFramework.h> #include <test/liblll/ExecutionFramework.h>
#include <test/TestHelper.h> #include <test/Options.h>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>

View File

@ -20,7 +20,7 @@
* Tests for the json ast output. * Tests for the json ast output.
*/ */
#include <test/TestHelper.h> #include <test/Options.h>
#include <libsolidity/interface/Exceptions.h> #include <libsolidity/interface/Exceptions.h>
#include <libsolidity/interface/CompilerStack.h> #include <libsolidity/interface/CompilerStack.h>

View File

@ -20,7 +20,7 @@
#include <test/libsolidity/AnalysisFramework.h> #include <test/libsolidity/AnalysisFramework.h>
#include <test/TestHelper.h> #include <test/Options.h>
#include <libsolidity/interface/CompilerStack.h> #include <libsolidity/interface/CompilerStack.h>
#include <libsolidity/interface/SourceReferenceFormatter.h> #include <libsolidity/interface/SourceReferenceFormatter.h>

View File

@ -20,7 +20,7 @@
* Unit tests for Assembly Items from evmasm/Assembly.h * Unit tests for Assembly Items from evmasm/Assembly.h
*/ */
#include <test/TestHelper.h> #include <test/Options.h>
#include <libevmasm/SourceLocation.h> #include <libevmasm/SourceLocation.h>
#include <libevmasm/Assembly.h> #include <libevmasm/Assembly.h>

View File

@ -21,7 +21,7 @@
*/ */
#include <test/libsolidity/ErrorCheck.h> #include <test/libsolidity/ErrorCheck.h>
#include <test/TestHelper.h> #include <test/Options.h>
#include <libsolidity/interface/Exceptions.h> #include <libsolidity/interface/Exceptions.h>
#include <libsolidity/interface/CompilerStack.h> #include <libsolidity/interface/CompilerStack.h>

View File

@ -20,7 +20,7 @@
* Unit tests for inline assembly. * Unit tests for inline assembly.
*/ */
#include "../TestHelper.h" #include <test/Options.h>
#include <libsolidity/interface/AssemblyStack.h> #include <libsolidity/interface/AssemblyStack.h>
#include <libsolidity/parsing/Scanner.h> #include <libsolidity/parsing/Scanner.h>

View File

@ -25,8 +25,8 @@
#include <libsolidity/interface/Version.h> #include <libsolidity/interface/Version.h>
#include <libsolc/libsolc.h> #include <libsolc/libsolc.h>
#include "../Metadata.h" #include <test/Metadata.h>
#include "../TestHelper.h" #include <test/Options.h>
using namespace std; using namespace std;

View File

@ -19,8 +19,8 @@
* Unit tests for the metadata output. * Unit tests for the metadata output.
*/ */
#include "../Metadata.h" #include <test/Metadata.h>
#include "../TestHelper.h" #include <test/Options.h>
#include <libsolidity/interface/CompilerStack.h> #include <libsolidity/interface/CompilerStack.h>
#include <libdevcore/SwarmHash.h> #include <libdevcore/SwarmHash.h>
#include <libdevcore/JSON.h> #include <libdevcore/JSON.h>

View File

@ -25,7 +25,7 @@
#include <tuple> #include <tuple>
#include <libsolidity/parsing/Scanner.h> #include <libsolidity/parsing/Scanner.h>
#include <libsolidity/analysis/SemVerHandler.h> #include <libsolidity/analysis/SemVerHandler.h>
#include "../TestHelper.h" #include <test/Options.h>
using namespace std; using namespace std;

View File

@ -20,7 +20,7 @@
* Unit tests for the solidity compiler JSON Interface output. * Unit tests for the solidity compiler JSON Interface output.
*/ */
#include "../TestHelper.h" #include <test/Options.h>
#include <libsolidity/interface/CompilerStack.h> #include <libsolidity/interface/CompilerStack.h>
#include <libdevcore/Exceptions.h> #include <libdevcore/Exceptions.h>

View File

@ -23,7 +23,7 @@
#include <test/libsolidity/SolidityExecutionFramework.h> #include <test/libsolidity/SolidityExecutionFramework.h>
#include <test/TestHelper.h> #include <test/Options.h>
#include <libsolidity/interface/Exceptions.h> #include <libsolidity/interface/Exceptions.h>
#include <libsolidity/interface/EVMVersion.h> #include <libsolidity/interface/EVMVersion.h>
@ -1788,6 +1788,23 @@ BOOST_AUTO_TEST_CASE(transfer_ether)
ABI_CHECK(callContractFunction("b(address,uint256)", oogRecipient, 10), encodeArgs()); 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) BOOST_AUTO_TEST_CASE(log0)
{ {
char const* sourceCode = R"( char const* sourceCode = R"(
@ -2879,6 +2896,58 @@ BOOST_AUTO_TEST_CASE(function_modifier_multiple_times_local_vars)
ABI_CHECK(callContractFunction("a()"), encodeArgs(0)); 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) BOOST_AUTO_TEST_CASE(crazy_elementary_typenames_on_stack)
{ {
char const* sourceCode = R"( char const* sourceCode = R"(

View File

@ -30,7 +30,7 @@
#include <libsolidity/ast/AST.h> #include <libsolidity/ast/AST.h>
#include <libsolidity/analysis/TypeChecker.h> #include <libsolidity/analysis/TypeChecker.h>
#include <libsolidity/interface/ErrorReporter.h> #include <libsolidity/interface/ErrorReporter.h>
#include "../TestHelper.h" #include <test/Options.h>
using namespace std; using namespace std;

View File

@ -22,7 +22,7 @@
#include <test/libsolidity/AnalysisFramework.h> #include <test/libsolidity/AnalysisFramework.h>
#include <test/TestHelper.h> #include <test/Options.h>
#include <libsolidity/ast/AST.h> #include <libsolidity/ast/AST.h>

View File

@ -20,7 +20,7 @@
* Unit tests for the solidity compiler JSON Interface output. * Unit tests for the solidity compiler JSON Interface output.
*/ */
#include "../TestHelper.h" #include <test/Options.h>
#include <string> #include <string>
#include <libdevcore/JSON.h> #include <libdevcore/JSON.h>
#include <libsolidity/interface/CompilerStack.h> #include <libsolidity/interface/CompilerStack.h>

View File

@ -25,8 +25,8 @@
#include <libsolidity/parsing/Scanner.h> #include <libsolidity/parsing/Scanner.h>
#include <libsolidity/parsing/Parser.h> #include <libsolidity/parsing/Parser.h>
#include <libsolidity/interface/ErrorReporter.h> #include <libsolidity/interface/ErrorReporter.h>
#include "../TestHelper.h" #include <test/Options.h>
#include "ErrorCheck.h" #include <test/libsolidity/ErrorCheck.h>
using namespace std; using namespace std;

View File

@ -21,6 +21,7 @@
#include <boost/throw_exception.hpp> #include <boost/throw_exception.hpp>
#include <cctype> #include <cctype>
#include <fstream> #include <fstream>
#include <memory>
#include <stdexcept> #include <stdexcept>
using namespace dev; using namespace dev;
@ -188,6 +189,9 @@ int SyntaxTest::registerTests(
} }
else else
{ {
static vector<unique_ptr<string>> filenames;
filenames.emplace_back(new string(_path.string()));
_suite.add(make_test_case( _suite.add(make_test_case(
[fullpath] [fullpath]
{ {
@ -196,7 +200,7 @@ int SyntaxTest::registerTests(
BOOST_ERROR("Test expectation mismatch.\n" + errorStream.str()); BOOST_ERROR("Test expectation mismatch.\n" + errorStream.str());
}, },
_path.stem().string(), _path.stem().string(),
_path.string(), *filenames.back(),
0 0
)); ));
numTestsAdded = 1; numTestsAdded = 1;

View File

@ -20,7 +20,7 @@
#include <test/libsolidity/AnalysisFramework.h> #include <test/libsolidity/AnalysisFramework.h>
#include <test/TestHelper.h> #include <test/Options.h>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>

View File

@ -0,0 +1,6 @@
contract C {
/// @param id
function vote(uint id) public;
}
// ----
// DocstringParsingError: No description given for param id

View File

@ -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);
}
}
// ----