aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rw-r--r--CMakeLists.txt2
-rw-r--r--Changelog.md1
-rw-r--r--cmake/jsoncpp.cmake51
m---------deps0
-rw-r--r--docs/abi-spec.rst8
-rw-r--r--libdevcore/SHA3.cpp5
-rw-r--r--libdevcore/SwarmHash.h4
-rw-r--r--libevmasm/ConstantOptimiser.h2
-rw-r--r--libevmasm/GasMeter.cpp4
-rw-r--r--libjulia/backends/evm/EVMCodeTransform.cpp14
-rw-r--r--libjulia/backends/evm/EVMCodeTransform.h1
-rw-r--r--libsolidity/analysis/DocStringAnalyser.cpp16
-rw-r--r--libsolidity/analysis/NameAndTypeResolver.h2
-rw-r--r--libsolidity/analysis/PostTypeChecker.h4
-rw-r--r--libsolidity/ast/ASTJsonConverter.cpp4
-rw-r--r--libsolidity/ast/ASTJsonConverter.h20
-rw-r--r--libsolidity/codegen/ContractCompiler.h4
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp2
-rw-r--r--libsolidity/codegen/ExpressionCompiler.h2
-rw-r--r--libsolidity/formal/SMTLib2Interface.h2
-rw-r--r--libsolidity/inlineasm/AsmAnalysis.cpp20
-rw-r--r--libsolidity/inlineasm/AsmData.h6
-rw-r--r--libsolidity/inlineasm/AsmParser.cpp30
-rw-r--r--libsolidity/inlineasm/AsmPrinter.cpp6
-rw-r--r--libsolidity/interface/ErrorReporter.h2
-rw-r--r--libsolidity/parsing/ParserBase.cpp2
-rw-r--r--scripts/install_deps.bat2
-rw-r--r--scripts/install_deps.cmake99
-rw-r--r--test/ExecutionFramework.h2
-rw-r--r--test/RPCSession.h6
-rw-r--r--test/libdevcore/Whiskers.cpp (renamed from test/libdevcore/MiniMoustache.cpp)0
-rw-r--r--test/libjulia/Parser.cpp20
-rw-r--r--test/libsolidity/AnalysisFramework.h4
-rw-r--r--test/libsolidity/InlineAssembly.cpp18
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp25
36 files changed, 332 insertions, 61 deletions
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index ba66d79f..00000000
--- a/.gitmodules
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "deps"]
- path = deps
- url = https://github.com/ethereum/cpp-dependencies
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0a65071d..89d627dc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -15,7 +15,7 @@ option(SOLC_LINK_STATIC "Link solc executable statically on supported platforms"
# Let's find our dependencies
include(EthDependencies)
-include(deps/jsoncpp.cmake)
+include(jsoncpp)
find_package(Threads)
diff --git a/Changelog.md b/Changelog.md
index c4918013..458a9543 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -2,6 +2,7 @@
Features:
* Support ``pragma experimental "v0.5.0";`` to turn on upcoming breaking changes.
+ * Assembly Parser: Support multiple assignment (``x, y := f()``).
* Code Generator: Added ``.selector`` member on external function types to retrieve their signature.
* Code Generator: Keep a single copy of encoding functions when using the experimental "ABIEncoderV2".
* Optimizer: Add new optimization step to remove unused ``JUMPDEST``s.
diff --git a/cmake/jsoncpp.cmake b/cmake/jsoncpp.cmake
new file mode 100644
index 00000000..6ddf4c74
--- /dev/null
+++ b/cmake/jsoncpp.cmake
@@ -0,0 +1,51 @@
+include(ExternalProject)
+
+if (${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten")
+ set(JSONCPP_CMAKE_COMMAND emcmake cmake)
+else()
+ set(JSONCPP_CMAKE_COMMAND ${CMAKE_COMMAND})
+endif()
+
+# Disable implicit fallthrough warning in jsoncpp for gcc >= 7 until the upstream handles it properly
+if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0)
+ set(JSONCCP_EXTRA_FLAGS -Wno-implicit-fallthrough)
+else()
+ set(JSONCCP_EXTRA_FLAGS "")
+endif()
+
+set(prefix "${CMAKE_BINARY_DIR}/deps")
+set(JSONCPP_LIBRARY "${prefix}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}jsoncpp${CMAKE_STATIC_LIBRARY_SUFFIX}")
+set(JSONCPP_INCLUDE_DIR "${prefix}/include")
+
+set(byproducts "")
+if(CMAKE_VERSION VERSION_GREATER 3.1)
+ set(byproducts BUILD_BYPRODUCTS "${JSONCPP_LIBRARY}")
+endif()
+
+ExternalProject_Add(jsoncpp-project
+ PREFIX "${prefix}"
+ DOWNLOAD_DIR "${CMAKE_SOURCE_DIR}/deps/downloads"
+ DOWNLOAD_NAME jsoncpp-1.7.7.tar.gz
+ URL https://github.com/open-source-parsers/jsoncpp/archive/1.7.7.tar.gz
+ URL_HASH SHA256=087640ebcf7fbcfe8e2717a0b9528fff89c52fcf69fa2a18cc2b538008098f97
+ CMAKE_COMMAND ${JSONCPP_CMAKE_COMMAND}
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
+ -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
+ -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
+ # Build static lib but suitable to be included in a shared lib.
+ -DCMAKE_POSITION_INDEPENDENT_CODE=${BUILD_SHARED_LIBS}
+ -DJSONCPP_WITH_TESTS=OFF
+ -DJSONCPP_WITH_PKGCONFIG_SUPPORT=OFF
+ -DCMAKE_CXX_FLAGS=${JSONCCP_EXTRA_FLAGS}
+ # Overwrite build and install commands to force Release build on MSVC.
+ BUILD_COMMAND cmake --build <BINARY_DIR> --config Release
+ INSTALL_COMMAND cmake --build <BINARY_DIR> --config Release --target install
+ ${byproducts}
+)
+
+# Create jsoncpp imported library
+add_library(jsoncpp STATIC IMPORTED)
+file(MAKE_DIRECTORY ${JSONCPP_INCLUDE_DIR}) # Must exist.
+set_property(TARGET jsoncpp PROPERTY IMPORTED_LOCATION ${JSONCPP_LIBRARY})
+set_property(TARGET jsoncpp PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${JSONCPP_INCLUDE_DIR})
+add_dependencies(jsoncpp jsoncpp-project)
diff --git a/deps b/deps
deleted file mode 160000
-Subproject e5c8316db8d3daa0abc3b5af8545ce330057608
diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst
index 97320c7f..29d98645 100644
--- a/docs/abi-spec.rst
+++ b/docs/abi-spec.rst
@@ -42,7 +42,7 @@ The following elementary types exist:
- ``address``: equivalent to ``uint160``, except for the assumed interpretation and language typing.
-- ``uint``, ``int``: synonyms for ``uint256``, ``int256`` respectively (not to be used for computing the function selector).
+- ``uint``, ``int``: synonyms for ``uint256``, ``int256`` respectively (this shorthand not to be used for computing the function selector).
- ``bool``: equivalent to ``uint8`` restricted to the values 0 and 1
@@ -50,7 +50,7 @@ The following elementary types exist:
- ``ufixed<M>x<N>``: unsigned variant of ``fixed<M>x<N>``.
-- ``fixed``, ``ufixed``: synonyms for ``fixed128x19``, ``ufixed128x19`` respectively (not to be used for computing the function selector).
+- ``fixed``, ``ufixed``: synonyms for ``fixed128x19``, ``ufixed128x19`` respectively (this shorthand not to be used for computing the function selector).
- ``bytes<M>``: binary type of ``M`` bytes, ``0 < M <= 32``.
@@ -58,7 +58,7 @@ The following elementary types exist:
The following (fixed-size) array type exists:
-- ``<type>[M]``: a fixed-length array of the given fixed-length type.
+- ``<type>[M]``: a fixed-length array of ``M`` elements, ``M > 0``, of the given type.
The following non-fixed-size types exist:
@@ -66,7 +66,7 @@ The following non-fixed-size types exist:
- ``string``: dynamic sized unicode string assumed to be UTF-8 encoded.
-- ``<type>[]``: a variable-length array of the given fixed-length type.
+- ``<type>[]``: a variable-length array of elements of the given type.
Types can be combined to a tuple by enclosing a finite non-negative number
of them inside parentheses, separated by commas:
diff --git a/libdevcore/SHA3.cpp b/libdevcore/SHA3.cpp
index 4d82ec85..b0e40ccb 100644
--- a/libdevcore/SHA3.cpp
+++ b/libdevcore/SHA3.cpp
@@ -97,10 +97,9 @@ static const uint64_t RC[24] = \
static inline void keccakf(void* state) {
uint64_t* a = (uint64_t*)state;
uint64_t b[5] = {0};
- uint64_t t = 0;
- uint8_t x, y;
for (int i = 0; i < 24; i++) {
+ uint8_t x, y;
// Theta
FOR5(x, 1,
b[x] = 0;
@@ -110,7 +109,7 @@ static inline void keccakf(void* state) {
FOR5(y, 5,
a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); ))
// Rho and pi
- t = a[1];
+ uint64_t t = a[1];
x = 0;
REPEAT24(b[0] = a[pi[x]];
a[pi[x]] = rol(t, rho[x]);
diff --git a/libdevcore/SwarmHash.h b/libdevcore/SwarmHash.h
index a5da96f5..a06f7bda 100644
--- a/libdevcore/SwarmHash.h
+++ b/libdevcore/SwarmHash.h
@@ -26,7 +26,7 @@
namespace dev
{
-/// Compute the "swarm hash" of @a _data
-h256 swarmHash(std::string const& _data);
+/// Compute the "swarm hash" of @a _input
+h256 swarmHash(std::string const& _input);
}
diff --git a/libevmasm/ConstantOptimiser.h b/libevmasm/ConstantOptimiser.h
index 82982e25..c450b0b4 100644
--- a/libevmasm/ConstantOptimiser.h
+++ b/libevmasm/ConstantOptimiser.h
@@ -91,7 +91,7 @@ protected:
}
/// Replaces all constants i by the code given in @a _replacement[i].
- static void replaceConstants(AssemblyItems& _items, std::map<u256, AssemblyItems> const& _replacement);
+ static void replaceConstants(AssemblyItems& _items, std::map<u256, AssemblyItems> const& _replacements);
Params m_params;
u256 const& m_value;
diff --git a/libevmasm/GasMeter.cpp b/libevmasm/GasMeter.cpp
index 6a7c80e0..dad952bc 100644
--- a/libevmasm/GasMeter.cpp
+++ b/libevmasm/GasMeter.cpp
@@ -189,9 +189,9 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
return gas;
}
-GasMeter::GasConsumption GasMeter::wordGas(u256 const& _multiplier, ExpressionClasses::Id _position)
+GasMeter::GasConsumption GasMeter::wordGas(u256 const& _multiplier, ExpressionClasses::Id _value)
{
- u256 const* value = m_state->expressionClasses().knownConstant(_position);
+ u256 const* value = m_state->expressionClasses().knownConstant(_value);
if (!value)
return GasConsumption::infinite();
return GasConsumption(_multiplier * ((*value + 31) / 32));
diff --git a/libjulia/backends/evm/EVMCodeTransform.cpp b/libjulia/backends/evm/EVMCodeTransform.cpp
index e0b11cf3..66f593e8 100644
--- a/libjulia/backends/evm/EVMCodeTransform.cpp
+++ b/libjulia/backends/evm/EVMCodeTransform.cpp
@@ -60,9 +60,12 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl)
void CodeTransform::operator()(Assignment const& _assignment)
{
- visitExpression(*_assignment.value);
+ int height = m_assembly.stackHeight();
+ boost::apply_visitor(*this, *_assignment.value);
+ expectDeposit(_assignment.variableNames.size(), height);
+
m_assembly.setSourceLocation(_assignment.location);
- generateAssignment(_assignment.variableName);
+ generateMultiAssignment(_assignment.variableNames);
checkStackHeight(&_assignment);
}
@@ -469,6 +472,13 @@ void CodeTransform::finalizeBlock(Block const& _block, int blockStartStackHeight
checkStackHeight(&_block);
}
+void CodeTransform::generateMultiAssignment(vector<Identifier> const& _variableNames)
+{
+ solAssert(m_scope, "");
+ for (auto const& variableName: _variableNames | boost::adaptors::reversed)
+ generateAssignment(variableName);
+}
+
void CodeTransform::generateAssignment(Identifier const& _variableName)
{
solAssert(m_scope, "");
diff --git a/libjulia/backends/evm/EVMCodeTransform.h b/libjulia/backends/evm/EVMCodeTransform.h
index 2c0fd10c..951c8a50 100644
--- a/libjulia/backends/evm/EVMCodeTransform.h
+++ b/libjulia/backends/evm/EVMCodeTransform.h
@@ -124,6 +124,7 @@ private:
/// to @a _blackStartStackHeight.
void finalizeBlock(solidity::assembly::Block const& _block, int _blockStartStackHeight);
+ void generateMultiAssignment(std::vector<solidity::assembly::Identifier> const& _variableNames);
void generateAssignment(solidity::assembly::Identifier const& _variableName);
/// Determines the stack height difference to the given variables. Throws
diff --git a/libsolidity/analysis/DocStringAnalyser.cpp b/libsolidity/analysis/DocStringAnalyser.cpp
index d08c4eb5..b3fb5258 100644
--- a/libsolidity/analysis/DocStringAnalyser.cpp
+++ b/libsolidity/analysis/DocStringAnalyser.cpp
@@ -38,30 +38,30 @@ bool DocStringAnalyser::analyseDocStrings(SourceUnit const& _sourceUnit)
return !m_errorOccured;
}
-bool DocStringAnalyser::visit(ContractDefinition const& _node)
+bool DocStringAnalyser::visit(ContractDefinition const& _contract)
{
static const set<string> validTags = set<string>{"author", "title", "dev", "notice"};
- parseDocStrings(_node, _node.annotation(), validTags, "contracts");
+ parseDocStrings(_contract, _contract.annotation(), validTags, "contracts");
return true;
}
-bool DocStringAnalyser::visit(FunctionDefinition const& _node)
+bool DocStringAnalyser::visit(FunctionDefinition const& _function)
{
- handleCallable(_node, _node, _node.annotation());
+ handleCallable(_function, _function, _function.annotation());
return true;
}
-bool DocStringAnalyser::visit(ModifierDefinition const& _node)
+bool DocStringAnalyser::visit(ModifierDefinition const& _modifier)
{
- handleCallable(_node, _node, _node.annotation());
+ handleCallable(_modifier, _modifier, _modifier.annotation());
return true;
}
-bool DocStringAnalyser::visit(EventDefinition const& _node)
+bool DocStringAnalyser::visit(EventDefinition const& _event)
{
- handleCallable(_node, _node, _node.annotation());
+ handleCallable(_event, _event, _event.annotation());
return true;
}
diff --git a/libsolidity/analysis/NameAndTypeResolver.h b/libsolidity/analysis/NameAndTypeResolver.h
index 59bd3b1f..d83697cd 100644
--- a/libsolidity/analysis/NameAndTypeResolver.h
+++ b/libsolidity/analysis/NameAndTypeResolver.h
@@ -148,7 +148,7 @@ public:
private:
bool visit(SourceUnit& _sourceUnit) override;
void endVisit(SourceUnit& _sourceUnit) override;
- bool visit(ImportDirective& _declaration) override;
+ bool visit(ImportDirective& _import) override;
bool visit(ContractDefinition& _contract) override;
void endVisit(ContractDefinition& _contract) override;
bool visit(StructDefinition& _struct) override;
diff --git a/libsolidity/analysis/PostTypeChecker.h b/libsolidity/analysis/PostTypeChecker.h
index dbdf50e0..91d2b0b9 100644
--- a/libsolidity/analysis/PostTypeChecker.h
+++ b/libsolidity/analysis/PostTypeChecker.h
@@ -50,8 +50,8 @@ private:
virtual bool visit(ContractDefinition const& _contract) override;
virtual void endVisit(ContractDefinition const& _contract) override;
- virtual bool visit(VariableDeclaration const& _declaration) override;
- virtual void endVisit(VariableDeclaration const& _declaration) override;
+ virtual bool visit(VariableDeclaration const& _variable) override;
+ virtual void endVisit(VariableDeclaration const& _variable) override;
virtual bool visit(Identifier const& _identifier) override;
diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp
index 6811d3e4..51249f20 100644
--- a/libsolidity/ast/ASTJsonConverter.cpp
+++ b/libsolidity/ast/ASTJsonConverter.cpp
@@ -129,7 +129,7 @@ string ASTJsonConverter::sourceLocationToString(SourceLocation const& _location)
return std::to_string(_location.start) + ":" + std::to_string(length) + ":" + std::to_string(sourceIndex);
}
-string ASTJsonConverter::namePathToString(std::vector<ASTString> const& _namePath) const
+string ASTJsonConverter::namePathToString(std::vector<ASTString> const& _namePath)
{
return boost::algorithm::join(_namePath, ".");
}
@@ -171,7 +171,7 @@ void ASTJsonConverter::appendExpressionAttributes(
_attributes += exprAttributes;
}
-Json::Value ASTJsonConverter::inlineAssemblyIdentifierToJson(pair<assembly::Identifier const* ,InlineAssemblyAnnotation::ExternalIdentifierInfo> _info)
+Json::Value ASTJsonConverter::inlineAssemblyIdentifierToJson(pair<assembly::Identifier const* ,InlineAssemblyAnnotation::ExternalIdentifierInfo> _info) const
{
Json::Value tuple(Json::objectValue);
tuple["src"] = sourceLocationToString(_info.first->location);
diff --git a/libsolidity/ast/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h
index 60c660c1..9a886220 100644
--- a/libsolidity/ast/ASTJsonConverter.h
+++ b/libsolidity/ast/ASTJsonConverter.h
@@ -120,7 +120,7 @@ private:
std::vector<std::pair<std::string, Json::Value>>&& _attributes
);
std::string sourceLocationToString(SourceLocation const& _location) const;
- std::string namePathToString(std::vector<ASTString> const& _namePath) const;
+ static std::string namePathToString(std::vector<ASTString> const& _namePath);
static Json::Value idOrNull(ASTNode const* _pt)
{
return _pt ? Json::Value(nodeId(*_pt)) : Json::nullValue;
@@ -129,13 +129,13 @@ private:
{
return _node ? toJson(*_node) : Json::nullValue;
}
- Json::Value inlineAssemblyIdentifierToJson(std::pair<assembly::Identifier const* , InlineAssemblyAnnotation::ExternalIdentifierInfo> _info);
- std::string location(VariableDeclaration::Location _location);
- std::string contractKind(ContractDefinition::ContractKind _kind);
- std::string functionCallKind(FunctionCallKind _kind);
- std::string literalTokenKind(Token::Value _token);
- std::string type(Expression const& _expression);
- std::string type(VariableDeclaration const& _varDecl);
+ Json::Value inlineAssemblyIdentifierToJson(std::pair<assembly::Identifier const* , InlineAssemblyAnnotation::ExternalIdentifierInfo> _info) const;
+ static std::string location(VariableDeclaration::Location _location);
+ static std::string contractKind(ContractDefinition::ContractKind _kind);
+ static std::string functionCallKind(FunctionCallKind _kind);
+ static std::string literalTokenKind(Token::Value _token);
+ static std::string type(Expression const& _expression);
+ static std::string type(VariableDeclaration const& _varDecl);
static int nodeId(ASTNode const& _node)
{
return _node.id();
@@ -151,8 +151,8 @@ private:
}
return tmp;
}
- Json::Value typePointerToJson(TypePointer _tp);
- Json::Value typePointerToJson(std::shared_ptr<std::vector<TypePointer>> _tps);
+ static Json::Value typePointerToJson(TypePointer _tp);
+ static Json::Value typePointerToJson(std::shared_ptr<std::vector<TypePointer>> _tps);
void appendExpressionAttributes(
std::vector<std::pair<std::string, Json::Value>> &_attributes,
ExpressionAnnotation const& _annotation
diff --git a/libsolidity/codegen/ContractCompiler.h b/libsolidity/codegen/ContractCompiler.h
index 38c1e045..7c5ee59f 100644
--- a/libsolidity/codegen/ContractCompiler.h
+++ b/libsolidity/codegen/ContractCompiler.h
@@ -96,8 +96,8 @@ private:
virtual bool visit(IfStatement const& _ifStatement) override;
virtual bool visit(WhileStatement const& _whileStatement) override;
virtual bool visit(ForStatement const& _forStatement) override;
- virtual bool visit(Continue const& _continue) override;
- virtual bool visit(Break const& _break) override;
+ virtual bool visit(Continue const& _continueStatement) override;
+ virtual bool visit(Break const& _breakStatement) override;
virtual bool visit(Return const& _return) override;
virtual bool visit(Throw const& _throw) override;
virtual bool visit(VariableDeclarationStatement const& _variableDeclarationStatement) override;
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index 631a25ff..c94baa10 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -1819,7 +1819,7 @@ void ExpressionCompiler::setLValueToStorageItem(Expression const& _expression)
setLValue<StorageItem>(_expression, *_expression.annotation().type);
}
-bool ExpressionCompiler::cleanupNeededForOp(Type::Category _type, Token::Value _op) const
+bool ExpressionCompiler::cleanupNeededForOp(Type::Category _type, Token::Value _op)
{
if (Token::isCompareOp(_op) || Token::isShiftOp(_op))
return true;
diff --git a/libsolidity/codegen/ExpressionCompiler.h b/libsolidity/codegen/ExpressionCompiler.h
index 5f6c3d64..cdfa096e 100644
--- a/libsolidity/codegen/ExpressionCompiler.h
+++ b/libsolidity/codegen/ExpressionCompiler.h
@@ -119,7 +119,7 @@ private:
/// @returns true if the operator applied to the given type requires a cleanup prior to the
/// operation.
- bool cleanupNeededForOp(Type::Category _type, Token::Value _op) const;
+ static bool cleanupNeededForOp(Type::Category _type, Token::Value _op);
/// @returns the CompilerUtils object containing the current context.
CompilerUtils utils();
diff --git a/libsolidity/formal/SMTLib2Interface.h b/libsolidity/formal/SMTLib2Interface.h
index b8dac366..63188acd 100644
--- a/libsolidity/formal/SMTLib2Interface.h
+++ b/libsolidity/formal/SMTLib2Interface.h
@@ -41,7 +41,7 @@ namespace smt
class SMTLib2Interface: public SolverInterface, public boost::noncopyable
{
public:
- SMTLib2Interface(ReadCallback::Callback const& _queryCallback);
+ explicit SMTLib2Interface(ReadCallback::Callback const& _queryCallback);
void reset() override;
diff --git a/libsolidity/inlineasm/AsmAnalysis.cpp b/libsolidity/inlineasm/AsmAnalysis.cpp
index 76b0bbd5..e5bdc90f 100644
--- a/libsolidity/inlineasm/AsmAnalysis.cpp
+++ b/libsolidity/inlineasm/AsmAnalysis.cpp
@@ -163,11 +163,25 @@ bool AsmAnalyzer::operator()(assembly::StackAssignment const& _assignment)
bool AsmAnalyzer::operator()(assembly::Assignment const& _assignment)
{
+ int const expectedItems = _assignment.variableNames.size();
+ solAssert(expectedItems >= 1, "");
int const stackHeight = m_stackHeight;
bool success = boost::apply_visitor(*this, *_assignment.value);
- solAssert(m_stackHeight >= stackHeight, "Negative value size.");
- if (!checkAssignment(_assignment.variableName, m_stackHeight - stackHeight))
- success = false;
+ if ((m_stackHeight - stackHeight) != expectedItems)
+ {
+ m_errorReporter.declarationError(
+ _assignment.location,
+ "Variable count does not match number of values (" +
+ to_string(expectedItems) +
+ " vs. " +
+ to_string(m_stackHeight - stackHeight) +
+ ")"
+ );
+ return false;
+ }
+ for (auto const& variableName: _assignment.variableNames)
+ if (!checkAssignment(variableName, 1))
+ success = false;
m_info.stackHeightInfo[&_assignment] = m_stackHeight;
return success;
}
diff --git a/libsolidity/inlineasm/AsmData.h b/libsolidity/inlineasm/AsmData.h
index db5840bc..b0dd85ca 100644
--- a/libsolidity/inlineasm/AsmData.h
+++ b/libsolidity/inlineasm/AsmData.h
@@ -54,7 +54,11 @@ struct Label { SourceLocation location; std::string name; };
struct StackAssignment { SourceLocation location; Identifier variableName; };
/// Assignment ("x := mload(20:u256)", expects push-1-expression on the right hand
/// side and requires x to occupy exactly one stack slot.
-struct Assignment { SourceLocation location; Identifier variableName; std::shared_ptr<Statement> value; };
+///
+/// Multiple assignment ("x, y := f()"), where the left hand side variables each occupy
+/// a single stack slot and expects a single expression on the right hand returning
+/// the same amount of items as the number of variables.
+struct Assignment { SourceLocation location; std::vector<Identifier> variableNames; std::shared_ptr<Statement> value; };
/// Functional instruction, e.g. "mul(mload(20:u256), add(2:u256, x))"
struct FunctionalInstruction { SourceLocation location; Instruction instruction; std::vector<Statement> arguments; };
struct FunctionCall { SourceLocation location; Identifier functionName; std::vector<Statement> arguments; };
diff --git a/libsolidity/inlineasm/AsmParser.cpp b/libsolidity/inlineasm/AsmParser.cpp
index d84fe999..3087ad86 100644
--- a/libsolidity/inlineasm/AsmParser.cpp
+++ b/libsolidity/inlineasm/AsmParser.cpp
@@ -122,6 +122,34 @@ assembly::Statement Parser::parseStatement()
{
case Token::LParen:
return parseCall(std::move(statement));
+ case Token::Comma:
+ {
+ // if a comma follows, a multiple assignment is assumed
+
+ if (statement.type() != typeid(assembly::Identifier))
+ fatalParserError("Label name / variable name must precede \",\" (multiple assignment).");
+ assembly::Identifier const& identifier = boost::get<assembly::Identifier>(statement);
+
+ Assignment assignment = createWithLocation<Assignment>(identifier.location);
+ assignment.variableNames.emplace_back(identifier);
+
+ do
+ {
+ expectToken(Token::Comma);
+ statement = parseElementaryOperation(false);
+ if (statement.type() != typeid(assembly::Identifier))
+ fatalParserError("Variable name expected in multiple assignemnt.");
+ assignment.variableNames.emplace_back(boost::get<assembly::Identifier>(statement));
+ }
+ while (currentToken() == Token::Comma);
+
+ expectToken(Token::Colon);
+ expectToken(Token::Assign);
+
+ assignment.value.reset(new Statement(parseExpression()));
+ assignment.location.end = locationOf(*assignment.value).end;
+ return assignment;
+ }
case Token::Colon:
{
if (statement.type() != typeid(assembly::Identifier))
@@ -136,7 +164,7 @@ assembly::Statement Parser::parseStatement()
if (!m_julia && instructions().count(identifier.name))
fatalParserError("Cannot use instruction names for identifier names.");
advance();
- assignment.variableName = identifier;
+ assignment.variableNames.emplace_back(identifier);
assignment.value.reset(new Statement(parseExpression()));
assignment.location.end = locationOf(*assignment.value).end;
return assignment;
diff --git a/libsolidity/inlineasm/AsmPrinter.cpp b/libsolidity/inlineasm/AsmPrinter.cpp
index 47ede91d..a5272808 100644
--- a/libsolidity/inlineasm/AsmPrinter.cpp
+++ b/libsolidity/inlineasm/AsmPrinter.cpp
@@ -116,7 +116,11 @@ string AsmPrinter::operator()(assembly::StackAssignment const& _assignment)
string AsmPrinter::operator()(assembly::Assignment const& _assignment)
{
- return (*this)(_assignment.variableName) + " := " + boost::apply_visitor(*this, *_assignment.value);
+ solAssert(_assignment.variableNames.size() >= 1, "");
+ string variables = (*this)(_assignment.variableNames.front());
+ for (size_t i = 1; i < _assignment.variableNames.size(); ++i)
+ variables += ", " + (*this)(_assignment.variableNames[i]);
+ return variables + " := " + boost::apply_visitor(*this, *_assignment.value);
}
string AsmPrinter::operator()(assembly::VariableDeclaration const& _variableDeclaration)
diff --git a/libsolidity/interface/ErrorReporter.h b/libsolidity/interface/ErrorReporter.h
index 6f7ef51d..a87db21d 100644
--- a/libsolidity/interface/ErrorReporter.h
+++ b/libsolidity/interface/ErrorReporter.h
@@ -86,7 +86,7 @@ public:
void fatalTypeError(SourceLocation const& _location, std::string const& _description);
- void docstringParsingError(std::string const& _location);
+ void docstringParsingError(std::string const& _description);
ErrorList const& errors() const;
diff --git a/libsolidity/parsing/ParserBase.cpp b/libsolidity/parsing/ParserBase.cpp
index fe95b0fe..5b83c5bd 100644
--- a/libsolidity/parsing/ParserBase.cpp
+++ b/libsolidity/parsing/ParserBase.cpp
@@ -104,7 +104,7 @@ void ParserBase::expectToken(Token::Value _value)
void ParserBase::increaseRecursionDepth()
{
m_recursionDepth++;
- if (m_recursionDepth >= 3000)
+ if (m_recursionDepth >= 2560)
fatalParserError("Maximum recursion depth reached during parsing.");
}
diff --git a/scripts/install_deps.bat b/scripts/install_deps.bat
index 512a28df..d02005cc 100644
--- a/scripts/install_deps.bat
+++ b/scripts/install_deps.bat
@@ -58,4 +58,4 @@ REM
REM Copyright (c) 2016 solidity contributors.
REM ---------------------------------------------------------------------------
-cmake -P deps\install_deps.cmake
+cmake -P scripts\install_deps.cmake
diff --git a/scripts/install_deps.cmake b/scripts/install_deps.cmake
new file mode 100644
index 00000000..d1284b9e
--- /dev/null
+++ b/scripts/install_deps.cmake
@@ -0,0 +1,99 @@
+get_filename_component(ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}/../deps" ABSOLUTE)
+
+set(CACHE_DIR "${ROOT_DIR}/cache")
+set(PACKAGES_DIR "${ROOT_DIR}/packages")
+
+function(download URL DST_FILE STATUS)
+ set(TMP_FILE "${DST_FILE}.part")
+
+ get_filename_component(FILE_NAME ${DST_FILE} NAME)
+ if (NOT EXISTS ${DST_FILE})
+ message("Downloading ${FILE_NAME}")
+ file(DOWNLOAD ${URL} ${TMP_FILE} SHOW_PROGRESS STATUS DOWNLOAD_STATUS)
+ list(GET DOWNLOAD_STATUS 0 STATUS_CODE)
+ if (STATUS_CODE EQUAL 0)
+ file(RENAME ${TMP_FILE} ${DST_FILE})
+ else()
+ file(REMOVE ${TMP_FILE})
+ list(GET DOWNLOAD_STATUS 1 ERROR_MSG)
+
+ message("ERROR! Downloading '${FILE_NAME}' failed.")
+ message(STATUS "URL: ${URL}")
+ message(STATUS "Error: ${STATUS_CODE} ${ERROR_MSG}")
+ set(STATUS FALSE PARENT_SCOPE)
+ return()
+ endif()
+ else()
+ message("Using cached ${FILE_NAME}")
+ endif()
+ set(STATUS TRUE PARENT_SCOPE)
+endfunction(download)
+
+function(download_and_unpack PACKAGE_URL DST_DIR)
+ get_filename_component(FILE_NAME ${PACKAGE_URL} NAME)
+
+ set(DST_FILE "${CACHE_DIR}/${FILE_NAME}")
+ set(TMP_FILE "${DST_FILE}.part")
+
+ file(MAKE_DIRECTORY ${CACHE_DIR})
+ file(MAKE_DIRECTORY ${DST_DIR})
+
+ download(${PACKAGE_URL} ${DST_FILE} STATUS)
+
+ if (STATUS)
+ message("Unpacking ${FILE_NAME} to ${DST_DIR}")
+ execute_process(COMMAND ${CMAKE_COMMAND} -E tar -xf ${DST_FILE}
+ WORKING_DIRECTORY ${DST_DIR})
+ endif()
+endfunction(download_and_unpack)
+
+# Packs installed package binaries and headers into an archive.
+function(create_package NAME DIR)
+ message("Creating package ${NAME}")
+ file(MAKE_DIRECTORY ${PACKAGES_DIR})
+
+ # To create an archive without addicional top level directory
+ # (like package-X.Y.Z) we need to know all top level files/dirs.
+ # Usually it is just "win64" dir.
+ file(GLOB TOP_FILES RELATIVE ${DIR} "${DIR}/*")
+
+ set(PACKAGE_FILE "${PACKAGES_DIR}/${NAME}.tar.gz")
+ execute_process(COMMAND ${CMAKE_COMMAND} -E
+ tar -czf ${PACKAGE_FILE} ${TOP_FILES}
+ WORKING_DIRECTORY ${DIR})
+endfunction(create_package)
+
+# Downloads the source code of the package and unpacks it to dedicated 'src'
+# dir. Also creates 'build' and 'install' dir to be used by a build script.
+function(prepare_package_source NAME VERSION URL)
+ set(PACKAGE_NAME "${NAME}-${VERSION}")
+
+ set(PACKAGE_DIR "${CACHE_DIR}/${PACKAGE_NAME}")
+ set(SOURCE_DIR "${PACKAGE_DIR}/src")
+ set(BUILD_DIR "${PACKAGE_DIR}/build")
+ set(INSTALL_DIR "${PACKAGE_DIR}/install")
+
+ if (NOT EXISTS ${SOURCE_DIR})
+ download_and_unpack(${URL} ${PACKAGE_DIR} STATUS)
+ file(GLOB ORIG_SOURCE_DIR_NAME "${PACKAGE_DIR}/*")
+ file(RENAME ${ORIG_SOURCE_DIR_NAME} ${SOURCE_DIR})
+ endif()
+
+ file(MAKE_DIRECTORY ${BUILD_DIR})
+ file(MAKE_DIRECTORY ${INSTALL_DIR})
+
+ # Export names and dirs to be used by a package-specific build script.
+ set(PACKAGE_NAME ${PACKAGE_NAME} PARENT_SCOPE)
+ set(SOURCE_DIR ${SOURCE_DIR} PARENT_SCOPE)
+ set(BUILD_DIR ${BUILD_DIR} PARENT_SCOPE)
+ set(INSTALL_DIR ${INSTALL_DIR} PARENT_SCOPE)
+endfunction()
+
+set(INSTALL_DIR "${ROOT_DIR}/install")
+set(SERVER "https://github.com/ethereum/cpp-dependencies/releases/download/vc140/")
+
+function(download_and_install PACKAGE_NAME)
+ download_and_unpack("${SERVER}${PACKAGE_NAME}.tar.gz" ${INSTALL_DIR})
+endfunction(download_and_install)
+
+download_and_install("boost-1.61")
diff --git a/test/ExecutionFramework.h b/test/ExecutionFramework.h
index ba385dee..e8d8d111 100644
--- a/test/ExecutionFramework.h
+++ b/test/ExecutionFramework.h
@@ -262,7 +262,7 @@ protected:
void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0);
void sendEther(Address const& _to, u256 const& _value);
size_t currentTimestamp();
- size_t blockTimestamp(u256 number);
+ size_t blockTimestamp(u256 _number);
/// @returns the (potentially newly created) _ith address.
Address account(size_t _i);
diff --git a/test/RPCSession.h b/test/RPCSession.h
index 558cb99f..eae6a09c 100644
--- a/test/RPCSession.h
+++ b/test/RPCSession.h
@@ -40,7 +40,7 @@
class IPCSocket : public boost::noncopyable
{
public:
- IPCSocket(std::string const& _path);
+ explicit IPCSocket(std::string const& _path);
std::string sendRequest(std::string const& _req);
~IPCSocket() { CloseHandle(m_socket); }
@@ -55,7 +55,7 @@ private:
class IPCSocket: public boost::noncopyable
{
public:
- IPCSocket(std::string const& _path);
+ explicit IPCSocket(std::string const& _path);
std::string sendRequest(std::string const& _req);
~IPCSocket() { close(m_socket); }
@@ -107,7 +107,7 @@ public:
Json::Value eth_getBlockByNumber(std::string const& _blockNumber, bool _fullObjects);
std::string eth_call(TransactionData const& _td, std::string const& _blockNumber);
TransactionReceipt eth_getTransactionReceipt(std::string const& _transactionHash);
- std::string eth_sendTransaction(TransactionData const& _transactionData);
+ std::string eth_sendTransaction(TransactionData const& _td);
std::string eth_sendTransaction(std::string const& _transaction);
std::string eth_getBalance(std::string const& _address, std::string const& _blockNumber);
std::string eth_getStorageRoot(std::string const& _address, std::string const& _blockNumber);
diff --git a/test/libdevcore/MiniMoustache.cpp b/test/libdevcore/Whiskers.cpp
index 84149173..84149173 100644
--- a/test/libdevcore/MiniMoustache.cpp
+++ b/test/libdevcore/Whiskers.cpp
diff --git a/test/libjulia/Parser.cpp b/test/libjulia/Parser.cpp
index 51070370..f8c1aa4d 100644
--- a/test/libjulia/Parser.cpp
+++ b/test/libjulia/Parser.cpp
@@ -249,6 +249,26 @@ BOOST_AUTO_TEST_CASE(recursion_depth)
CHECK_ERROR(input, ParserError, "recursion");
}
+BOOST_AUTO_TEST_CASE(multiple_assignment)
+{
+ CHECK_ERROR("{ let x:u256 function f() -> a:u256, b:u256 {} 123:u256, x := f() }", ParserError, "Label name / variable name must precede \",\" (multiple assignment).");
+ CHECK_ERROR("{ let x:u256 function f() -> a:u256, b:u256 {} x, 123:u256 := f() }", ParserError, "Variable name expected in multiple assignemnt.");
+
+ /// NOTE: Travis hiccups if not having a variable
+ char const* text = R"(
+ {
+ function f(a:u256) -> r1:u256, r2:u256 {
+ r1 := a
+ r2 := 7:u256
+ }
+ let x:u256 := 9:u256
+ let y:u256 := 2:u256
+ x, y := f(x)
+ }
+ )";
+ BOOST_CHECK(successParse(text));
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/AnalysisFramework.h b/test/libsolidity/AnalysisFramework.h
index f73f06c2..172ae01b 100644
--- a/test/libsolidity/AnalysisFramework.h
+++ b/test/libsolidity/AnalysisFramework.h
@@ -59,8 +59,8 @@ protected:
void printErrors();
- ContractDefinition const* retrieveContractByName(SourceUnit const& _source, std::string const& _name);
- FunctionTypePointer retrieveFunctionBySignature(
+ static ContractDefinition const* retrieveContractByName(SourceUnit const& _source, std::string const& _name);
+ static FunctionTypePointer retrieveFunctionBySignature(
ContractDefinition const& _contract,
std::string const& _signature
);
diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp
index 0debc66d..da3522b4 100644
--- a/test/libsolidity/InlineAssembly.cpp
+++ b/test/libsolidity/InlineAssembly.cpp
@@ -412,7 +412,25 @@ BOOST_AUTO_TEST_CASE(recursion_depth)
CHECK_PARSE_ERROR(input, ParserError, "recursion");
}
+BOOST_AUTO_TEST_CASE(multiple_assignment)
+{
+ CHECK_PARSE_ERROR("{ let x function f() -> a, b {} 123, x := f() }", ParserError, "Label name / variable name must precede \",\" (multiple assignment).");
+ CHECK_PARSE_ERROR("{ let x function f() -> a, b {} x, 123 := f() }", ParserError, "Variable name expected in multiple assignemnt.");
+ /// NOTE: Travis hiccups if not having a variable
+ char const* text = R"(
+ {
+ function f(a) -> r1, r2 {
+ r1 := a
+ r2 := 7
+ }
+ let x := 9
+ let y := 2
+ x, y := f(x)
+ }
+ )";
+ BOOST_CHECK(successParse(text));
+}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index bdac8278..458b64f4 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -7867,6 +7867,31 @@ BOOST_AUTO_TEST_CASE(inline_assembly_function_call)
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(1), u256(2), u256(7)));
}
+BOOST_AUTO_TEST_CASE(inline_assembly_function_call_assignment)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function f() {
+ assembly {
+ let a1, b1, c1
+ function asmfun(a, b, c) -> x, y, z {
+ x := a
+ y := b
+ z := 7
+ }
+ a1, b1, c1 := asmfun(1, 2, 3)
+ mstore(0x00, a1)
+ mstore(0x20, b1)
+ mstore(0x40, c1)
+ return(0, 0x60)
+ }
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(1), u256(2), u256(7)));
+}
+
BOOST_AUTO_TEST_CASE(inline_assembly_function_call2)
{
char const* sourceCode = R"(