aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Changelog.md2
-rw-r--r--docs/contracts.rst14
-rw-r--r--docs/units-and-global-variables.rst7
-rw-r--r--libjulia/optimiser/CommonSubexpressionEliminator.cpp48
-rw-r--r--libjulia/optimiser/CommonSubexpressionEliminator.h45
-rw-r--r--libsolidity/analysis/StaticAnalyzer.cpp14
-rw-r--r--libsolidity/analysis/StaticAnalyzer.h4
-rw-r--r--libsolidity/analysis/TypeChecker.cpp90
-rw-r--r--libsolidity/analysis/TypeChecker.h7
-rw-r--r--libsolidity/ast/ASTAnnotations.h3
-rw-r--r--libsolidity/ast/Types.h12
-rw-r--r--libsolidity/codegen/ContractCompiler.cpp39
-rw-r--r--libsolidity/codegen/ContractCompiler.h2
-rwxr-xr-xscripts/tests.sh12
-rw-r--r--test/libjulia/CommonSubexpression.cpp102
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp8
-rw-r--r--test/libsolidity/syntaxTests/inheritance/allow_empty_duplicated_super_constructor_call.sol3
-rw-r--r--test/libsolidity/syntaxTests/inheritance/base_arguments_multiple_inheritance.sol9
-rw-r--r--test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/ancestor.sol5
-rw-r--r--test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/ancestor_V050.sol7
-rw-r--r--test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/base.sol4
-rw-r--r--test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/base_V050.sol6
-rw-r--r--test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/base_multi.sol7
-rw-r--r--test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/base_multi_no_constructor.sol6
-rw-r--r--test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/base_multi_no_constructor_modifier_style.sol6
25 files changed, 383 insertions, 79 deletions
diff --git a/Changelog.md b/Changelog.md
index d6860bdf..3b8cba1d 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -9,6 +9,7 @@ Features:
* Optimizer: Remove useless ``SWAP1`` instruction preceding a commutative instruction (such as ``ADD``, ``MUL``, etc).
* Optimizer: Replace comparison operators (``LT``, ``GT``, etc) with opposites if preceded by ``SWAP1``, e.g. ``SWAP1 LT`` is replaced with ``GT``.
* Optimizer: Optimize across ``mload`` if ``msize()`` is not used.
+ * Static Analyzer: Error on duplicated super constructor calls as experimental 0.5.0 feature.
* Syntax Checker: Issue warning for empty structs (or error as experimental 0.5.0 feature).
* General: Introduce new constructor syntax using the ``constructor`` keyword as experimental 0.5.0 feature.
* Inheritance: Error when using empty parenthesis for base class constructors that require arguments as experimental 0.5.0 feature.
@@ -27,6 +28,7 @@ Bugfixes:
* Type System: Improve error message when attempting to shift by a fractional amount.
* Type System: Make external library functions accessible.
* Type System: Prevent encoding of weird types.
+ * Static Analyzer: Fix non-deterministic order of unused variable warnings.
### 0.4.21 (2018-03-07)
diff --git a/docs/contracts.rst b/docs/contracts.rst
index f8a44fb3..0dd9845c 100644
--- a/docs/contracts.rst
+++ b/docs/contracts.rst
@@ -1034,9 +1034,12 @@ the base constructors. This can be done in two ways::
constructor(uint _x) public { x = _x; }
}
- contract Derived is Base(7) {
- constructor(uint _y) Base(_y * _y) public {
- }
+ contract Derived1 is Base(7) {
+ constructor(uint _y) public {}
+ }
+
+ contract Derived2 is Base {
+ constructor(uint _y) Base(_y * _y) public {}
}
One way is directly in the inheritance list (``is Base(7)``). The other is in
@@ -1046,8 +1049,9 @@ do it is more convenient if the constructor argument is a
constant and defines the behaviour of the contract or
describes it. The second way has to be used if the
constructor arguments of the base depend on those of the
-derived contract. If, as in this silly example, both places
-are used, the modifier-style argument takes precedence.
+derived contract. Arguments have to be given either in the
+inheritance list or in modifier-style in the derived constuctor.
+Specifying arguments in both places is an error.
.. index:: ! inheritance;multiple, ! linearization, ! C3 linearization
diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst
index 2571f20a..e7f41ed1 100644
--- a/docs/units-and-global-variables.rst
+++ b/docs/units-and-global-variables.rst
@@ -169,6 +169,13 @@ For more information, see the section on :ref:`address`.
Use a pattern where the recipient withdraws the money.
.. note::
+ If storage variables are accessed via a low-level delegatecall, the storage layout of the two contracts
+ must align in order for the called contract to correctly access the storage variables of the calling contract by name.
+ This is of course not the case if storage pointers are passed as function arguments as in the case for
+ the high-level libraries.
+
+
+.. note::
The use of ``callcode`` is discouraged and will be removed in the future.
.. index:: this, selfdestruct
diff --git a/libjulia/optimiser/CommonSubexpressionEliminator.cpp b/libjulia/optimiser/CommonSubexpressionEliminator.cpp
new file mode 100644
index 00000000..229bd35e
--- /dev/null
+++ b/libjulia/optimiser/CommonSubexpressionEliminator.cpp
@@ -0,0 +1,48 @@
+/*(
+ This file is part of solidity.
+
+ solidity is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ solidity is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with solidity. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * Optimisation stage that replaces expressions known to be the current value of a variable
+ * in scope by a reference to that variable.
+ */
+
+#include <libjulia/optimiser/CommonSubexpressionEliminator.h>
+
+#include <libjulia/optimiser/Metrics.h>
+#include <libjulia/optimiser/SyntacticalEquality.h>
+
+#include <libsolidity/inlineasm/AsmData.h>
+
+using namespace std;
+using namespace dev;
+using namespace dev::julia;
+
+void CommonSubexpressionEliminator::visit(Expression& _e)
+{
+ // Single exception for substitution: We do not substitute one variable for another.
+ if (_e.type() != typeid(Identifier))
+ // TODO this search rather inefficient.
+ for (auto const& var: m_value)
+ {
+ solAssert(var.second, "");
+ if (SyntacticalEqualityChecker::equal(_e, *var.second))
+ {
+ _e = Identifier{locationOf(_e), var.first};
+ break;
+ }
+ }
+ DataFlowAnalyzer::visit(_e);
+}
diff --git a/libjulia/optimiser/CommonSubexpressionEliminator.h b/libjulia/optimiser/CommonSubexpressionEliminator.h
new file mode 100644
index 00000000..a8ca3abb
--- /dev/null
+++ b/libjulia/optimiser/CommonSubexpressionEliminator.h
@@ -0,0 +1,45 @@
+/*
+ This file is part of solidity.
+
+ solidity is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ solidity is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with solidity. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * Optimisation stage that replaces expressions known to be the current value of a variable
+ * in scope by a reference to that variable.
+ */
+
+#pragma once
+
+#include <libjulia/optimiser/DataFlowAnalyzer.h>
+
+namespace dev
+{
+namespace julia
+{
+
+/**
+ * Optimisation stage that replaces expressions known to be the current value of a variable
+ * in scope by a reference to that variable.
+ *
+ * Prerequisite: Disambiguator
+ */
+class CommonSubexpressionEliminator: public DataFlowAnalyzer
+{
+protected:
+ using ASTModifier::visit;
+ virtual void visit(Expression& _e) override;
+};
+
+}
+}
diff --git a/libsolidity/analysis/StaticAnalyzer.cpp b/libsolidity/analysis/StaticAnalyzer.cpp
index d96f8748..33b0e296 100644
--- a/libsolidity/analysis/StaticAnalyzer.cpp
+++ b/libsolidity/analysis/StaticAnalyzer.cpp
@@ -78,13 +78,13 @@ void StaticAnalyzer::endVisit(FunctionDefinition const&)
for (auto const& var: m_localVarUseCount)
if (var.second == 0)
{
- if (var.first->isCallableParameter())
+ if (var.first.second->isCallableParameter())
m_errorReporter.warning(
- var.first->location(),
+ var.first.second->location(),
"Unused function parameter. Remove or comment out the variable name to silence this warning."
);
else
- m_errorReporter.warning(var.first->location(), "Unused local variable.");
+ m_errorReporter.warning(var.first.second->location(), "Unused local variable.");
}
m_localVarUseCount.clear();
@@ -97,7 +97,7 @@ bool StaticAnalyzer::visit(Identifier const& _identifier)
{
solAssert(!var->name().empty(), "");
if (var->isLocalVariable())
- m_localVarUseCount[var] += 1;
+ m_localVarUseCount[make_pair(var->id(), var)] += 1;
}
return true;
}
@@ -109,7 +109,7 @@ bool StaticAnalyzer::visit(VariableDeclaration const& _variable)
solAssert(_variable.isLocalVariable(), "");
if (_variable.name() != "")
// This is not a no-op, the entry might pre-exist.
- m_localVarUseCount[&_variable] += 0;
+ m_localVarUseCount[make_pair(_variable.id(), &_variable)] += 0;
}
else if (_variable.isStateVariable())
{
@@ -132,7 +132,7 @@ bool StaticAnalyzer::visit(Return const& _return)
if (m_currentFunction && _return.expression())
for (auto const& var: m_currentFunction->returnParameters())
if (!var->name().empty())
- m_localVarUseCount[var.get()] += 1;
+ m_localVarUseCount[make_pair(var->id(), var.get())] += 1;
return true;
}
@@ -224,7 +224,7 @@ bool StaticAnalyzer::visit(InlineAssembly const& _inlineAssembly)
{
solAssert(!var->name().empty(), "");
if (var->isLocalVariable())
- m_localVarUseCount[var] += 1;
+ m_localVarUseCount[make_pair(var->id(), var)] += 1;
}
}
diff --git a/libsolidity/analysis/StaticAnalyzer.h b/libsolidity/analysis/StaticAnalyzer.h
index 124c4e7c..0a806bbd 100644
--- a/libsolidity/analysis/StaticAnalyzer.h
+++ b/libsolidity/analysis/StaticAnalyzer.h
@@ -77,7 +77,9 @@ private:
bool m_nonPayablePublic = false;
/// Number of uses of each (named) local variable in a function, counter is initialized with zero.
- std::map<VariableDeclaration const*, int> m_localVarUseCount;
+ /// Pairs of AST ids and pointers are used as keys to ensure a deterministic order
+ /// when traversing.
+ std::map<std::pair<size_t, VariableDeclaration const*>, int> m_localVarUseCount;
FunctionDefinition const* m_currentFunction = nullptr;
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index a252742d..1d8fd82d 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -101,7 +101,7 @@ bool TypeChecker::visit(ContractDefinition const& _contract)
checkContractDuplicateEvents(_contract);
checkContractIllegalOverrides(_contract);
checkContractAbstractFunctions(_contract);
- checkContractAbstractConstructors(_contract);
+ checkContractBaseConstructorArguments(_contract);
FunctionDefinition const* function = _contract.constructor();
if (function)
@@ -291,42 +291,90 @@ void TypeChecker::checkContractAbstractFunctions(ContractDefinition const& _cont
}
}
-void TypeChecker::checkContractAbstractConstructors(ContractDefinition const& _contract)
+void TypeChecker::checkContractBaseConstructorArguments(ContractDefinition const& _contract)
{
- set<ContractDefinition const*> argumentsNeeded;
- // check that we get arguments for all base constructors that need it.
- // If not mark the contract as abstract (not fully implemented)
-
vector<ContractDefinition const*> const& bases = _contract.annotation().linearizedBaseContracts;
- for (ContractDefinition const* contract: bases)
- if (FunctionDefinition const* constructor = contract->constructor())
- if (contract != &_contract && !constructor->parameters().empty())
- argumentsNeeded.insert(contract);
+ // Determine the arguments that are used for the base constructors.
for (ContractDefinition const* contract: bases)
{
if (FunctionDefinition const* constructor = contract->constructor())
for (auto const& modifier: constructor->modifiers())
{
- auto baseContract = dynamic_cast<ContractDefinition const*>(
- &dereference(*modifier->name())
- );
- if (baseContract)
- argumentsNeeded.erase(baseContract);
+ auto baseContract = dynamic_cast<ContractDefinition const*>(&dereference(*modifier->name()));
+ if (baseContract && baseContract->constructor() && !modifier->arguments().empty())
+ annotateBaseConstructorArguments(_contract, baseContract->constructor(), modifier.get());
}
-
for (ASTPointer<InheritanceSpecifier> const& base: contract->baseContracts())
{
auto baseContract = dynamic_cast<ContractDefinition const*>(&dereference(base->name()));
solAssert(baseContract, "");
- if (base->arguments() && !base->arguments()->empty())
- argumentsNeeded.erase(baseContract);
+
+ if (baseContract->constructor() && base->arguments() && !base->arguments()->empty())
+ annotateBaseConstructorArguments(_contract, baseContract->constructor(), base.get());
}
}
- if (!argumentsNeeded.empty())
- for (ContractDefinition const* contract: argumentsNeeded)
- _contract.annotation().unimplementedFunctions.push_back(contract->constructor());
+
+ // check that we get arguments for all base constructors that need it.
+ // If not mark the contract as abstract (not fully implemented)
+ for (ContractDefinition const* contract: bases)
+ if (FunctionDefinition const* constructor = contract->constructor())
+ if (contract != &_contract && !constructor->parameters().empty())
+ if (!_contract.annotation().baseConstructorArguments.count(constructor))
+ _contract.annotation().unimplementedFunctions.push_back(constructor);
+}
+
+void TypeChecker::annotateBaseConstructorArguments(
+ ContractDefinition const& _currentContract,
+ FunctionDefinition const* _baseConstructor,
+ ASTNode const* _argumentNode
+)
+{
+ bool const v050 = _currentContract.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050);
+
+ solAssert(_baseConstructor, "");
+ solAssert(_argumentNode, "");
+
+ auto insertionResult = _currentContract.annotation().baseConstructorArguments.insert(
+ std::make_pair(_baseConstructor, _argumentNode)
+ );
+ if (!insertionResult.second)
+ {
+ ASTNode const* previousNode = insertionResult.first->second;
+
+ SourceLocation const* mainLocation = nullptr;
+ SecondarySourceLocation ssl;
+
+ if (
+ _currentContract.location().contains(previousNode->location()) ||
+ _currentContract.location().contains(_argumentNode->location())
+ )
+ {
+ mainLocation = &previousNode->location();
+ ssl.append("Second constructor call is here:", _argumentNode->location());
+ }
+ else
+ {
+ mainLocation = &_currentContract.location();
+ ssl.append("First constructor call is here: ", _argumentNode->location());
+ ssl.append("Second constructor call is here: ", previousNode->location());
+ }
+
+ if (v050)
+ m_errorReporter.declarationError(
+ *mainLocation,
+ ssl,
+ "Base constructor arguments given twice."
+ );
+ else
+ m_errorReporter.warning(
+ *mainLocation,
+ "Base constructor arguments given twice.",
+ ssl
+ );
+ }
+
}
void TypeChecker::checkContractIllegalOverrides(ContractDefinition const& _contract)
diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h
index 2ba31232..2245abd6 100644
--- a/libsolidity/analysis/TypeChecker.h
+++ b/libsolidity/analysis/TypeChecker.h
@@ -73,7 +73,12 @@ private:
void checkFunctionOverride(FunctionDefinition const& function, FunctionDefinition const& super);
void overrideError(FunctionDefinition const& function, FunctionDefinition const& super, std::string message);
void checkContractAbstractFunctions(ContractDefinition const& _contract);
- void checkContractAbstractConstructors(ContractDefinition const& _contract);
+ void checkContractBaseConstructorArguments(ContractDefinition const& _contract);
+ void annotateBaseConstructorArguments(
+ ContractDefinition const& _currentContract,
+ FunctionDefinition const* _baseConstructor,
+ ASTNode const* _argumentNode
+ );
/// Checks that different functions with external visibility end up having different
/// external argument types (i.e. different signature).
void checkContractExternalTypeClashes(ContractDefinition const& _contract);
diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h
index 3d4236cc..5cbe42bd 100644
--- a/libsolidity/ast/ASTAnnotations.h
+++ b/libsolidity/ast/ASTAnnotations.h
@@ -90,6 +90,9 @@ struct ContractDefinitionAnnotation: TypeDeclarationAnnotation, DocumentedAnnota
/// List of contracts this contract creates, i.e. which need to be compiled first.
/// Also includes all contracts from @a linearizedBaseContracts.
std::set<ContractDefinition const*> contractDependencies;
+ /// Mapping containing the nodes that define the arguments for base constructors.
+ /// These can either be inheritance specifiers or modifier invocations.
+ std::map<FunctionDefinition const*, ASTNode const*> baseConstructorArguments;
};
struct FunctionDefinitionAnnotation: ASTAnnotation, DocumentedAnnotation
diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h
index aa46520f..05f506f1 100644
--- a/libsolidity/ast/Types.h
+++ b/libsolidity/ast/Types.h
@@ -403,7 +403,7 @@ private:
};
/**
- * Integer and fixed point constants either literals or computed.
+ * Integer and fixed point constants either literals or computed.
* Example expressions: 2, 3.14, 2+10.2, ~10.
* There is one distinct type per value.
*/
@@ -415,7 +415,7 @@ public:
/// @returns true if the literal is a valid integer.
static std::tuple<bool, rational> isValidLiteral(Literal const& _literal);
-
+
explicit RationalNumberType(rational const& _value):
m_value(_value)
{}
@@ -436,7 +436,7 @@ public:
/// @returns the smallest integer type that can hold the value or an empty pointer if not possible.
std::shared_ptr<IntegerType const> integerType() const;
- /// @returns the smallest fixed type that can hold the value or incurs the least precision loss.
+ /// @returns the smallest fixed type that can hold the value or incurs the least precision loss.
/// If the integer part does not fit, returns an empty pointer.
std::shared_ptr<FixedPointType const> fixedPointType() const;
@@ -778,7 +778,7 @@ public:
virtual std::string canonicalName() const override;
virtual std::string signatureInExternalFunction(bool _structsByName) const override;
- /// @returns a function that peforms the type conversion between a list of struct members
+ /// @returns a function that performs the type conversion between a list of struct members
/// and a memory struct of this type.
FunctionTypePointer constructorType() const;
@@ -1039,7 +1039,7 @@ public:
return *m_declaration;
}
bool hasDeclaration() const { return !!m_declaration; }
- /// @returns true if the the result of this function only depends on its arguments
+ /// @returns true if the result of this function only depends on its arguments
/// and it does not modify the state.
/// Currently, this will only return true for internal functions like keccak and ecrecover.
bool isPure() const;
@@ -1056,7 +1056,7 @@ public:
bool bound() const { return m_bound; }
/// @returns a copy of this type, where gas or value are set manually. This will never set one
- /// of the parameters to fals.
+ /// of the parameters to false.
TypePointer copyAndSetGasOrValue(bool _setGas, bool _setValue) const;
/// @returns a copy of this function type where all return parameters of dynamic size are
diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp
index d3a7e4ea..3ca0b69d 100644
--- a/libsolidity/codegen/ContractCompiler.cpp
+++ b/libsolidity/codegen/ContractCompiler.cpp
@@ -135,34 +135,13 @@ void ContractCompiler::appendInitAndConstructorCode(ContractDefinition const& _c
{
solAssert(!_contract.isLibrary(), "Tried to initialize library.");
CompilerContext::LocationSetter locationSetter(m_context, _contract);
- // Determine the arguments that are used for the base constructors.
- std::vector<ContractDefinition const*> const& bases = _contract.annotation().linearizedBaseContracts;
- for (ContractDefinition const* contract: bases)
- {
- if (FunctionDefinition const* constructor = contract->constructor())
- for (auto const& modifier: constructor->modifiers())
- {
- auto baseContract = dynamic_cast<ContractDefinition const*>(
- modifier->name()->annotation().referencedDeclaration
- );
- if (baseContract && !modifier->arguments().empty())
- if (m_baseArguments.count(baseContract->constructor()) == 0)
- m_baseArguments[baseContract->constructor()] = &modifier->arguments();
- }
- for (ASTPointer<InheritanceSpecifier> const& base: contract->baseContracts())
- {
- ContractDefinition const* baseContract = dynamic_cast<ContractDefinition const*>(
- base->name().annotation().referencedDeclaration
- );
- solAssert(baseContract, "");
+ m_baseArguments = &_contract.annotation().baseConstructorArguments;
- if (!m_baseArguments.count(baseContract->constructor()) && base->arguments() && !base->arguments()->empty())
- m_baseArguments[baseContract->constructor()] = base->arguments();
- }
- }
// Initialization of state variables in base-to-derived order.
- for (ContractDefinition const* contract: boost::adaptors::reverse(bases))
+ for (ContractDefinition const* contract: boost::adaptors::reverse(
+ _contract.annotation().linearizedBaseContracts
+ ))
initializeStateVariables(*contract);
if (FunctionDefinition const* constructor = _contract.constructor())
@@ -236,8 +215,14 @@ void ContractCompiler::appendBaseConstructor(FunctionDefinition const& _construc
FunctionType constructorType(_constructor);
if (!constructorType.parameterTypes().empty())
{
- solAssert(m_baseArguments.count(&_constructor), "");
- std::vector<ASTPointer<Expression>> const* arguments = m_baseArguments[&_constructor];
+ solAssert(m_baseArguments, "");
+ solAssert(m_baseArguments->count(&_constructor), "");
+ std::vector<ASTPointer<Expression>> const* arguments = nullptr;
+ ASTNode const* baseArgumentNode = m_baseArguments->at(&_constructor);
+ if (auto inheritanceSpecifier = dynamic_cast<InheritanceSpecifier const*>(baseArgumentNode))
+ arguments = inheritanceSpecifier->arguments();
+ else if (auto modifierInvocation = dynamic_cast<ModifierInvocation const*>(baseArgumentNode))
+ arguments = &modifierInvocation->arguments();
solAssert(arguments, "");
solAssert(arguments->size() == constructorType.parameterTypes().size(), "");
for (unsigned i = 0; i < arguments->size(); ++i)
diff --git a/libsolidity/codegen/ContractCompiler.h b/libsolidity/codegen/ContractCompiler.h
index e04a56fb..02a3452f 100644
--- a/libsolidity/codegen/ContractCompiler.h
+++ b/libsolidity/codegen/ContractCompiler.h
@@ -135,7 +135,7 @@ private:
FunctionDefinition const* m_currentFunction = nullptr;
unsigned m_stackCleanupForReturn = 0; ///< this number of stack elements need to be removed before jump to m_returnTag
// arguments for base constructors, filled in derived-to-base order
- std::map<FunctionDefinition const*, std::vector<ASTPointer<Expression>> const*> m_baseArguments;
+ std::map<FunctionDefinition const*, ASTNode const*> const* m_baseArguments;
};
}
diff --git a/scripts/tests.sh b/scripts/tests.sh
index 37ffafc2..2e40f8cb 100755
--- a/scripts/tests.sh
+++ b/scripts/tests.sh
@@ -61,13 +61,13 @@ function download_eth()
mkdir -p /tmp/test
if grep -i trusty /etc/lsb-release >/dev/null 2>&1
then
- # built from 1ecff3cac12f0fbbeea3e645f331d5ac026b24d3 at 2018-03-06
- ETH_BINARY=eth_byzantium_trusty
- ETH_HASH="5432ea81c150e8a3547615bf597cd6dce9e1e27b"
+ # built from 5ac09111bd0b6518365fe956e1bdb97a2db82af1 at 2018-04-05
+ ETH_BINARY=eth_2018-04-05_trusty
+ ETH_HASH="1e5e178b005e5b51f9d347df4452875ba9b53cc6"
else
- # built from ?? at 2018-02-13 ?
- ETH_BINARY=eth_byzantium_artful
- ETH_HASH="e527dd3e3dc17b983529dd7dcfb74a0d3a5aed4e"
+ # built from 5ac09111bd0b6518365fe956e1bdb97a2db82af1 at 2018-04-05
+ ETH_BINARY=eth_2018-04-05_artful
+ ETH_HASH="eb2d0df022753bb2b442ba73e565a9babf6828d6"
fi
wget -q -O /tmp/test/eth https://github.com/ethereum/cpp-ethereum/releases/download/solidityTester/$ETH_BINARY
test "$(shasum /tmp/test/eth)" = "$ETH_HASH /tmp/test/eth"
diff --git a/test/libjulia/CommonSubexpression.cpp b/test/libjulia/CommonSubexpression.cpp
new file mode 100644
index 00000000..8a575c48
--- /dev/null
+++ b/test/libjulia/CommonSubexpression.cpp
@@ -0,0 +1,102 @@
+/*
+ This file is part of solidity.
+
+ solidity is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ solidity is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with solidity. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * Unit tests for the common subexpression eliminator optimizer stage.
+ */
+
+#include <test/libjulia/Common.h>
+
+#include <libjulia/optimiser/CommonSubexpressionEliminator.h>
+
+#include <libsolidity/inlineasm/AsmPrinter.h>
+
+#include <boost/test/unit_test.hpp>
+
+#include <boost/range/adaptors.hpp>
+#include <boost/algorithm/string/join.hpp>
+
+using namespace std;
+using namespace dev;
+using namespace dev::julia;
+using namespace dev::julia::test;
+using namespace dev::solidity;
+
+
+#define CHECK(_original, _expectation)\
+do\
+{\
+ assembly::AsmPrinter p;\
+ Block b = disambiguate(_original, false);\
+ (CommonSubexpressionEliminator{})(b);\
+ string result = p(b);\
+ BOOST_CHECK_EQUAL(result, format(_expectation, false));\
+}\
+while(false)
+
+BOOST_AUTO_TEST_SUITE(IuliaCSE)
+
+BOOST_AUTO_TEST_CASE(smoke_test)
+{
+ CHECK("{ }", "{ }");
+}
+
+BOOST_AUTO_TEST_CASE(trivial)
+{
+ CHECK(
+ "{ let a := mul(1, codesize()) let b := mul(1, codesize()) }",
+ "{ let a := mul(1, codesize()) let b := a }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(non_movable_instr)
+{
+ CHECK(
+ "{ let a := mload(1) let b := mload(1) }",
+ "{ let a := mload(1) let b := mload(1) }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(non_movable_instr2)
+{
+ CHECK(
+ "{ let a := gas() let b := gas() }",
+ "{ let a := gas() let b := gas() }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(branches_if)
+{
+ CHECK(
+ "{ let b := 1 if b { b := 1 } let c := 1 }",
+ "{ let b := 1 if b { b := b } let c := 1 }"
+ );
+}
+
+BOOST_AUTO_TEST_CASE(branches_for)
+{
+ CHECK(
+ "{ let a := 1 let b := codesize()"
+ "for { } lt(1, codesize()) { mstore(1, codesize()) a := add(a, codesize()) }"
+ "{ mstore(1, codesize()) } mstore(1, codesize()) }",
+
+ "{ let a := 1 let b := codesize()"
+ "for { } lt(1, b) { mstore(1, b) a := add(a, b) }"
+ "{ mstore(1, b) } mstore(1, b) }"
+ );
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index beeae786..5ed53a2f 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -5191,7 +5191,7 @@ BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base)
}
uint public m_i;
}
- contract Derived is Base(2) {
+ contract Derived is Base {
function Derived(uint i) Base(i)
{}
}
@@ -5211,10 +5211,10 @@ BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base_base)
}
uint public m_i;
}
- contract Base1 is Base(3) {
+ contract Base1 is Base {
function Base1(uint k) Base(k*k) {}
}
- contract Derived is Base(3), Base1(2) {
+ contract Derived is Base, Base1 {
function Derived(uint i) Base(i) Base1(i)
{}
}
@@ -5235,7 +5235,7 @@ BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base_base_with_gap)
uint public m_i;
}
contract Base1 is Base(3) {}
- contract Derived is Base(2), Base1 {
+ contract Derived is Base, Base1 {
function Derived(uint i) Base(i) {}
}
contract Final is Derived(4) {
diff --git a/test/libsolidity/syntaxTests/inheritance/allow_empty_duplicated_super_constructor_call.sol b/test/libsolidity/syntaxTests/inheritance/allow_empty_duplicated_super_constructor_call.sol
new file mode 100644
index 00000000..1f580b1d
--- /dev/null
+++ b/test/libsolidity/syntaxTests/inheritance/allow_empty_duplicated_super_constructor_call.sol
@@ -0,0 +1,3 @@
+contract A { constructor() public { } }
+contract B1 is A { constructor() A() public { } }
+contract B2 is A { constructor() A public { } }
diff --git a/test/libsolidity/syntaxTests/inheritance/base_arguments_multiple_inheritance.sol b/test/libsolidity/syntaxTests/inheritance/base_arguments_multiple_inheritance.sol
new file mode 100644
index 00000000..5483d5d7
--- /dev/null
+++ b/test/libsolidity/syntaxTests/inheritance/base_arguments_multiple_inheritance.sol
@@ -0,0 +1,9 @@
+contract Base {
+ constructor(uint) public { }
+}
+contract Base1 is Base(3) {}
+contract Derived is Base, Base1 {
+ constructor(uint i) Base(i) public {}
+}
+// ----
+// Warning: Base constructor arguments given twice.
diff --git a/test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/ancestor.sol b/test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/ancestor.sol
new file mode 100644
index 00000000..8b1af245
--- /dev/null
+++ b/test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/ancestor.sol
@@ -0,0 +1,5 @@
+contract A { constructor(uint) public { } }
+contract B is A(2) { constructor() public { } }
+contract C is B { constructor() A(3) public { } }
+// ----
+// Warning: Base constructor arguments given twice.
diff --git a/test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/ancestor_V050.sol b/test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/ancestor_V050.sol
new file mode 100644
index 00000000..6616c9a9
--- /dev/null
+++ b/test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/ancestor_V050.sol
@@ -0,0 +1,7 @@
+pragma experimental "v0.5.0";
+
+contract A { constructor(uint) public { } }
+contract B is A(2) { constructor() public { } }
+contract C is B { constructor() A(3) public { } }
+// ----
+// DeclarationError: Base constructor arguments given twice.
diff --git a/test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/base.sol b/test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/base.sol
new file mode 100644
index 00000000..1fb504fe
--- /dev/null
+++ b/test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/base.sol
@@ -0,0 +1,4 @@
+contract A { constructor(uint) public { } }
+contract B is A(2) { constructor() A(3) public { } }
+// ----
+// Warning: Base constructor arguments given twice.
diff --git a/test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/base_V050.sol b/test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/base_V050.sol
new file mode 100644
index 00000000..96eb1bb1
--- /dev/null
+++ b/test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/base_V050.sol
@@ -0,0 +1,6 @@
+pragma experimental "v0.5.0";
+
+contract A { constructor(uint) public { } }
+contract B is A(2) { constructor() A(3) public { } }
+// ----
+// DeclarationError: Base constructor arguments given twice.
diff --git a/test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/base_multi.sol b/test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/base_multi.sol
new file mode 100644
index 00000000..db9ffc85
--- /dev/null
+++ b/test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/base_multi.sol
@@ -0,0 +1,7 @@
+contract C { constructor(uint) public {} }
+contract A is C(2) {}
+contract B is C(2) {}
+contract D is A, B { constructor() C(3) public {} }
+// ----
+// Warning: Base constructor arguments given twice.
+// Warning: Base constructor arguments given twice.
diff --git a/test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/base_multi_no_constructor.sol b/test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/base_multi_no_constructor.sol
new file mode 100644
index 00000000..fe280ad5
--- /dev/null
+++ b/test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/base_multi_no_constructor.sol
@@ -0,0 +1,6 @@
+contract C { constructor(uint) public {} }
+contract A is C(2) {}
+contract B is C(2) {}
+contract D is A, B {}
+// ----
+// Warning: Base constructor arguments given twice.
diff --git a/test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/base_multi_no_constructor_modifier_style.sol b/test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/base_multi_no_constructor_modifier_style.sol
new file mode 100644
index 00000000..ea85aae7
--- /dev/null
+++ b/test/libsolidity/syntaxTests/inheritance/duplicated_constructor_call/base_multi_no_constructor_modifier_style.sol
@@ -0,0 +1,6 @@
+contract C { constructor(uint) public {} }
+contract A is C { constructor() C(2) public {} }
+contract B is C { constructor() C(2) public {} }
+contract D is A, B { }
+// ----
+// Warning: Base constructor arguments given twice.