aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/control-structures.rst4
-rw-r--r--docs/frequently-asked-questions.rst8
-rw-r--r--libsolidity/analysis/ConstantEvaluator.cpp4
-rw-r--r--libsolidity/analysis/SemVerHandler.cpp4
-rw-r--r--libsolidity/analysis/SemVerHandler.h8
-rw-r--r--libsolidity/analysis/SyntaxChecker.cpp2
-rw-r--r--libsolidity/analysis/TypeChecker.cpp14
-rw-r--r--libsolidity/ast/AST.h58
-rw-r--r--libsolidity/ast/ASTJsonConverter.cpp12
-rw-r--r--libsolidity/ast/ASTJsonConverter.h2
-rw-r--r--libsolidity/ast/ASTPrinter.cpp8
-rw-r--r--libsolidity/ast/Types.cpp64
-rw-r--r--libsolidity/ast/Types.h58
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp40
-rw-r--r--libsolidity/codegen/ExpressionCompiler.h12
-rw-r--r--libsolidity/formal/SMTChecker.cpp127
-rw-r--r--libsolidity/formal/SMTChecker.h16
-rw-r--r--libsolidity/formal/SSAVariable.cpp2
-rw-r--r--libsolidity/formal/SSAVariable.h10
-rw-r--r--libsolidity/formal/SymbolicAddressVariable.cpp11
-rw-r--r--libsolidity/formal/SymbolicAddressVariable.h1
-rw-r--r--libsolidity/formal/SymbolicBoolVariable.cpp6
-rw-r--r--libsolidity/formal/SymbolicBoolVariable.h2
-rw-r--r--libsolidity/formal/SymbolicIntVariable.cpp8
-rw-r--r--libsolidity/formal/SymbolicIntVariable.h2
-rw-r--r--libsolidity/formal/SymbolicTypes.cpp15
-rw-r--r--libsolidity/formal/SymbolicVariable.cpp6
-rw-r--r--libsolidity/formal/SymbolicVariable.h11
-rw-r--r--libsolidity/parsing/Parser.cpp80
-rw-r--r--libsolidity/parsing/ParserBase.cpp20
-rw-r--r--libsolidity/parsing/ParserBase.h8
-rw-r--r--libsolidity/parsing/Scanner.cpp32
-rw-r--r--libsolidity/parsing/Scanner.h30
-rw-r--r--libsolidity/parsing/Token.cpp98
-rw-r--r--libsolidity/parsing/Token.h145
-rw-r--r--libyul/optimiser/RedundantAssignEliminator.cpp193
-rw-r--r--libyul/optimiser/RedundantAssignEliminator.h185
-rw-r--r--libyul/optimiser/Suite.cpp113
-rw-r--r--libyul/optimiser/Suite.h55
-rwxr-xr-xtest/cmdlineTests.sh2
-rw-r--r--test/compilationTests/MultiSigWallet/MultiSigWallet.sol2
-rw-r--r--test/compilationTests/MultiSigWallet/MultiSigWalletFactory.sol2
-rw-r--r--test/compilationTests/MultiSigWallet/MultiSigWalletWithDailyLimit.sol2
-rw-r--r--test/compilationTests/MultiSigWallet/MultiSigWalletWithDailyLimitFactory.sol2
-rw-r--r--test/compilationTests/MultiSigWallet/TestToken.sol2
-rw-r--r--test/compilationTests/corion/announcementTypes.sol2
-rw-r--r--test/compilationTests/corion/ico.sol2
-rw-r--r--test/compilationTests/corion/module.sol2
-rw-r--r--test/compilationTests/corion/moduleHandler.sol2
-rw-r--r--test/compilationTests/corion/multiOwner.sol2
-rw-r--r--test/compilationTests/corion/owned.sol2
-rw-r--r--test/compilationTests/corion/premium.sol2
-rw-r--r--test/compilationTests/corion/provider.sol2
-rw-r--r--test/compilationTests/corion/publisher.sol2
-rw-r--r--test/compilationTests/corion/safeMath.sol2
-rw-r--r--test/compilationTests/corion/schelling.sol2
-rw-r--r--test/compilationTests/corion/token.sol2
-rw-r--r--test/compilationTests/corion/tokenDB.sol2
-rw-r--r--test/compilationTests/gnosis/Events/CategoricalEvent.sol2
-rw-r--r--test/compilationTests/gnosis/Events/Event.sol2
-rw-r--r--test/compilationTests/gnosis/Events/EventFactory.sol2
-rw-r--r--test/compilationTests/gnosis/Events/ScalarEvent.sol2
-rw-r--r--test/compilationTests/gnosis/MarketMakers/LMSRMarketMaker.sol2
-rw-r--r--test/compilationTests/gnosis/MarketMakers/MarketMaker.sol2
-rw-r--r--test/compilationTests/gnosis/Markets/Campaign.sol2
-rw-r--r--test/compilationTests/gnosis/Markets/CampaignFactory.sol2
-rw-r--r--test/compilationTests/gnosis/Markets/Market.sol2
-rw-r--r--test/compilationTests/gnosis/Markets/MarketFactory.sol2
-rw-r--r--test/compilationTests/gnosis/Markets/StandardMarket.sol2
-rw-r--r--test/compilationTests/gnosis/Markets/StandardMarketFactory.sol2
-rw-r--r--test/compilationTests/gnosis/Migrations.sol2
-rw-r--r--test/compilationTests/gnosis/Oracles/CentralizedOracle.sol2
-rw-r--r--test/compilationTests/gnosis/Oracles/CentralizedOracleFactory.sol2
-rw-r--r--test/compilationTests/gnosis/Oracles/DifficultyOracle.sol2
-rw-r--r--test/compilationTests/gnosis/Oracles/DifficultyOracleFactory.sol2
-rw-r--r--test/compilationTests/gnosis/Oracles/FutarchyOracle.sol2
-rw-r--r--test/compilationTests/gnosis/Oracles/FutarchyOracleFactory.sol2
-rw-r--r--test/compilationTests/gnosis/Oracles/MajorityOracle.sol2
-rw-r--r--test/compilationTests/gnosis/Oracles/MajorityOracleFactory.sol2
-rw-r--r--test/compilationTests/gnosis/Oracles/Oracle.sol2
-rw-r--r--test/compilationTests/gnosis/Oracles/SignedMessageOracle.sol2
-rw-r--r--test/compilationTests/gnosis/Oracles/SignedMessageOracleFactory.sol2
-rw-r--r--test/compilationTests/gnosis/Oracles/UltimateOracle.sol2
-rw-r--r--test/compilationTests/gnosis/Oracles/UltimateOracleFactory.sol2
-rw-r--r--test/compilationTests/gnosis/Tokens/EtherToken.sol2
-rw-r--r--test/compilationTests/gnosis/Tokens/OutcomeToken.sol2
-rw-r--r--test/compilationTests/gnosis/Tokens/StandardToken.sol2
-rw-r--r--test/compilationTests/gnosis/Tokens/Token.sol2
-rw-r--r--test/compilationTests/gnosis/Utils/Math.sol2
-rw-r--r--test/compilationTests/milestonetracker/MilestoneTracker.sol2
-rw-r--r--test/compilationTests/milestonetracker/RLP.sol2
-rw-r--r--test/compilationTests/stringutils/strings.sol2
-rw-r--r--test/compilationTests/zeppelin/Bounty.sol78
-rw-r--r--test/compilationTests/zeppelin/DayLimit.sol75
-rw-r--r--test/compilationTests/zeppelin/LICENSE22
-rw-r--r--test/compilationTests/zeppelin/LimitBalance.sol33
-rw-r--r--test/compilationTests/zeppelin/MultisigWallet.sol125
-rw-r--r--test/compilationTests/zeppelin/README.md3
-rw-r--r--test/compilationTests/zeppelin/ReentrancyGuard.sol34
-rw-r--r--test/compilationTests/zeppelin/crowdsale/CappedCrowdsale.sol33
-rw-r--r--test/compilationTests/zeppelin/crowdsale/Crowdsale.sol108
-rw-r--r--test/compilationTests/zeppelin/crowdsale/FinalizableCrowdsale.sol39
-rw-r--r--test/compilationTests/zeppelin/crowdsale/RefundVault.sol56
-rw-r--r--test/compilationTests/zeppelin/crowdsale/RefundableCrowdsale.sol59
-rw-r--r--test/compilationTests/zeppelin/lifecycle/Destructible.sol25
-rw-r--r--test/compilationTests/zeppelin/lifecycle/Migrations.sol21
-rw-r--r--test/compilationTests/zeppelin/lifecycle/Pausable.sol51
-rw-r--r--test/compilationTests/zeppelin/lifecycle/TokenDestructible.sol36
-rw-r--r--test/compilationTests/zeppelin/math/Math.sol24
-rw-r--r--test/compilationTests/zeppelin/math/SafeMath.sol32
-rw-r--r--test/compilationTests/zeppelin/ownership/Claimable.sol40
-rw-r--r--test/compilationTests/zeppelin/ownership/Contactable.sol21
-rw-r--r--test/compilationTests/zeppelin/ownership/DelayedClaimable.sol43
-rw-r--r--test/compilationTests/zeppelin/ownership/HasNoContracts.sol21
-rw-r--r--test/compilationTests/zeppelin/ownership/HasNoEther.sol44
-rw-r--r--test/compilationTests/zeppelin/ownership/HasNoTokens.sol34
-rw-r--r--test/compilationTests/zeppelin/ownership/Multisig.sol28
-rw-r--r--test/compilationTests/zeppelin/ownership/NoOwner.sol14
-rw-r--r--test/compilationTests/zeppelin/ownership/Ownable.sol43
-rw-r--r--test/compilationTests/zeppelin/ownership/Shareable.sol189
-rw-r--r--test/compilationTests/zeppelin/payment/PullPayment.sol50
-rw-r--r--test/compilationTests/zeppelin/token/BasicToken.sol37
-rw-r--r--test/compilationTests/zeppelin/token/ERC20.sol16
-rw-r--r--test/compilationTests/zeppelin/token/ERC20Basic.sol14
-rw-r--r--test/compilationTests/zeppelin/token/LimitedTransferToken.sol57
-rw-r--r--test/compilationTests/zeppelin/token/MintableToken.sol50
-rw-r--r--test/compilationTests/zeppelin/token/PausableToken.sol21
-rw-r--r--test/compilationTests/zeppelin/token/SimpleToken.sol28
-rw-r--r--test/compilationTests/zeppelin/token/StandardToken.sol65
-rw-r--r--test/compilationTests/zeppelin/token/TokenTimelock.sol41
-rw-r--r--test/compilationTests/zeppelin/token/VestedToken.sol248
-rw-r--r--test/libsolidity/SMTChecker.cpp17
-rw-r--r--test/libsolidity/SemVerMatcher.cpp6
-rw-r--r--test/libsolidity/smtCheckerTests/special/blockhash.sol14
-rw-r--r--test/libsolidity/smtCheckerTests/special/difficulty.sol10
-rw-r--r--test/libsolidity/smtCheckerTests/special/gasleft.sol14
-rw-r--r--test/libsolidity/smtCheckerTests/special/many.sol25
-rw-r--r--test/libsolidity/smtCheckerTests/special/msg_data.sol14
-rw-r--r--test/libsolidity/smtCheckerTests/special/msg_sender_1.sol10
-rw-r--r--test/libsolidity/smtCheckerTests/special/msg_sender_2.sol14
-rw-r--r--test/libsolidity/smtCheckerTests/special/msg_sender_fail_1.sol13
-rw-r--r--test/libsolidity/smtCheckerTests/special/msg_sig.sol14
-rw-r--r--test/libyul/YulOptimizerTest.cpp16
-rw-r--r--test/libyul/yulOptimizerTests/fullSuite/medium.yul26
-rw-r--r--test/libyul/yulOptimizerTests/redundantAssignEliminator/for.yul26
-rw-r--r--test/libyul/yulOptimizerTests/redundantAssignEliminator/for_branch.yul31
-rw-r--r--test/libyul/yulOptimizerTests/redundantAssignEliminator/for_rerun.yul27
-rw-r--r--test/libyul/yulOptimizerTests/redundantAssignEliminator/function.yul23
-rw-r--r--test/libyul/yulOptimizerTests/redundantAssignEliminator/if.yul24
-rw-r--r--test/libyul/yulOptimizerTests/redundantAssignEliminator/if_overwrite_all_branches.yul24
-rw-r--r--test/libyul/yulOptimizerTests/redundantAssignEliminator/if_used_in_one_branch.yul25
-rw-r--r--test/libyul/yulOptimizerTests/redundantAssignEliminator/multi_assign.yul19
-rw-r--r--test/libyul/yulOptimizerTests/redundantAssignEliminator/multivar.yul15
-rw-r--r--test/libyul/yulOptimizerTests/redundantAssignEliminator/non_movable.yul11
-rw-r--r--test/libyul/yulOptimizerTests/redundantAssignEliminator/scopes.yul16
-rw-r--r--test/libyul/yulOptimizerTests/redundantAssignEliminator/simple.yul10
-rw-r--r--test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_in_all.yul22
-rw-r--r--test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_in_one.yul19
-rw-r--r--test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_use_combination.yul23
-rw-r--r--test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_unused.yul16
-rw-r--r--test/libyul/yulOptimizerTests/ssaPlusCleanup/control_structures.yul35
-rw-r--r--test/libyul/yulOptimizerTests/ssaPlusCleanup/multi_reassign.yul17
-rw-r--r--test/libyul/yulOptimizerTests/ssaPlusCleanup/multi_reassign_with_use.yul17
163 files changed, 1671 insertions, 2460 deletions
diff --git a/docs/control-structures.rst b/docs/control-structures.rst
index c2d60df1..9da29d14 100644
--- a/docs/control-structures.rst
+++ b/docs/control-structures.rst
@@ -126,6 +126,10 @@ actual contract has not been created yet.
Functions of other contracts have to be called externally. For an external call,
all function arguments have to be copied to memory.
+.. note::
+ A function call from one contract to another does not create its own transaction,
+ it is a message call as part of the overall transaction.
+
When calling functions of other contracts, the amount of Wei sent with the call and
the gas can be specified with special options ``.value()`` and ``.gas()``, respectively::
diff --git a/docs/frequently-asked-questions.rst b/docs/frequently-asked-questions.rst
index 0f8b34f8..3e9a6aca 100644
--- a/docs/frequently-asked-questions.rst
+++ b/docs/frequently-asked-questions.rst
@@ -213,14 +213,6 @@ It gets added to the total balance of the contract, just like when you send ethe
You can only send ether along to a function that has the ``payable`` modifier,
otherwise an exception is thrown.
-Is it possible to get a tx receipt for a transaction executed contract-to-contract?
-===================================================================================
-
-No, a function call from one contract to another does not create its own transaction,
-you have to look in the overall transaction. This is also the reason why several
-block explorer do not show Ether sent between contracts correctly.
-
-
******************
Advanced Questions
******************
diff --git a/libsolidity/analysis/ConstantEvaluator.cpp b/libsolidity/analysis/ConstantEvaluator.cpp
index 8659bbfd..f9b00927 100644
--- a/libsolidity/analysis/ConstantEvaluator.cpp
+++ b/libsolidity/analysis/ConstantEvaluator.cpp
@@ -46,7 +46,7 @@ void ConstantEvaluator::endVisit(BinaryOperation const& _operation)
m_errorReporter.fatalTypeError(
_operation.location(),
"Operator " +
- string(Token::toString(_operation.getOperator())) +
+ string(TokenTraits::toString(_operation.getOperator())) +
" not compatible with types " +
left->toString() +
" and " +
@@ -54,7 +54,7 @@ void ConstantEvaluator::endVisit(BinaryOperation const& _operation)
);
setType(
_operation,
- Token::isCompareOp(_operation.getOperator()) ?
+ TokenTraits::isCompareOp(_operation.getOperator()) ?
make_shared<BoolType>() :
commonType
);
diff --git a/libsolidity/analysis/SemVerHandler.cpp b/libsolidity/analysis/SemVerHandler.cpp
index 29f6d5de..64fa17b3 100644
--- a/libsolidity/analysis/SemVerHandler.cpp
+++ b/libsolidity/analysis/SemVerHandler.cpp
@@ -199,7 +199,7 @@ void SemVerMatchExpressionParser::parseMatchExpression()
SemVerMatchExpression::MatchComponent SemVerMatchExpressionParser::parseMatchComponent()
{
SemVerMatchExpression::MatchComponent component;
- Token::Value token = currentToken();
+ Token token = currentToken();
switch (token)
{
@@ -280,7 +280,7 @@ char SemVerMatchExpressionParser::nextChar()
return currentChar();
}
-Token::Value SemVerMatchExpressionParser::currentToken() const
+Token SemVerMatchExpressionParser::currentToken() const
{
if (m_pos < m_tokens.size())
return m_tokens[m_pos];
diff --git a/libsolidity/analysis/SemVerHandler.h b/libsolidity/analysis/SemVerHandler.h
index 76b70c5b..03a557c5 100644
--- a/libsolidity/analysis/SemVerHandler.h
+++ b/libsolidity/analysis/SemVerHandler.h
@@ -61,7 +61,7 @@ struct SemVerMatchExpression
struct MatchComponent
{
/// Prefix from < > <= >= ~ ^
- Token::Value prefix = Token::Illegal;
+ Token prefix = Token::Illegal;
/// Version, where unsigned(-1) in major, minor or patch denotes '*', 'x' or 'X'
SemVerVersion version;
/// Whether we have 1, 1.2 or 1.2.4
@@ -81,7 +81,7 @@ struct SemVerMatchExpression
class SemVerMatchExpressionParser
{
public:
- SemVerMatchExpressionParser(std::vector<Token::Value> const& _tokens, std::vector<std::string> const& _literals):
+ SemVerMatchExpressionParser(std::vector<Token> const& _tokens, std::vector<std::string> const& _literals):
m_tokens(_tokens), m_literals(_literals)
{}
SemVerMatchExpression parse();
@@ -95,10 +95,10 @@ private:
char currentChar() const;
char nextChar();
- Token::Value currentToken() const;
+ Token currentToken() const;
void nextToken();
- std::vector<Token::Value> m_tokens;
+ std::vector<Token> m_tokens;
std::vector<std::string> m_literals;
unsigned m_pos = 0;
diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp
index ab544388..3f9f8373 100644
--- a/libsolidity/analysis/SyntaxChecker.cpp
+++ b/libsolidity/analysis/SyntaxChecker.cpp
@@ -106,7 +106,7 @@ bool SyntaxChecker::visit(PragmaDirective const& _pragma)
}
else if (_pragma.literals()[0] == "solidity")
{
- vector<Token::Value> tokens(_pragma.tokens().begin() + 1, _pragma.tokens().end());
+ vector<Token> tokens(_pragma.tokens().begin() + 1, _pragma.tokens().end());
vector<string> literals(_pragma.literals().begin() + 1, _pragma.literals().end());
SemVerMatchExpressionParser parser(tokens, literals);
auto matchExpression = parser.parse();
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index 3830935f..3774cf86 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -1499,14 +1499,14 @@ bool TypeChecker::visit(Assignment const& _assignment)
// compound assignment
_assignment.rightHandSide().accept(*this);
TypePointer resultType = t->binaryOperatorResult(
- Token::AssignmentToBinaryOp(_assignment.assignmentOperator()),
+ TokenTraits::AssignmentToBinaryOp(_assignment.assignmentOperator()),
type(_assignment.rightHandSide())
);
if (!resultType || *resultType != *t)
m_errorReporter.typeError(
_assignment.location(),
"Operator " +
- string(Token::toString(_assignment.assignmentOperator())) +
+ string(TokenTraits::toString(_assignment.assignmentOperator())) +
" not compatible with types " +
t->toString() +
" and " +
@@ -1607,8 +1607,8 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
bool TypeChecker::visit(UnaryOperation const& _operation)
{
// Inc, Dec, Add, Sub, Not, BitNot, Delete
- Token::Value op = _operation.getOperator();
- bool const modifying = (op == Token::Value::Inc || op == Token::Value::Dec || op == Token::Value::Delete);
+ Token op = _operation.getOperator();
+ bool const modifying = (op == Token::Inc || op == Token::Dec || op == Token::Delete);
if (modifying)
requireLValue(_operation.subExpression());
else
@@ -1620,7 +1620,7 @@ bool TypeChecker::visit(UnaryOperation const& _operation)
m_errorReporter.typeError(
_operation.location(),
"Unary operator " +
- string(Token::toString(op)) +
+ string(TokenTraits::toString(op)) +
" cannot be applied to type " +
subExprType->toString()
);
@@ -1641,7 +1641,7 @@ void TypeChecker::endVisit(BinaryOperation const& _operation)
m_errorReporter.typeError(
_operation.location(),
"Operator " +
- string(Token::toString(_operation.getOperator())) +
+ string(TokenTraits::toString(_operation.getOperator())) +
" not compatible with types " +
leftType->toString() +
" and " +
@@ -1651,7 +1651,7 @@ void TypeChecker::endVisit(BinaryOperation const& _operation)
}
_operation.annotation().commonType = commonType;
_operation.annotation().type =
- Token::isCompareOp(_operation.getOperator()) ?
+ TokenTraits::isCompareOp(_operation.getOperator()) ?
make_shared<BoolType>() :
commonType;
_operation.annotation().isPure =
diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h
index b84f9730..d819402e 100644
--- a/libsolidity/ast/AST.h
+++ b/libsolidity/ast/AST.h
@@ -237,7 +237,7 @@ class PragmaDirective: public ASTNode
public:
PragmaDirective(
SourceLocation const& _location,
- std::vector<Token::Value> const& _tokens,
+ std::vector<Token> const& _tokens,
std::vector<ASTString> const& _literals
): ASTNode(_location), m_tokens(_tokens), m_literals(_literals)
{}
@@ -245,13 +245,13 @@ public:
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- std::vector<Token::Value> const& tokens() const { return m_tokens; }
+ std::vector<Token> const& tokens() const { return m_tokens; }
std::vector<ASTString> const& literals() const { return m_literals; }
private:
/// Sequence of tokens following the "pragma" keyword.
- std::vector<Token::Value> m_tokens;
+ std::vector<Token> m_tokens;
/// Sequence of literals following the "pragma" keyword.
std::vector<ASTString> m_literals;
};
@@ -1379,7 +1379,7 @@ public:
Assignment(
SourceLocation const& _location,
ASTPointer<Expression> const& _leftHandSide,
- Token::Value _assignmentOperator,
+ Token _assignmentOperator,
ASTPointer<Expression> const& _rightHandSide
):
Expression(_location),
@@ -1387,18 +1387,18 @@ public:
m_assigmentOperator(_assignmentOperator),
m_rightHandSide(_rightHandSide)
{
- solAssert(Token::isAssignmentOp(_assignmentOperator), "");
+ solAssert(TokenTraits::isAssignmentOp(_assignmentOperator), "");
}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
Expression const& leftHandSide() const { return *m_leftHandSide; }
- Token::Value assignmentOperator() const { return m_assigmentOperator; }
+ Token assignmentOperator() const { return m_assigmentOperator; }
Expression const& rightHandSide() const { return *m_rightHandSide; }
private:
ASTPointer<Expression> m_leftHandSide;
- Token::Value m_assigmentOperator;
+ Token m_assigmentOperator;
ASTPointer<Expression> m_rightHandSide;
};
@@ -1441,7 +1441,7 @@ class UnaryOperation: public Expression
public:
UnaryOperation(
SourceLocation const& _location,
- Token::Value _operator,
+ Token _operator,
ASTPointer<Expression> const& _subExpression,
bool _isPrefix
):
@@ -1450,17 +1450,17 @@ public:
m_subExpression(_subExpression),
m_isPrefix(_isPrefix)
{
- solAssert(Token::isUnaryOp(_operator), "");
+ solAssert(TokenTraits::isUnaryOp(_operator), "");
}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- Token::Value getOperator() const { return m_operator; }
+ Token getOperator() const { return m_operator; }
bool isPrefixOperation() const { return m_isPrefix; }
Expression const& subExpression() const { return *m_subExpression; }
private:
- Token::Value m_operator;
+ Token m_operator;
ASTPointer<Expression> m_subExpression;
bool m_isPrefix;
};
@@ -1475,25 +1475,25 @@ public:
BinaryOperation(
SourceLocation const& _location,
ASTPointer<Expression> const& _left,
- Token::Value _operator,
+ Token _operator,
ASTPointer<Expression> const& _right
):
Expression(_location), m_left(_left), m_operator(_operator), m_right(_right)
{
- solAssert(Token::isBinaryOp(_operator) || Token::isCompareOp(_operator), "");
+ solAssert(TokenTraits::isBinaryOp(_operator) || TokenTraits::isCompareOp(_operator), "");
}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
Expression const& leftExpression() const { return *m_left; }
Expression const& rightExpression() const { return *m_right; }
- Token::Value getOperator() const { return m_operator; }
+ Token getOperator() const { return m_operator; }
BinaryOperationAnnotation& annotation() const override;
private:
ASTPointer<Expression> m_left;
- Token::Value m_operator;
+ Token m_operator;
ASTPointer<Expression> m_right;
};
@@ -1653,21 +1653,21 @@ class Literal: public PrimaryExpression
public:
enum class SubDenomination
{
- None = Token::Illegal,
- Wei = Token::SubWei,
- Szabo = Token::SubSzabo,
- Finney = Token::SubFinney,
- Ether = Token::SubEther,
- Second = Token::SubSecond,
- Minute = Token::SubMinute,
- Hour = Token::SubHour,
- Day = Token::SubDay,
- Week = Token::SubWeek,
- Year = Token::SubYear
+ None = static_cast<int>(Token::Illegal),
+ Wei = static_cast<int>(Token::SubWei),
+ Szabo = static_cast<int>(Token::SubSzabo),
+ Finney = static_cast<int>(Token::SubFinney),
+ Ether = static_cast<int>(Token::SubEther),
+ Second = static_cast<int>(Token::SubSecond),
+ Minute = static_cast<int>(Token::SubMinute),
+ Hour = static_cast<int>(Token::SubHour),
+ Day = static_cast<int>(Token::SubDay),
+ Week = static_cast<int>(Token::SubWeek),
+ Year = static_cast<int>(Token::SubYear)
};
Literal(
SourceLocation const& _location,
- Token::Value _token,
+ Token _token,
ASTPointer<ASTString> const& _value,
SubDenomination _sub = SubDenomination::None
):
@@ -1675,7 +1675,7 @@ public:
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- Token::Value token() const { return m_token; }
+ Token token() const { return m_token; }
/// @returns the non-parsed value of the literal
ASTString const& value() const { return *m_value; }
@@ -1694,7 +1694,7 @@ public:
std::string getChecksummedAddress() const;
private:
- Token::Value m_token;
+ Token m_token;
ASTPointer<ASTString> m_value;
SubDenomination m_subDenomination;
};
diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp
index 4b282d85..569e5b0e 100644
--- a/libsolidity/ast/ASTJsonConverter.cpp
+++ b/libsolidity/ast/ASTJsonConverter.cpp
@@ -589,7 +589,7 @@ bool ASTJsonConverter::visit(Conditional const& _node)
bool ASTJsonConverter::visit(Assignment const& _node)
{
std::vector<pair<string, Json::Value>> attributes = {
- make_pair("operator", Token::toString(_node.assignmentOperator())),
+ make_pair("operator", TokenTraits::toString(_node.assignmentOperator())),
make_pair("leftHandSide", toJson(_node.leftHandSide())),
make_pair("rightHandSide", toJson(_node.rightHandSide()))
};
@@ -613,7 +613,7 @@ bool ASTJsonConverter::visit(UnaryOperation const& _node)
{
std::vector<pair<string, Json::Value>> attributes = {
make_pair("prefix", _node.isPrefixOperation()),
- make_pair("operator", Token::toString(_node.getOperator())),
+ make_pair("operator", TokenTraits::toString(_node.getOperator())),
make_pair("subExpression", toJson(_node.subExpression()))
};
appendExpressionAttributes(attributes, _node.annotation());
@@ -624,7 +624,7 @@ bool ASTJsonConverter::visit(UnaryOperation const& _node)
bool ASTJsonConverter::visit(BinaryOperation const& _node)
{
std::vector<pair<string, Json::Value>> attributes = {
- make_pair("operator", Token::toString(_node.getOperator())),
+ make_pair("operator", TokenTraits::toString(_node.getOperator())),
make_pair("leftExpression", toJson(_node.leftExpression())),
make_pair("rightExpression", toJson(_node.rightExpression())),
make_pair("commonType", typePointerToJson(_node.annotation().commonType)),
@@ -719,7 +719,7 @@ bool ASTJsonConverter::visit(Literal const& _node)
Json::Value value{_node.value()};
if (!dev::validateUTF8(_node.value()))
value = Json::nullValue;
- Token::Value subdenomination = Token::Value(_node.subDenomination());
+ Token subdenomination = Token(_node.subDenomination());
std::vector<pair<string, Json::Value>> attributes = {
make_pair(m_legacy ? "token" : "kind", literalTokenKind(_node.token())),
make_pair("value", value),
@@ -728,7 +728,7 @@ bool ASTJsonConverter::visit(Literal const& _node)
"subdenomination",
subdenomination == Token::Illegal ?
Json::nullValue :
- Json::Value{Token::toString(subdenomination)}
+ Json::Value{TokenTraits::toString(subdenomination)}
)
};
appendExpressionAttributes(attributes, _node.annotation());
@@ -790,7 +790,7 @@ string ASTJsonConverter::functionCallKind(FunctionCallKind _kind)
}
}
-string ASTJsonConverter::literalTokenKind(Token::Value _token)
+string ASTJsonConverter::literalTokenKind(Token _token)
{
switch (_token)
{
diff --git a/libsolidity/ast/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h
index 29712f3b..8429708c 100644
--- a/libsolidity/ast/ASTJsonConverter.h
+++ b/libsolidity/ast/ASTJsonConverter.h
@@ -134,7 +134,7 @@ private:
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 literalTokenKind(Token _token);
static std::string type(Expression const& _expression);
static std::string type(VariableDeclaration const& _varDecl);
static int nodeId(ASTNode const& _node)
diff --git a/libsolidity/ast/ASTPrinter.cpp b/libsolidity/ast/ASTPrinter.cpp
index 4273f225..255cb9be 100644
--- a/libsolidity/ast/ASTPrinter.cpp
+++ b/libsolidity/ast/ASTPrinter.cpp
@@ -289,7 +289,7 @@ bool ASTPrinter::visit(Conditional const& _node)
bool ASTPrinter::visit(Assignment const& _node)
{
- writeLine(string("Assignment using operator ") + Token::toString(_node.assignmentOperator()));
+ writeLine(string("Assignment using operator ") + TokenTraits::toString(_node.assignmentOperator()));
printType(_node);
printSourcePart(_node);
return goDeeper();
@@ -306,7 +306,7 @@ bool ASTPrinter::visit(TupleExpression const& _node)
bool ASTPrinter::visit(UnaryOperation const& _node)
{
writeLine(string("UnaryOperation (") + (_node.isPrefixOperation() ? "prefix" : "postfix") +
- ") " + Token::toString(_node.getOperator()));
+ ") " + TokenTraits::toString(_node.getOperator()));
printType(_node);
printSourcePart(_node);
return goDeeper();
@@ -314,7 +314,7 @@ bool ASTPrinter::visit(UnaryOperation const& _node)
bool ASTPrinter::visit(BinaryOperation const& _node)
{
- writeLine(string("BinaryOperation using operator ") + Token::toString(_node.getOperator()));
+ writeLine(string("BinaryOperation using operator ") + TokenTraits::toString(_node.getOperator()));
printType(_node);
printSourcePart(_node);
return goDeeper();
@@ -370,7 +370,7 @@ bool ASTPrinter::visit(ElementaryTypeNameExpression const& _node)
bool ASTPrinter::visit(Literal const& _node)
{
- char const* tokenString = Token::toString(_node.token());
+ char const* tokenString = TokenTraits::toString(_node.token());
if (!tokenString)
tokenString = "[no token]";
writeLine(string("Literal, token: ") + tokenString + " value: " + _node.value());
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index 195b2e2d..301687b4 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -268,11 +268,11 @@ string Type::identifier() const
TypePointer Type::fromElementaryTypeName(ElementaryTypeNameToken const& _type)
{
- solAssert(Token::isElementaryTypeName(_type.token()),
+ solAssert(TokenTraits::isElementaryTypeName(_type.token()),
"Expected an elementary type name but got " + _type.toString()
);
- Token::Value token = _type.token();
+ Token token = _type.token();
unsigned m = _type.firstNumber();
unsigned n = _type.secondNumber();
@@ -320,9 +320,9 @@ TypePointer Type::fromElementaryTypeName(string const& _name)
vector<string> nameParts;
boost::split(nameParts, _name, boost::is_any_of(" "));
solAssert(nameParts.size() == 1 || nameParts.size() == 2, "Cannot parse elementary type: " + _name);
- Token::Value token;
+ Token token;
unsigned short firstNum, secondNum;
- tie(token, firstNum, secondNum) = Token::fromIdentifierOrKeyword(nameParts[0]);
+ tie(token, firstNum, secondNum) = TokenTraits::fromIdentifierOrKeyword(nameParts[0]);
auto t = fromElementaryTypeName(ElementaryTypeNameToken(token, firstNum, secondNum));
if (auto* ref = dynamic_cast<ReferenceType const*>(t.get()))
{
@@ -502,16 +502,16 @@ u256 AddressType::literalValue(Literal const* _literal) const
return u256(_literal->valueWithoutUnderscores());
}
-TypePointer AddressType::unaryOperatorResult(Token::Value _operator) const
+TypePointer AddressType::unaryOperatorResult(Token _operator) const
{
return _operator == Token::Delete ? make_shared<TupleType>() : TypePointer();
}
-TypePointer AddressType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
+TypePointer AddressType::binaryOperatorResult(Token _operator, TypePointer const& _other) const
{
// Addresses can only be compared.
- if (!Token::isCompareOp(_operator))
+ if (!TokenTraits::isCompareOp(_operator))
return TypePointer();
return Type::commonType(shared_from_this(), _other);
@@ -545,7 +545,7 @@ MemberList::MemberMap AddressType::nativeMembers(ContractDefinition const*) cons
namespace
{
-bool isValidShiftAndAmountType(Token::Value _operator, Type const& _shiftAmountType)
+bool isValidShiftAndAmountType(Token _operator, Type const& _shiftAmountType)
{
// Disable >>> here.
if (_operator == Token::SHR)
@@ -605,7 +605,7 @@ bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const
_convertTo.category() == Category::FixedPoint;
}
-TypePointer IntegerType::unaryOperatorResult(Token::Value _operator) const
+TypePointer IntegerType::unaryOperatorResult(Token _operator) const
{
// "delete" is ok for all integer types
if (_operator == Token::Delete)
@@ -649,7 +649,7 @@ bigint IntegerType::maxValue() const
return (bigint(1) << m_bits) - 1;
}
-TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
+TypePointer IntegerType::binaryOperatorResult(Token _operator, TypePointer const& _other) const
{
if (
_other->category() != Category::RationalNumber &&
@@ -657,7 +657,7 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe
_other->category() != category()
)
return TypePointer();
- if (Token::isShiftOp(_operator))
+ if (TokenTraits::isShiftOp(_operator))
{
// Shifts are not symmetric with respect to the type
if (isValidShiftAndAmountType(_operator, *_other))
@@ -671,9 +671,9 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe
return TypePointer();
// All integer types can be compared
- if (Token::isCompareOp(_operator))
+ if (TokenTraits::isCompareOp(_operator))
return commonType;
- if (Token::isBooleanOp(_operator))
+ if (TokenTraits::isBooleanOp(_operator))
return TypePointer();
if (auto intType = dynamic_pointer_cast<IntegerType const>(commonType))
{
@@ -720,7 +720,7 @@ bool FixedPointType::isExplicitlyConvertibleTo(Type const& _convertTo) const
return _convertTo.category() == category() || _convertTo.category() == Category::Integer;
}
-TypePointer FixedPointType::unaryOperatorResult(Token::Value _operator) const
+TypePointer FixedPointType::unaryOperatorResult(Token _operator) const
{
switch(_operator)
{
@@ -769,7 +769,7 @@ bigint FixedPointType::minIntegerValue() const
return bigint(0);
}
-TypePointer FixedPointType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
+TypePointer FixedPointType::binaryOperatorResult(Token _operator, TypePointer const& _other) const
{
auto commonType = Type::commonType(shared_from_this(), _other);
@@ -777,9 +777,9 @@ TypePointer FixedPointType::binaryOperatorResult(Token::Value _operator, TypePoi
return TypePointer();
// All fixed types can be compared
- if (Token::isCompareOp(_operator))
+ if (TokenTraits::isCompareOp(_operator))
return commonType;
- if (Token::isBitOp(_operator) || Token::isBooleanOp(_operator) || _operator == Token::Exp)
+ if (TokenTraits::isBitOp(_operator) || TokenTraits::isBooleanOp(_operator) || _operator == Token::Exp)
return TypePointer();
return commonType;
}
@@ -1006,7 +1006,7 @@ bool RationalNumberType::isExplicitlyConvertibleTo(Type const& _convertTo) const
return false;
}
-TypePointer RationalNumberType::unaryOperatorResult(Token::Value _operator) const
+TypePointer RationalNumberType::unaryOperatorResult(Token _operator) const
{
rational value;
switch (_operator)
@@ -1030,7 +1030,7 @@ TypePointer RationalNumberType::unaryOperatorResult(Token::Value _operator) cons
return make_shared<RationalNumberType>(value);
}
-TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
+TypePointer RationalNumberType::binaryOperatorResult(Token _operator, TypePointer const& _other) const
{
if (_other->category() == Category::Integer || _other->category() == Category::FixedPoint)
{
@@ -1043,7 +1043,7 @@ TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, Typ
return TypePointer();
RationalNumberType const& other = dynamic_cast<RationalNumberType const&>(*_other);
- if (Token::isCompareOp(_operator))
+ if (TokenTraits::isCompareOp(_operator))
{
// Since we do not have a "BoolConstantType", we have to do the actual comparison
// at runtime and convert to mobile typse first. Such a comparison is not a very common
@@ -1423,7 +1423,7 @@ bool FixedBytesType::isExplicitlyConvertibleTo(Type const& _convertTo) const
_convertTo.category() == category();
}
-TypePointer FixedBytesType::unaryOperatorResult(Token::Value _operator) const
+TypePointer FixedBytesType::unaryOperatorResult(Token _operator) const
{
// "delete" and "~" is okay for FixedBytesType
if (_operator == Token::Delete)
@@ -1434,9 +1434,9 @@ TypePointer FixedBytesType::unaryOperatorResult(Token::Value _operator) const
return TypePointer();
}
-TypePointer FixedBytesType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
+TypePointer FixedBytesType::binaryOperatorResult(Token _operator, TypePointer const& _other) const
{
- if (Token::isShiftOp(_operator))
+ if (TokenTraits::isShiftOp(_operator))
{
if (isValidShiftAndAmountType(_operator, *_other))
return shared_from_this();
@@ -1449,7 +1449,7 @@ TypePointer FixedBytesType::binaryOperatorResult(Token::Value _operator, TypePoi
return TypePointer();
// FixedBytes can be compared and have bitwise operators applied to them
- if (Token::isCompareOp(_operator) || Token::isBitOp(_operator))
+ if (TokenTraits::isCompareOp(_operator) || TokenTraits::isBitOp(_operator))
return commonType;
return TypePointer();
@@ -1484,14 +1484,14 @@ u256 BoolType::literalValue(Literal const* _literal) const
solAssert(false, "Bool type constructed from non-boolean literal.");
}
-TypePointer BoolType::unaryOperatorResult(Token::Value _operator) const
+TypePointer BoolType::unaryOperatorResult(Token _operator) const
{
if (_operator == Token::Delete)
return make_shared<TupleType>();
return (_operator == Token::Not) ? shared_from_this() : TypePointer();
}
-TypePointer BoolType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
+TypePointer BoolType::binaryOperatorResult(Token _operator, TypePointer const& _other) const
{
if (category() != _other->category())
return TypePointer();
@@ -1531,14 +1531,14 @@ bool ContractType::isPayable() const
return fallbackFunction && fallbackFunction->isPayable();
}
-TypePointer ContractType::unaryOperatorResult(Token::Value _operator) const
+TypePointer ContractType::unaryOperatorResult(Token _operator) const
{
if (isSuper())
return TypePointer{};
return _operator == Token::Delete ? make_shared<TupleType>() : TypePointer();
}
-TypePointer ReferenceType::unaryOperatorResult(Token::Value _operator) const
+TypePointer ReferenceType::unaryOperatorResult(Token _operator) const
{
if (_operator != Token::Delete)
return TypePointer();
@@ -2237,7 +2237,7 @@ bool StructType::recursive() const
return *m_recursive;
}
-TypePointer EnumType::unaryOperatorResult(Token::Value _operator) const
+TypePointer EnumType::unaryOperatorResult(Token _operator) const
{
return _operator == Token::Delete ? make_shared<TupleType>() : TypePointer();
}
@@ -2668,14 +2668,14 @@ bool FunctionType::isImplicitlyConvertibleTo(Type const& _convertTo) const
return true;
}
-TypePointer FunctionType::unaryOperatorResult(Token::Value _operator) const
+TypePointer FunctionType::unaryOperatorResult(Token _operator) const
{
- if (_operator == Token::Value::Delete)
+ if (_operator == Token::Delete)
return make_shared<TupleType>();
return TypePointer();
}
-TypePointer FunctionType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
+TypePointer FunctionType::binaryOperatorResult(Token _operator, TypePointer const& _other) const
{
if (_other->category() != category() || !(_operator == Token::Equal || _operator == Token::NotEqual))
return TypePointer();
diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h
index 0f3373a1..b764717f 100644
--- a/libsolidity/ast/Types.h
+++ b/libsolidity/ast/Types.h
@@ -188,13 +188,13 @@ public:
/// @returns the resulting type of applying the given unary operator or an empty pointer if
/// this is not possible.
/// The default implementation does not allow any unary operator.
- virtual TypePointer unaryOperatorResult(Token::Value) const { return TypePointer(); }
+ virtual TypePointer unaryOperatorResult(Token) const { return TypePointer(); }
/// @returns the resulting type of applying the given binary operator or an empty pointer if
/// this is not possible.
/// The default implementation allows comparison operators if a common type exists
- virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
+ virtual TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const
{
- return Token::isCompareOp(_operator) ? commonType(shared_from_this(), _other) : TypePointer();
+ return TokenTraits::isCompareOp(_operator) ? commonType(shared_from_this(), _other) : TypePointer();
}
virtual bool operator==(Type const& _other) const { return category() == _other.category(); }
@@ -329,8 +329,8 @@ public:
virtual std::string richIdentifier() const override;
virtual bool isImplicitlyConvertibleTo(Type const& _other) const override;
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
- virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
- virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override;
+ virtual TypePointer unaryOperatorResult(Token _operator) const override;
+ virtual TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
virtual bool operator==(Type const& _other) const override;
@@ -372,8 +372,8 @@ public:
virtual std::string richIdentifier() const override;
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
- virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
- virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override;
+ virtual TypePointer unaryOperatorResult(Token _operator) const override;
+ virtual TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
virtual bool operator==(Type const& _other) const override;
@@ -414,8 +414,8 @@ public:
virtual std::string richIdentifier() const override;
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
- virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
- virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override;
+ virtual TypePointer unaryOperatorResult(Token _operator) const override;
+ virtual TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
virtual bool operator==(Type const& _other) const override;
@@ -468,8 +468,8 @@ public:
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
- virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
- virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override;
+ virtual TypePointer unaryOperatorResult(Token _operator) const override;
+ virtual TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
virtual std::string richIdentifier() const override;
virtual bool operator==(Type const& _other) const override;
@@ -526,7 +526,7 @@ public:
explicit StringLiteralType(Literal const& _literal);
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
- virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override
+ virtual TypePointer binaryOperatorResult(Token, TypePointer const&) const override
{
return TypePointer();
}
@@ -563,8 +563,8 @@ public:
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual std::string richIdentifier() const override;
virtual bool operator==(Type const& _other) const override;
- virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
- virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override;
+ virtual TypePointer unaryOperatorResult(Token _operator) const override;
+ virtual TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
virtual unsigned calldataEncodedSize(bool _padded) const override { return _padded && m_bytes > 0 ? 32 : m_bytes; }
virtual unsigned storageBytes() const override { return m_bytes; }
@@ -590,8 +590,8 @@ public:
BoolType() {}
virtual Category category() const override { return Category::Bool; }
virtual std::string richIdentifier() const override { return "t_bool"; }
- virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
- virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override;
+ virtual TypePointer unaryOperatorResult(Token _operator) const override;
+ virtual TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
virtual unsigned calldataEncodedSize(bool _padded) const override{ return _padded ? 32 : 1; }
virtual unsigned storageBytes() const override { return 1; }
@@ -613,8 +613,8 @@ public:
explicit ReferenceType(DataLocation _location): m_location(_location) {}
DataLocation location() const { return m_location; }
- virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
- virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override
+ virtual TypePointer unaryOperatorResult(Token _operator) const override;
+ virtual TypePointer binaryOperatorResult(Token, TypePointer const&) const override
{
return TypePointer();
}
@@ -749,7 +749,7 @@ public:
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
/// Contracts can only be explicitly converted to address types and base contracts.
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
- virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
+ virtual TypePointer unaryOperatorResult(Token _operator) const override;
virtual std::string richIdentifier() const override;
virtual bool operator==(Type const& _other) const override;
virtual unsigned calldataEncodedSize(bool _padded ) const override
@@ -865,7 +865,7 @@ class EnumType: public Type
public:
virtual Category category() const override { return Category::Enum; }
explicit EnumType(EnumDefinition const& _enum): m_enum(_enum) {}
- virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
+ virtual TypePointer unaryOperatorResult(Token _operator) const override;
virtual std::string richIdentifier() const override;
virtual bool operator==(Type const& _other) const override;
virtual unsigned calldataEncodedSize(bool _padded) const override
@@ -909,7 +909,7 @@ public:
virtual bool isImplicitlyConvertibleTo(Type const& _other) const override;
virtual std::string richIdentifier() const override;
virtual bool operator==(Type const& _other) const override;
- virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); }
+ virtual TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
virtual std::string toString(bool) const override;
virtual bool canBeStored() const override { return false; }
virtual u256 storageSize() const override;
@@ -1056,8 +1056,8 @@ public:
virtual bool operator==(Type const& _other) const override;
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
- virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
- virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override;
+ virtual TypePointer unaryOperatorResult(Token _operator) const override;
+ virtual TypePointer binaryOperatorResult(Token, TypePointer const&) const override;
virtual std::string canonicalName() const override;
virtual std::string toString(bool _short) const override;
virtual unsigned calldataEncodedSize(bool _padded) const override;
@@ -1187,7 +1187,7 @@ public:
virtual std::string toString(bool _short) const override;
virtual std::string canonicalName() const override;
virtual bool canLiveOutsideStorage() const override { return false; }
- virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); }
+ virtual TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
virtual TypePointer encodingType() const override
{
return std::make_shared<IntegerType>(256);
@@ -1220,7 +1220,7 @@ public:
explicit TypeType(TypePointer const& _actualType): m_actualType(_actualType) {}
TypePointer const& actualType() const { return m_actualType; }
- virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); }
+ virtual TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
virtual std::string richIdentifier() const override;
virtual bool operator==(Type const& _other) const override;
virtual bool canBeStored() const override { return false; }
@@ -1245,7 +1245,7 @@ public:
virtual Category category() const override { return Category::Modifier; }
explicit ModifierType(ModifierDefinition const& _modifier);
- virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); }
+ virtual TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
virtual bool canBeStored() const override { return false; }
virtual u256 storageSize() const override;
virtual bool canLiveOutsideStorage() const override { return false; }
@@ -1271,7 +1271,7 @@ public:
explicit ModuleType(SourceUnit const& _source): m_sourceUnit(_source) {}
- virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); }
+ virtual TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
virtual std::string richIdentifier() const override;
virtual bool operator==(Type const& _other) const override;
virtual bool canBeStored() const override { return false; }
@@ -1298,7 +1298,7 @@ public:
explicit MagicType(Kind _kind): m_kind(_kind) {}
- virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override
+ virtual TypePointer binaryOperatorResult(Token, TypePointer const&) const override
{
return TypePointer();
}
@@ -1331,7 +1331,7 @@ public:
virtual std::string richIdentifier() const override { return "t_inaccessible"; }
virtual bool isImplicitlyConvertibleTo(Type const&) const override { return false; }
virtual bool isExplicitlyConvertibleTo(Type const&) const override { return false; }
- virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); }
+ virtual TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
virtual unsigned calldataEncodedSize(bool _padded) const override { (void)_padded; return 32; }
virtual bool canBeStored() const override { return false; }
virtual bool canLiveOutsideStorage() const override { return false; }
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index 749739ce..63faddd3 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -206,8 +206,8 @@ bool ExpressionCompiler::visit(Conditional const& _condition)
bool ExpressionCompiler::visit(Assignment const& _assignment)
{
CompilerContext::LocationSetter locationSetter(m_context, _assignment);
- Token::Value op = _assignment.assignmentOperator();
- Token::Value binOp = op == Token::Assign ? op : Token::AssignmentToBinaryOp(op);
+ Token op = _assignment.assignmentOperator();
+ Token binOp = op == Token::Assign ? op : TokenTraits::AssignmentToBinaryOp(op);
Type const& leftType = *_assignment.leftHandSide().annotation().type;
if (leftType.category() == Type::Category::Tuple)
{
@@ -223,7 +223,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
// Perform some conversion already. This will convert storage types to memory and literals
// to their actual type, but will not convert e.g. memory to storage.
TypePointer rightIntermediateType;
- if (op != Token::Assign && Token::isShiftOp(binOp))
+ if (op != Token::Assign && TokenTraits::isShiftOp(binOp))
rightIntermediateType = _assignment.rightHandSide().annotation().type->mobileType();
else
rightIntermediateType = _assignment.rightHandSide().annotation().type->closestTemporaryType(
@@ -251,7 +251,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
m_currentLValue->retrieveValue(_assignment.location(), true);
utils().convertType(leftType, leftType, cleanupNeeded);
- if (Token::isShiftOp(binOp))
+ if (TokenTraits::isShiftOp(binOp))
appendShiftOperatorCode(binOp, leftType, *rightIntermediateType);
else
{
@@ -384,7 +384,7 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
m_context << u256(0) << Instruction::SUB;
break;
default:
- solAssert(false, "Invalid unary operator: " + string(Token::toString(_unaryOperation.getOperator())));
+ solAssert(false, "Invalid unary operator: " + string(TokenTraits::toString(_unaryOperation.getOperator())));
}
return false;
}
@@ -396,7 +396,7 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
Expression const& rightExpression = _binaryOperation.rightExpression();
solAssert(!!_binaryOperation.annotation().commonType, "");
TypePointer const& commonType = _binaryOperation.annotation().commonType;
- Token::Value const c_op = _binaryOperation.getOperator();
+ Token const c_op = _binaryOperation.getOperator();
if (c_op == Token::And || c_op == Token::Or) // special case: short-circuiting
appendAndOrOperatorCode(_binaryOperation);
@@ -407,7 +407,7 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
bool cleanupNeeded = cleanupNeededForOp(commonType->category(), c_op);
TypePointer leftTargetType = commonType;
- TypePointer rightTargetType = Token::isShiftOp(c_op) ? rightExpression.annotation().type->mobileType() : commonType;
+ TypePointer rightTargetType = TokenTraits::isShiftOp(c_op) ? rightExpression.annotation().type->mobileType() : commonType;
solAssert(rightTargetType, "");
// for commutative operators, push the literal as late as possible to allow improved optimization
@@ -415,7 +415,7 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
{
return dynamic_cast<Literal const*>(&_e) || _e.annotation().type->category() == Type::Category::RationalNumber;
};
- bool swap = m_optimize && Token::isCommutativeOp(c_op) && isLiteral(rightExpression) && !isLiteral(leftExpression);
+ bool swap = m_optimize && TokenTraits::isCommutativeOp(c_op) && isLiteral(rightExpression) && !isLiteral(leftExpression);
if (swap)
{
leftExpression.accept(*this);
@@ -430,10 +430,10 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
leftExpression.accept(*this);
utils().convertType(*leftExpression.annotation().type, *leftTargetType, cleanupNeeded);
}
- if (Token::isShiftOp(c_op))
+ if (TokenTraits::isShiftOp(c_op))
// shift only cares about the signedness of both sides
appendShiftOperatorCode(c_op, *leftTargetType, *rightTargetType);
- else if (Token::isCompareOp(c_op))
+ else if (TokenTraits::isCompareOp(c_op))
appendCompareOperatorCode(c_op, *commonType);
else
appendOrdinaryBinaryOperatorCode(c_op, *commonType);
@@ -1602,7 +1602,7 @@ void ExpressionCompiler::endVisit(Literal const& _literal)
void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation const& _binaryOperation)
{
- Token::Value const c_op = _binaryOperation.getOperator();
+ Token const c_op = _binaryOperation.getOperator();
solAssert(c_op == Token::Or || c_op == Token::And, "");
_binaryOperation.leftExpression().accept(*this);
@@ -1615,7 +1615,7 @@ void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation const& _binaryO
m_context << endLabel;
}
-void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type const& _type)
+void ExpressionCompiler::appendCompareOperatorCode(Token _operator, Type const& _type)
{
solAssert(_type.sizeOnStack() == 1, "Comparison of multi-slot types.");
if (_operator == Token::Equal || _operator == Token::NotEqual)
@@ -1665,17 +1665,17 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type
}
}
-void ExpressionCompiler::appendOrdinaryBinaryOperatorCode(Token::Value _operator, Type const& _type)
+void ExpressionCompiler::appendOrdinaryBinaryOperatorCode(Token _operator, Type const& _type)
{
- if (Token::isArithmeticOp(_operator))
+ if (TokenTraits::isArithmeticOp(_operator))
appendArithmeticOperatorCode(_operator, _type);
- else if (Token::isBitOp(_operator))
+ else if (TokenTraits::isBitOp(_operator))
appendBitOperatorCode(_operator);
else
solAssert(false, "Unknown binary operator.");
}
-void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Type const& _type)
+void ExpressionCompiler::appendArithmeticOperatorCode(Token _operator, Type const& _type)
{
if (_type.category() == Type::Category::FixedPoint)
solUnimplemented("Not yet implemented - FixedPointType.");
@@ -1715,7 +1715,7 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Ty
}
}
-void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator)
+void ExpressionCompiler::appendBitOperatorCode(Token _operator)
{
switch (_operator)
{
@@ -1733,7 +1733,7 @@ void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator)
}
}
-void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator, Type const& _valueType, Type const& _shiftAmountType)
+void ExpressionCompiler::appendShiftOperatorCode(Token _operator, Type const& _valueType, Type const& _shiftAmountType)
{
// stack: shift_amount value_to_shift
@@ -2140,9 +2140,9 @@ void ExpressionCompiler::setLValueToStorageItem(Expression const& _expression)
setLValue<StorageItem>(_expression, *_expression.annotation().type);
}
-bool ExpressionCompiler::cleanupNeededForOp(Type::Category _type, Token::Value _op)
+bool ExpressionCompiler::cleanupNeededForOp(Type::Category _type, Token _op)
{
- if (Token::isCompareOp(_op) || Token::isShiftOp(_op))
+ if (TokenTraits::isCompareOp(_op) || TokenTraits::isShiftOp(_op))
return true;
else if (_type == Type::Category::Integer && (_op == Token::Div || _op == Token::Mod || _op == Token::Exp))
// We need cleanup for EXP because 0**0 == 1, but 0**0x100 == 0
diff --git a/libsolidity/codegen/ExpressionCompiler.h b/libsolidity/codegen/ExpressionCompiler.h
index cdfa096e..3d8e8682 100644
--- a/libsolidity/codegen/ExpressionCompiler.h
+++ b/libsolidity/codegen/ExpressionCompiler.h
@@ -86,12 +86,12 @@ private:
///@{
///@name Append code for various operator types
void appendAndOrOperatorCode(BinaryOperation const& _binaryOperation);
- void appendCompareOperatorCode(Token::Value _operator, Type const& _type);
- void appendOrdinaryBinaryOperatorCode(Token::Value _operator, Type const& _type);
+ void appendCompareOperatorCode(Token _operator, Type const& _type);
+ void appendOrdinaryBinaryOperatorCode(Token _operator, Type const& _type);
- void appendArithmeticOperatorCode(Token::Value _operator, Type const& _type);
- void appendBitOperatorCode(Token::Value _operator);
- void appendShiftOperatorCode(Token::Value _operator, Type const& _valueType, Type const& _shiftAmountType);
+ void appendArithmeticOperatorCode(Token _operator, Type const& _type);
+ void appendBitOperatorCode(Token _operator);
+ void appendShiftOperatorCode(Token _operator, Type const& _valueType, Type const& _shiftAmountType);
/// @}
/// Appends code to call a function of the given type with the given arguments.
@@ -119,7 +119,7 @@ private:
/// @returns true if the operator applied to the given type requires a cleanup prior to the
/// operation.
- static bool cleanupNeededForOp(Type::Category _type, Token::Value _op);
+ static bool cleanupNeededForOp(Type::Category _type, Token _op);
/// @returns the CompilerUtils object containing the current context.
CompilerUtils utils();
diff --git a/libsolidity/formal/SMTChecker.cpp b/libsolidity/formal/SMTChecker.cpp
index e5648eb3..631a9eee 100644
--- a/libsolidity/formal/SMTChecker.cpp
+++ b/libsolidity/formal/SMTChecker.cpp
@@ -212,7 +212,7 @@ void SMTChecker::endVisit(VariableDeclarationStatement const& _varDecl)
void SMTChecker::endVisit(Assignment const& _assignment)
{
- if (_assignment.assignmentOperator() != Token::Value::Assign)
+ if (_assignment.assignmentOperator() != Token::Assign)
m_errorReporter.warning(
_assignment.location(),
"Assertion checker does not yet implement compound assignment."
@@ -331,11 +331,11 @@ void SMTChecker::endVisit(UnaryOperation const& _op)
void SMTChecker::endVisit(BinaryOperation const& _op)
{
- if (Token::isArithmeticOp(_op.getOperator()))
+ if (TokenTraits::isArithmeticOp(_op.getOperator()))
arithmeticOperation(_op);
- else if (Token::isCompareOp(_op.getOperator()))
+ else if (TokenTraits::isCompareOp(_op.getOperator()))
compareOperation(_op);
- else if (Token::isBooleanOp(_op.getOperator()))
+ else if (TokenTraits::isBooleanOp(_op.getOperator()))
booleanOperation(_op);
else
m_errorReporter.warning(
@@ -363,6 +363,10 @@ void SMTChecker::endVisit(FunctionCall const& _funCall)
visitAssert(_funCall);
else if (funType.kind() == FunctionType::Kind::Require)
visitRequire(_funCall);
+ else if (funType.kind() == FunctionType::Kind::GasLeft)
+ visitGasLeft(_funCall);
+ else if (funType.kind() == FunctionType::Kind::BlockHash)
+ visitBlockHash(_funCall);
else if (funType.kind() == FunctionType::Kind::Internal)
inlineFunctionCall(_funCall);
else
@@ -393,6 +397,27 @@ void SMTChecker::visitRequire(FunctionCall const& _funCall)
addPathImpliedExpression(expr(*args[0]));
}
+void SMTChecker::visitGasLeft(FunctionCall const& _funCall)
+{
+ string gasLeft = "gasleft()";
+ // We increase the variable index since gasleft changes
+ // inside a tx.
+ defineSpecialVariable(gasLeft, _funCall, true);
+ auto const& symbolicVar = m_specialVariables.at(gasLeft);
+ unsigned index = symbolicVar->index();
+ // We set the current value to unknown anyway to add type constraints.
+ symbolicVar->setUnknownValue();
+ if (index > 0)
+ m_interface->addAssertion(symbolicVar->currentValue() <= symbolicVar->valueAtIndex(index - 1));
+}
+
+void SMTChecker::visitBlockHash(FunctionCall const& _funCall)
+{
+ string blockHash = "blockhash()";
+ // TODO Define blockhash as an uninterpreted function
+ defineSpecialVariable(blockHash, _funCall);
+}
+
void SMTChecker::inlineFunctionCall(FunctionCall const& _funCall)
{
FunctionDefinition const* _funDef = nullptr;
@@ -460,7 +485,12 @@ void SMTChecker::endVisit(Identifier const& _identifier)
}
else if (FunctionType const* fun = dynamic_cast<FunctionType const*>(_identifier.annotation().type.get()))
{
- if (fun->kind() == FunctionType::Kind::Assert || fun->kind() == FunctionType::Kind::Require)
+ if (
+ fun->kind() == FunctionType::Kind::Assert ||
+ fun->kind() == FunctionType::Kind::Require ||
+ fun->kind() == FunctionType::Kind::GasLeft ||
+ fun->kind() == FunctionType::Kind::BlockHash
+ )
return;
createExpr(_identifier);
}
@@ -468,6 +498,8 @@ void SMTChecker::endVisit(Identifier const& _identifier)
{
if (VariableDeclaration const* decl = dynamic_cast<VariableDeclaration const*>(_identifier.annotation().referencedDeclaration))
defineExpr(_identifier, currentValue(*decl));
+ else if (_identifier.name() == "now")
+ defineSpecialVariable(_identifier.name(), _identifier);
else
// TODO: handle MagicVariableDeclaration here
m_errorReporter.warning(
@@ -496,7 +528,7 @@ void SMTChecker::endVisit(Literal const& _literal)
void SMTChecker::endVisit(Return const& _return)
{
- if (hasExpr(*_return.expression()))
+ if (knownExpr(*_return.expression()))
{
auto returnParams = m_functionPath.back()->returnParameters();
if (returnParams.size() > 1)
@@ -509,6 +541,54 @@ void SMTChecker::endVisit(Return const& _return)
}
}
+bool SMTChecker::visit(MemberAccess const& _memberAccess)
+{
+ auto const& exprType = _memberAccess.expression().annotation().type;
+ solAssert(exprType, "");
+ if (exprType->category() == Type::Category::Magic)
+ {
+ auto identifier = dynamic_cast<Identifier const*>(&_memberAccess.expression());
+ string accessedName;
+ if (identifier)
+ accessedName = identifier->name();
+ else
+ m_errorReporter.warning(
+ _memberAccess.location(),
+ "Assertion checker does not yet support this expression."
+ );
+ defineSpecialVariable(accessedName + "." + _memberAccess.memberName(), _memberAccess);
+ return false;
+ }
+ else
+ m_errorReporter.warning(
+ _memberAccess.location(),
+ "Assertion checker does not yet support this expression."
+ );
+
+ return true;
+}
+
+void SMTChecker::defineSpecialVariable(string const& _name, Expression const& _expr, bool _increaseIndex)
+{
+ if (!knownSpecialVariable(_name))
+ {
+ auto result = newSymbolicVariable(*_expr.annotation().type, _name, *m_interface);
+ m_specialVariables.emplace(_name, result.second);
+ result.second->setUnknownValue();
+ if (result.first)
+ m_errorReporter.warning(
+ _expr.location(),
+ "Assertion checker does not yet support this special variable."
+ );
+ }
+ else if (_increaseIndex)
+ m_specialVariables.at(_name)->increaseIndex();
+ // The default behavior is not to increase the index since
+ // most of the special values stay the same throughout a tx.
+ defineExpr(_expr, m_specialVariables.at(_name)->currentValue());
+}
+
+
void SMTChecker::arithmeticOperation(BinaryOperation const& _op)
{
switch (_op.getOperator())
@@ -530,7 +610,7 @@ void SMTChecker::arithmeticOperation(BinaryOperation const& _op)
auto const& intType = dynamic_cast<IntegerType const&>(*_op.annotation().commonType);
smt::Expression left(expr(_op.leftExpression()));
smt::Expression right(expr(_op.rightExpression()));
- Token::Value op = _op.getOperator();
+ Token op = _op.getOperator();
smt::Expression value(
op == Token::Add ? left + right :
op == Token::Sub ? left - right :
@@ -564,7 +644,7 @@ void SMTChecker::compareOperation(BinaryOperation const& _op)
{
smt::Expression left(expr(_op.leftExpression()));
smt::Expression right(expr(_op.rightExpression()));
- Token::Value op = _op.getOperator();
+ Token op = _op.getOperator();
shared_ptr<smt::Expression> value;
if (isNumber(_op.annotation().commonType->category()))
{
@@ -681,11 +761,15 @@ void SMTChecker::checkCondition(
expressionNames.push_back(_additionalValueName);
}
for (auto const& var: m_variables)
- if (knownVariable(*var.first))
- {
- expressionsToEvaluate.emplace_back(currentValue(*var.first));
- expressionNames.push_back(var.first->name());
- }
+ {
+ expressionsToEvaluate.emplace_back(currentValue(*var.first));
+ expressionNames.push_back(var.first->name());
+ }
+ for (auto const& var: m_specialVariables)
+ {
+ expressionsToEvaluate.emplace_back(var.second->currentValue());
+ expressionNames.push_back(var.first);
+ }
}
smt::CheckResult result;
vector<string> values;
@@ -910,7 +994,7 @@ void SMTChecker::mergeVariables(vector<VariableDeclaration const*> const& _varia
bool SMTChecker::createVariable(VariableDeclaration const& _varDecl)
{
// This might be the case for multiple calls to the same function.
- if (hasVariable(_varDecl))
+ if (knownVariable(_varDecl))
return true;
auto const& type = _varDecl.type();
solAssert(m_variables.count(&_varDecl) == 0, "");
@@ -927,11 +1011,6 @@ bool SMTChecker::createVariable(VariableDeclaration const& _varDecl)
return true;
}
-string SMTChecker::uniqueSymbol(Expression const& _expr)
-{
- return "expr_" + to_string(_expr.id());
-}
-
bool SMTChecker::knownVariable(VariableDeclaration const& _decl)
{
return m_variables.count(&_decl);
@@ -969,7 +1048,7 @@ void SMTChecker::setUnknownValue(VariableDeclaration const& _decl)
smt::Expression SMTChecker::expr(Expression const& _e)
{
- if (!hasExpr(_e))
+ if (!knownExpr(_e))
{
m_errorReporter.warning(_e.location(), "Internal error: Expression undefined for SMT solver." );
createExpr(_e);
@@ -977,20 +1056,20 @@ smt::Expression SMTChecker::expr(Expression const& _e)
return m_expressions.at(&_e)->currentValue();
}
-bool SMTChecker::hasExpr(Expression const& _e) const
+bool SMTChecker::knownExpr(Expression const& _e) const
{
return m_expressions.count(&_e);
}
-bool SMTChecker::hasVariable(VariableDeclaration const& _var) const
+bool SMTChecker::knownSpecialVariable(string const& _var) const
{
- return m_variables.count(&_var);
+ return m_specialVariables.count(_var);
}
void SMTChecker::createExpr(Expression const& _e)
{
solAssert(_e.annotation().type, "");
- if (hasExpr(_e))
+ if (knownExpr(_e))
m_expressions.at(&_e)->increaseIndex();
else
{
diff --git a/libsolidity/formal/SMTChecker.h b/libsolidity/formal/SMTChecker.h
index f66693d2..95e01708 100644
--- a/libsolidity/formal/SMTChecker.h
+++ b/libsolidity/formal/SMTChecker.h
@@ -66,6 +66,7 @@ private:
virtual void endVisit(Identifier const& _node) override;
virtual void endVisit(Literal const& _node) override;
virtual void endVisit(Return const& _node) override;
+ virtual bool visit(MemberAccess const& _node) override;
void arithmeticOperation(BinaryOperation const& _op);
void compareOperation(BinaryOperation const& _op);
@@ -73,10 +74,14 @@ private:
void visitAssert(FunctionCall const&);
void visitRequire(FunctionCall const&);
+ void visitGasLeft(FunctionCall const&);
+ void visitBlockHash(FunctionCall const&);
/// Visits the FunctionDefinition of the called function
/// if available and inlines the return value.
void inlineFunctionCall(FunctionCall const&);
+ void defineSpecialVariable(std::string const& _name, Expression const& _expr, bool _increaseIndex = false);
+
/// Division expression in the given type. Requires special treatment because
/// of rounding for signed division.
smt::Expression division(smt::Expression _left, smt::Expression _right, IntegerType const& _type);
@@ -129,8 +134,6 @@ private:
/// This fails if the type is not supported.
bool createVariable(VariableDeclaration const& _varDecl);
- static std::string uniqueSymbol(Expression const& _expr);
-
/// @returns true if _delc is a variable that is known at the current point, i.e.
/// has a valid index
bool knownVariable(VariableDeclaration const& _decl);
@@ -154,10 +157,13 @@ private:
/// Creates the expression (value can be arbitrary)
void createExpr(Expression const& _e);
/// Checks if expression was created
- bool hasExpr(Expression const& _e) const;
+ bool knownExpr(Expression const& _e) const;
/// Creates the expression and sets its value.
void defineExpr(Expression const& _e, smt::Expression _value);
+ /// Checks if special variable was seen.
+ bool knownSpecialVariable(std::string const& _var) const;
+
/// Adds a new path condition
void pushPathCondition(smt::Expression const& _e);
/// Remove the last path condition
@@ -172,9 +178,6 @@ private:
/// Removes local variables from the context.
void removeLocalVariables();
- /// Checks if VariableDeclaration was seen.
- bool hasVariable(VariableDeclaration const& _e) const;
-
/// Copy the SSA indices of m_variables.
VariableIndices copyVariableIndices();
/// Resets the variable indices.
@@ -187,6 +190,7 @@ private:
/// repeated calls to the same function.
std::unordered_map<Expression const*, std::shared_ptr<SymbolicVariable>> m_expressions;
std::unordered_map<VariableDeclaration const*, std::shared_ptr<SymbolicVariable>> m_variables;
+ std::unordered_map<std::string, std::shared_ptr<SymbolicVariable>> m_specialVariables;
std::vector<smt::Expression> m_pathConditions;
ErrorReporter& m_errorReporter;
diff --git a/libsolidity/formal/SSAVariable.cpp b/libsolidity/formal/SSAVariable.cpp
index dbc58664..36e15508 100644
--- a/libsolidity/formal/SSAVariable.cpp
+++ b/libsolidity/formal/SSAVariable.cpp
@@ -28,6 +28,6 @@ SSAVariable::SSAVariable()
void SSAVariable::resetIndex()
{
m_currentIndex = 0;
- m_nextFreeIndex.reset (new int);
+ m_nextFreeIndex.reset (new unsigned);
*m_nextFreeIndex = 1;
}
diff --git a/libsolidity/formal/SSAVariable.h b/libsolidity/formal/SSAVariable.h
index d357740d..46935472 100644
--- a/libsolidity/formal/SSAVariable.h
+++ b/libsolidity/formal/SSAVariable.h
@@ -34,19 +34,19 @@ public:
void resetIndex();
/// This function returns the current index of this SSA variable.
- int index() const { return m_currentIndex; }
- int& index() { return m_currentIndex; }
+ unsigned index() const { return m_currentIndex; }
+ unsigned& index() { return m_currentIndex; }
- int operator++()
+ unsigned operator++()
{
return m_currentIndex = (*m_nextFreeIndex)++;
}
private:
- int m_currentIndex;
+ unsigned m_currentIndex;
/// The next free index is a shared pointer because we want
/// the copy and the copied to share it.
- std::shared_ptr<int> m_nextFreeIndex;
+ std::shared_ptr<unsigned> m_nextFreeIndex;
};
}
diff --git a/libsolidity/formal/SymbolicAddressVariable.cpp b/libsolidity/formal/SymbolicAddressVariable.cpp
index 68b95080..67a18540 100644
--- a/libsolidity/formal/SymbolicAddressVariable.cpp
+++ b/libsolidity/formal/SymbolicAddressVariable.cpp
@@ -24,18 +24,17 @@ using namespace dev;
using namespace dev::solidity;
SymbolicAddressVariable::SymbolicAddressVariable(
- Type const& _type,
string const& _uniqueName,
smt::SolverInterface& _interface
):
- SymbolicIntVariable(_type, _uniqueName, _interface)
+ SymbolicIntVariable(make_shared<IntegerType>(160), _uniqueName, _interface)
{
- solAssert(isAddress(_type.category()), "");
}
void SymbolicAddressVariable::setUnknownValue()
{
- IntegerType intType{160};
- m_interface.addAssertion(currentValue() >= minValue(intType));
- m_interface.addAssertion(currentValue() <= maxValue(intType));
+ auto intType = dynamic_cast<IntegerType const*>(m_type.get());
+ solAssert(intType, "");
+ m_interface.addAssertion(currentValue() >= minValue(*intType));
+ m_interface.addAssertion(currentValue() <= maxValue(*intType));
}
diff --git a/libsolidity/formal/SymbolicAddressVariable.h b/libsolidity/formal/SymbolicAddressVariable.h
index 4a0f2361..3c9c379a 100644
--- a/libsolidity/formal/SymbolicAddressVariable.h
+++ b/libsolidity/formal/SymbolicAddressVariable.h
@@ -31,7 +31,6 @@ class SymbolicAddressVariable: public SymbolicIntVariable
{
public:
SymbolicAddressVariable(
- Type const& _type,
std::string const& _uniqueName,
smt::SolverInterface& _interface
);
diff --git a/libsolidity/formal/SymbolicBoolVariable.cpp b/libsolidity/formal/SymbolicBoolVariable.cpp
index 9c41ca9d..4d753c5c 100644
--- a/libsolidity/formal/SymbolicBoolVariable.cpp
+++ b/libsolidity/formal/SymbolicBoolVariable.cpp
@@ -22,13 +22,13 @@ using namespace dev;
using namespace dev::solidity;
SymbolicBoolVariable::SymbolicBoolVariable(
- Type const& _type,
+ TypePointer _type,
string const& _uniqueName,
smt::SolverInterface&_interface
):
- SymbolicVariable(_type, _uniqueName, _interface)
+ SymbolicVariable(move(_type), _uniqueName, _interface)
{
- solAssert(_type.category() == Type::Category::Bool, "");
+ solAssert(m_type->category() == Type::Category::Bool, "");
}
smt::Expression SymbolicBoolVariable::valueAtIndex(int _index) const
diff --git a/libsolidity/formal/SymbolicBoolVariable.h b/libsolidity/formal/SymbolicBoolVariable.h
index 85e41b3b..438af2c6 100644
--- a/libsolidity/formal/SymbolicBoolVariable.h
+++ b/libsolidity/formal/SymbolicBoolVariable.h
@@ -31,7 +31,7 @@ class SymbolicBoolVariable: public SymbolicVariable
{
public:
SymbolicBoolVariable(
- Type const& _type,
+ TypePointer _type,
std::string const& _uniqueName,
smt::SolverInterface& _interface
);
diff --git a/libsolidity/formal/SymbolicIntVariable.cpp b/libsolidity/formal/SymbolicIntVariable.cpp
index cf1a7486..a5939842 100644
--- a/libsolidity/formal/SymbolicIntVariable.cpp
+++ b/libsolidity/formal/SymbolicIntVariable.cpp
@@ -24,13 +24,13 @@ using namespace dev;
using namespace dev::solidity;
SymbolicIntVariable::SymbolicIntVariable(
- Type const& _type,
+ TypePointer _type,
string const& _uniqueName,
smt::SolverInterface& _interface
):
- SymbolicVariable(_type, _uniqueName, _interface)
+ SymbolicVariable(move(_type), _uniqueName, _interface)
{
- solAssert(isNumber(_type.category()), "");
+ solAssert(isNumber(m_type->category()), "");
}
smt::Expression SymbolicIntVariable::valueAtIndex(int _index) const
@@ -45,7 +45,7 @@ void SymbolicIntVariable::setZeroValue()
void SymbolicIntVariable::setUnknownValue()
{
- auto intType = dynamic_cast<IntegerType const*>(&m_type);
+ auto intType = dynamic_cast<IntegerType const*>(m_type.get());
solAssert(intType, "");
m_interface.addAssertion(currentValue() >= minValue(*intType));
m_interface.addAssertion(currentValue() <= maxValue(*intType));
diff --git a/libsolidity/formal/SymbolicIntVariable.h b/libsolidity/formal/SymbolicIntVariable.h
index 110ebb09..a9e51b1b 100644
--- a/libsolidity/formal/SymbolicIntVariable.h
+++ b/libsolidity/formal/SymbolicIntVariable.h
@@ -31,7 +31,7 @@ class SymbolicIntVariable: public SymbolicVariable
{
public:
SymbolicIntVariable(
- Type const& _type,
+ TypePointer _type,
std::string const& _uniqueName,
smt::SolverInterface& _interface
);
diff --git a/libsolidity/formal/SymbolicTypes.cpp b/libsolidity/formal/SymbolicTypes.cpp
index d47869db..7e5db7bd 100644
--- a/libsolidity/formal/SymbolicTypes.cpp
+++ b/libsolidity/formal/SymbolicTypes.cpp
@@ -43,27 +43,28 @@ pair<bool, shared_ptr<SymbolicVariable>> dev::solidity::newSymbolicVariable(
{
bool abstract = false;
shared_ptr<SymbolicVariable> var;
+ TypePointer type = _type.shared_from_this();
if (!isSupportedType(_type))
{
abstract = true;
- var = make_shared<SymbolicIntVariable>(IntegerType{256}, _uniqueName, _solver);
+ var = make_shared<SymbolicIntVariable>(make_shared<IntegerType>(256), _uniqueName, _solver);
}
else if (isBool(_type.category()))
- var = make_shared<SymbolicBoolVariable>(_type, _uniqueName, _solver);
+ var = make_shared<SymbolicBoolVariable>(type, _uniqueName, _solver);
else if (isFunction(_type.category()))
- var = make_shared<SymbolicIntVariable>(IntegerType{256}, _uniqueName, _solver);
+ var = make_shared<SymbolicIntVariable>(make_shared<IntegerType>(256), _uniqueName, _solver);
else if (isInteger(_type.category()))
- var = make_shared<SymbolicIntVariable>(_type, _uniqueName, _solver);
+ var = make_shared<SymbolicIntVariable>(type, _uniqueName, _solver);
else if (isAddress(_type.category()))
- var = make_shared<SymbolicAddressVariable>(_type, _uniqueName, _solver);
+ var = make_shared<SymbolicAddressVariable>(_uniqueName, _solver);
else if (isRational(_type.category()))
{
auto rational = dynamic_cast<RationalNumberType const*>(&_type);
solAssert(rational, "");
if (rational->isFractional())
- var = make_shared<SymbolicIntVariable>(IntegerType{256}, _uniqueName, _solver);
+ var = make_shared<SymbolicIntVariable>(make_shared<IntegerType>(256), _uniqueName, _solver);
else
- var = make_shared<SymbolicIntVariable>(_type, _uniqueName, _solver);
+ var = make_shared<SymbolicIntVariable>(type, _uniqueName, _solver);
}
else
solAssert(false, "");
diff --git a/libsolidity/formal/SymbolicVariable.cpp b/libsolidity/formal/SymbolicVariable.cpp
index c042ec48..530564d2 100644
--- a/libsolidity/formal/SymbolicVariable.cpp
+++ b/libsolidity/formal/SymbolicVariable.cpp
@@ -24,18 +24,18 @@ using namespace dev;
using namespace dev::solidity;
SymbolicVariable::SymbolicVariable(
- Type const& _type,
+ TypePointer _type,
string const& _uniqueName,
smt::SolverInterface& _interface
):
- m_type(_type),
+ m_type(move(_type)),
m_uniqueName(_uniqueName),
m_interface(_interface),
m_ssa(make_shared<SSAVariable>())
{
}
-string SymbolicVariable::uniqueSymbol(int _index) const
+string SymbolicVariable::uniqueSymbol(unsigned _index) const
{
return m_uniqueName + "_" + to_string(_index);
}
diff --git a/libsolidity/formal/SymbolicVariable.h b/libsolidity/formal/SymbolicVariable.h
index 417e1f92..e554139f 100644
--- a/libsolidity/formal/SymbolicVariable.h
+++ b/libsolidity/formal/SymbolicVariable.h
@@ -39,10 +39,11 @@ class SymbolicVariable
{
public:
SymbolicVariable(
- Type const& _type,
+ TypePointer _type,
std::string const& _uniqueName,
smt::SolverInterface& _interface
);
+
virtual ~SymbolicVariable() = default;
smt::Expression currentValue() const
@@ -58,8 +59,8 @@ public:
return currentValue();
}
- int index() const { return m_ssa->index(); }
- int& index() { return m_ssa->index(); }
+ unsigned index() const { return m_ssa->index(); }
+ unsigned& index() { return m_ssa->index(); }
/// Sets the var to the default value of its type.
/// Inherited types must implement.
@@ -69,9 +70,9 @@ public:
virtual void setUnknownValue() {}
protected:
- std::string uniqueSymbol(int _index) const;
+ std::string uniqueSymbol(unsigned _index) const;
- Type const& m_type;
+ TypePointer m_type = nullptr;
std::string m_uniqueName;
smt::SolverInterface& m_interface;
std::shared_ptr<SSAVariable> m_ssa = nullptr;
diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp
index ca9a9b57..f99b9ea4 100644
--- a/libsolidity/parsing/Parser.cpp
+++ b/libsolidity/parsing/Parser.cpp
@@ -112,17 +112,17 @@ ASTPointer<PragmaDirective> Parser::parsePragmaDirective()
ASTNodeFactory nodeFactory(*this);
expectToken(Token::Pragma);
vector<string> literals;
- vector<Token::Value> tokens;
+ vector<Token> tokens;
do
{
- Token::Value token = m_scanner->currentToken();
+ Token token = m_scanner->currentToken();
if (token == Token::Illegal)
parserError("Token incompatible with Solidity parser as part of pragma directive.");
else
{
string literal = m_scanner->currentLiteral();
- if (literal.empty() && Token::toString(token))
- literal = Token::toString(token);
+ if (literal.empty() && TokenTraits::toString(token))
+ literal = TokenTraits::toString(token);
literals.push_back(literal);
tokens.push_back(token);
}
@@ -240,7 +240,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
expectToken(Token::LBrace);
while (true)
{
- Token::Value currentTokenValue = m_scanner->currentToken();
+ Token currentTokenValue = m_scanner->currentToken();
if (currentTokenValue == Token::RBrace)
break;
else if (currentTokenValue == Token::Function || currentTokenValue == Token::Constructor)
@@ -254,7 +254,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
else if (
currentTokenValue == Token::Identifier ||
currentTokenValue == Token::Mapping ||
- Token::isElementaryTypeName(currentTokenValue)
+ TokenTraits::isElementaryTypeName(currentTokenValue)
)
{
VarDeclParserOptions options;
@@ -304,7 +304,7 @@ ASTPointer<InheritanceSpecifier> Parser::parseInheritanceSpecifier()
Declaration::Visibility Parser::parseVisibilitySpecifier()
{
Declaration::Visibility visibility(Declaration::Visibility::Default);
- Token::Value token = m_scanner->currentToken();
+ Token token = m_scanner->currentToken();
switch (token)
{
case Token::Public:
@@ -329,7 +329,7 @@ Declaration::Visibility Parser::parseVisibilitySpecifier()
StateMutability Parser::parseStateMutability()
{
StateMutability stateMutability(StateMutability::NonPayable);
- Token::Value token = m_scanner->currentToken();
+ Token token = m_scanner->currentToken();
switch(token)
{
case Token::Payable:
@@ -386,7 +386,7 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _forceEmptyN
result.parameters = parseParameterList(options);
while (true)
{
- Token::Value token = m_scanner->currentToken();
+ Token token = m_scanner->currentToken();
if (_allowModifiers && token == Token::Identifier)
{
// If the name is empty (and this is not a constructor),
@@ -401,7 +401,7 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _forceEmptyN
else
result.modifiers.push_back(parseModifierInvocation());
}
- else if (Token::isVisibilitySpecifier(token))
+ else if (TokenTraits::isVisibilitySpecifier(token))
{
if (result.visibility != Declaration::Visibility::Default)
{
@@ -423,7 +423,7 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _forceEmptyN
else
result.visibility = parseVisibilitySpecifier();
}
- else if (Token::isStateMutabilitySpecifier(token))
+ else if (TokenTraits::isStateMutabilitySpecifier(token))
{
if (result.stateMutability != StateMutability::NonPayable)
{
@@ -587,8 +587,8 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
while (true)
{
- Token::Value token = m_scanner->currentToken();
- if (_options.isStateVariable && Token::isVariableVisibilitySpecifier(token))
+ Token token = m_scanner->currentToken();
+ if (_options.isStateVariable && TokenTraits::isVariableVisibilitySpecifier(token))
{
nodeFactory.markEndPosition();
if (visibility != Declaration::Visibility::Default)
@@ -609,7 +609,7 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
isIndexed = true;
else if (token == Token::Constant)
isDeclaredConst = true;
- else if (_options.allowLocationSpecifier && Token::isLocationSpecifier(token))
+ else if (_options.allowLocationSpecifier && TokenTraits::isLocationSpecifier(token))
{
if (location != VariableDeclaration::Location::Unspecified)
parserError(string("Location already specified."));
@@ -806,8 +806,8 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar)
RecursionGuard recursionGuard(*this);
ASTNodeFactory nodeFactory(*this);
ASTPointer<TypeName> type;
- Token::Value token = m_scanner->currentToken();
- if (Token::isElementaryTypeName(token))
+ Token token = m_scanner->currentToken();
+ if (TokenTraits::isElementaryTypeName(token))
{
unsigned firstSize;
unsigned secondSize;
@@ -817,7 +817,7 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar)
nodeFactory.markEndPosition();
m_scanner->next();
auto stateMutability = boost::make_optional(elemTypeName.token() == Token::Address, StateMutability::NonPayable);
- if (Token::isStateMutabilitySpecifier(m_scanner->currentToken(), false))
+ if (TokenTraits::isStateMutabilitySpecifier(m_scanner->currentToken(), false))
{
if (elemTypeName.token() == Token::Address)
{
@@ -874,8 +874,8 @@ ASTPointer<Mapping> Parser::parseMapping()
expectToken(Token::Mapping);
expectToken(Token::LParen);
ASTPointer<ElementaryTypeName> keyType;
- Token::Value token = m_scanner->currentToken();
- if (!Token::isElementaryTypeName(token))
+ Token token = m_scanner->currentToken();
+ if (!TokenTraits::isElementaryTypeName(token))
fatalParserError(string("Expected elementary type name for mapping key type"));
unsigned firstSize;
unsigned secondSize;
@@ -1252,7 +1252,7 @@ pair<Parser::LookAheadInfo, Parser::IndexAccessedPath> Parser::tryParseIndexAcce
// VariableDeclarationStatement out of it.
IndexAccessedPath iap = parseIndexAccessedPath();
- if (m_scanner->currentToken() == Token::Identifier || Token::isLocationSpecifier(m_scanner->currentToken()))
+ if (m_scanner->currentToken() == Token::Identifier || TokenTraits::isLocationSpecifier(m_scanner->currentToken()))
return make_pair(LookAheadInfo::VariableDeclaration, move(iap));
else
return make_pair(LookAheadInfo::Expression, move(iap));
@@ -1342,16 +1342,16 @@ ASTPointer<Expression> Parser::parseExpression(
{
RecursionGuard recursionGuard(*this);
ASTPointer<Expression> expression = parseBinaryExpression(4, _partiallyParsedExpression);
- if (Token::isAssignmentOp(m_scanner->currentToken()))
+ if (TokenTraits::isAssignmentOp(m_scanner->currentToken()))
{
- Token::Value assignmentOperator = m_scanner->currentToken();
+ Token assignmentOperator = m_scanner->currentToken();
m_scanner->next();
ASTPointer<Expression> rightHandSide = parseExpression();
ASTNodeFactory nodeFactory(*this, expression);
nodeFactory.setEndPositionFromNode(rightHandSide);
return nodeFactory.createNode<Assignment>(expression, assignmentOperator, rightHandSide);
}
- else if (m_scanner->currentToken() == Token::Value::Conditional)
+ else if (m_scanner->currentToken() == Token::Conditional)
{
m_scanner->next();
ASTPointer<Expression> trueExpression = parseExpression();
@@ -1373,11 +1373,11 @@ ASTPointer<Expression> Parser::parseBinaryExpression(
RecursionGuard recursionGuard(*this);
ASTPointer<Expression> expression = parseUnaryExpression(_partiallyParsedExpression);
ASTNodeFactory nodeFactory(*this, expression);
- int precedence = Token::precedence(m_scanner->currentToken());
+ int precedence = TokenTraits::precedence(m_scanner->currentToken());
for (; precedence >= _minPrecedence; --precedence)
- while (Token::precedence(m_scanner->currentToken()) == precedence)
+ while (TokenTraits::precedence(m_scanner->currentToken()) == precedence)
{
- Token::Value op = m_scanner->currentToken();
+ Token op = m_scanner->currentToken();
m_scanner->next();
ASTPointer<Expression> right = parseBinaryExpression(precedence + 1);
nodeFactory.setEndPositionFromNode(right);
@@ -1393,8 +1393,8 @@ ASTPointer<Expression> Parser::parseUnaryExpression(
RecursionGuard recursionGuard(*this);
ASTNodeFactory nodeFactory = _partiallyParsedExpression ?
ASTNodeFactory(*this, _partiallyParsedExpression) : ASTNodeFactory(*this);
- Token::Value token = m_scanner->currentToken();
- if (!_partiallyParsedExpression && (Token::isUnaryOp(token) || Token::isCountOp(token)))
+ Token token = m_scanner->currentToken();
+ if (!_partiallyParsedExpression && (TokenTraits::isUnaryOp(token) || TokenTraits::isCountOp(token)))
{
// prefix expression
m_scanner->next();
@@ -1407,7 +1407,7 @@ ASTPointer<Expression> Parser::parseUnaryExpression(
// potential postfix expression
ASTPointer<Expression> subExpression = parseLeftHandSideExpression(_partiallyParsedExpression);
token = m_scanner->currentToken();
- if (!Token::isCountOp(token))
+ if (!TokenTraits::isCountOp(token))
return subExpression;
nodeFactory.markEndPosition();
m_scanner->next();
@@ -1482,7 +1482,7 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
{
RecursionGuard recursionGuard(*this);
ASTNodeFactory nodeFactory(*this);
- Token::Value token = m_scanner->currentToken();
+ Token token = m_scanner->currentToken();
ASTPointer<Expression> expression;
switch (token)
@@ -1493,7 +1493,7 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
expression = nodeFactory.createNode<Literal>(token, getLiteralAndAdvance());
break;
case Token::Number:
- if (Token::isEtherSubdenomination(m_scanner->peekNextToken()))
+ if (TokenTraits::isEtherSubdenomination(m_scanner->peekNextToken()))
{
ASTPointer<ASTString> literal = getLiteralAndAdvance();
nodeFactory.markEndPosition();
@@ -1501,7 +1501,7 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
m_scanner->next();
expression = nodeFactory.createNode<Literal>(token, literal, subdenomination);
}
- else if (Token::isTimeSubdenomination(m_scanner->peekNextToken()))
+ else if (TokenTraits::isTimeSubdenomination(m_scanner->peekNextToken()))
{
ASTPointer<ASTString> literal = getLiteralAndAdvance();
nodeFactory.markEndPosition();
@@ -1531,7 +1531,7 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
// (x,) is one-dimensional tuple, elements in arrays cannot be left out, only in tuples.
m_scanner->next();
vector<ASTPointer<Expression>> components;
- Token::Value oppositeToken = (token == Token::LParen ? Token::RParen : Token::RBrack);
+ Token oppositeToken = (token == Token::LParen ? Token::RParen : Token::RBrack);
bool isArray = (token == Token::LBrack);
if (m_scanner->currentToken() != oppositeToken)
@@ -1558,7 +1558,7 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
fatalParserError("Expected even number of hex-nibbles within double-quotes.");
break;
default:
- if (Token::isElementaryTypeName(token))
+ if (TokenTraits::isElementaryTypeName(token))
{
//used for casts
unsigned firstSize;
@@ -1595,7 +1595,7 @@ pair<vector<ASTPointer<Expression>>, vector<ASTPointer<ASTString>>> Parser::pars
{
RecursionGuard recursionGuard(*this);
pair<vector<ASTPointer<Expression>>, vector<ASTPointer<ASTString>>> ret;
- Token::Value token = m_scanner->currentToken();
+ Token token = m_scanner->currentToken();
if (token == Token::LBrace)
{
// call({arg1 : 1, arg2 : 2 })
@@ -1638,21 +1638,21 @@ Parser::LookAheadInfo Parser::peekStatementType() const
// or a mutability specifier, we also have a variable declaration.
// If we get an identifier followed by a "[" or ".", it can be both ("lib.type[9] a;" or "variable.el[9] = 7;").
// In all other cases, we have an expression statement.
- Token::Value token(m_scanner->currentToken());
- bool mightBeTypeName = (Token::isElementaryTypeName(token) || token == Token::Identifier);
+ Token token(m_scanner->currentToken());
+ bool mightBeTypeName = (TokenTraits::isElementaryTypeName(token) || token == Token::Identifier);
if (token == Token::Mapping || token == Token::Function || token == Token::Var)
return LookAheadInfo::VariableDeclaration;
if (mightBeTypeName)
{
- Token::Value next = m_scanner->peekNextToken();
+ Token next = m_scanner->peekNextToken();
// So far we only allow ``address payable`` in variable declaration statements and in no other
// kind of statement. This means, for example, that we do not allow type expressions of the form
// ``address payable;``.
// If we want to change this in the future, we need to consider another scanner token here.
- if (Token::isElementaryTypeName(token) && Token::isStateMutabilitySpecifier(next, false))
+ if (TokenTraits::isElementaryTypeName(token) && TokenTraits::isStateMutabilitySpecifier(next, false))
return LookAheadInfo::VariableDeclaration;
- if (next == Token::Identifier || Token::isLocationSpecifier(next))
+ if (next == Token::Identifier || TokenTraits::isLocationSpecifier(next))
return LookAheadInfo::VariableDeclaration;
if (next == Token::LBrack || next == Token::Period)
return LookAheadInfo::IndexAccessStructure;
diff --git a/libsolidity/parsing/ParserBase.cpp b/libsolidity/parsing/ParserBase.cpp
index 71133746..1d4cb1e2 100644
--- a/libsolidity/parsing/ParserBase.cpp
+++ b/libsolidity/parsing/ParserBase.cpp
@@ -43,12 +43,12 @@ int ParserBase::endPosition() const
return m_scanner->currentLocation().end;
}
-Token::Value ParserBase::currentToken() const
+Token ParserBase::currentToken() const
{
return m_scanner->currentToken();
}
-Token::Value ParserBase::peekNextToken() const
+Token ParserBase::peekNextToken() const
{
return m_scanner->peekNextToken();
}
@@ -58,31 +58,31 @@ std::string ParserBase::currentLiteral() const
return m_scanner->currentLiteral();
}
-Token::Value ParserBase::advance()
+Token ParserBase::advance()
{
return m_scanner->next();
}
-void ParserBase::expectToken(Token::Value _value, bool _advance)
+void ParserBase::expectToken(Token _value, bool _advance)
{
- Token::Value tok = m_scanner->currentToken();
+ Token tok = m_scanner->currentToken();
if (tok != _value)
{
- auto tokenName = [this](Token::Value _token)
+ auto tokenName = [this](Token _token)
{
if (_token == Token::Identifier)
return string("identifier");
else if (_token == Token::EOS)
return string("end of source");
- else if (Token::isReservedKeyword(_token))
- return string("reserved keyword '") + Token::friendlyName(_token) + "'";
- else if (Token::isElementaryTypeName(_token)) //for the sake of accuracy in reporting
+ else if (TokenTraits::isReservedKeyword(_token))
+ return string("reserved keyword '") + TokenTraits::friendlyName(_token) + "'";
+ else if (TokenTraits::isElementaryTypeName(_token)) //for the sake of accuracy in reporting
{
ElementaryTypeNameToken elemTypeName = m_scanner->currentElementaryTypeNameToken();
return string("'") + elemTypeName.toString() + "'";
}
else
- return string("'") + Token::friendlyName(_token) + "'";
+ return string("'") + TokenTraits::friendlyName(_token) + "'";
};
fatalParserError(string("Expected ") + tokenName(_value) + string(" but got ") + tokenName(tok));
diff --git a/libsolidity/parsing/ParserBase.h b/libsolidity/parsing/ParserBase.h
index b28e1b1b..e01f37d8 100644
--- a/libsolidity/parsing/ParserBase.h
+++ b/libsolidity/parsing/ParserBase.h
@@ -63,11 +63,11 @@ protected:
///@{
///@name Helper functions
/// If current token value is not _value, throw exception otherwise advance token.
- void expectToken(Token::Value _value, bool _advance = true);
- Token::Value currentToken() const;
- Token::Value peekNextToken() const;
+ void expectToken(Token _value, bool _advance = true);
+ Token currentToken() const;
+ Token peekNextToken() const;
std::string currentLiteral() const;
- Token::Value advance();
+ Token advance();
///@}
/// Increases the recursion depth and throws an exception if it is too deep.
diff --git a/libsolidity/parsing/Scanner.cpp b/libsolidity/parsing/Scanner.cpp
index 87d7c535..e9dad2ad 100644
--- a/libsolidity/parsing/Scanner.cpp
+++ b/libsolidity/parsing/Scanner.cpp
@@ -214,9 +214,9 @@ void Scanner::addUnicodeAsUTF8(unsigned codepoint)
}
// Ensure that tokens can be stored in a byte.
-BOOST_STATIC_ASSERT(Token::NUM_TOKENS <= 0x100);
+BOOST_STATIC_ASSERT(TokenTraits::count() <= 0x100);
-Token::Value Scanner::next()
+Token Scanner::next()
{
m_currentToken = m_nextToken;
m_skippedComment = m_nextSkippedComment;
@@ -225,7 +225,7 @@ Token::Value Scanner::next()
return m_currentToken.token;
}
-Token::Value Scanner::selectToken(char _next, Token::Value _then, Token::Value _else)
+Token Scanner::selectToken(char _next, Token _then, Token _else)
{
advance();
if (m_char == _next)
@@ -249,7 +249,7 @@ void Scanner::skipWhitespaceExceptUnicodeLinebreak()
advance();
}
-Token::Value Scanner::skipSingleLineComment()
+Token Scanner::skipSingleLineComment()
{
// Line terminator is not part of the comment. If it is a
// non-ascii line terminator, it will result in a parser error.
@@ -259,7 +259,7 @@ Token::Value Scanner::skipSingleLineComment()
return Token::Whitespace;
}
-Token::Value Scanner::scanSingleLineDocComment()
+Token Scanner::scanSingleLineDocComment()
{
LiteralScope literal(this, LITERAL_TYPE_COMMENT);
advance(); //consume the last '/' at ///
@@ -295,7 +295,7 @@ Token::Value Scanner::scanSingleLineDocComment()
return Token::CommentLiteral;
}
-Token::Value Scanner::skipMultiLineComment()
+Token Scanner::skipMultiLineComment()
{
advance();
while (!isSourcePastEndOfInput())
@@ -316,7 +316,7 @@ Token::Value Scanner::skipMultiLineComment()
return Token::Illegal;
}
-Token::Value Scanner::scanMultiLineDocComment()
+Token Scanner::scanMultiLineDocComment()
{
LiteralScope literal(this, LITERAL_TYPE_COMMENT);
bool endFound = false;
@@ -369,7 +369,7 @@ Token::Value Scanner::scanMultiLineDocComment()
return Token::CommentLiteral;
}
-Token::Value Scanner::scanSlash()
+Token Scanner::scanSlash()
{
int firstSlashPosition = sourcePos();
advance();
@@ -380,7 +380,7 @@ Token::Value Scanner::scanSlash()
else if (m_char == '/')
{
// doxygen style /// comment
- Token::Value comment;
+ Token comment;
m_nextSkippedComment.location.start = firstSlashPosition;
comment = scanSingleLineDocComment();
m_nextSkippedComment.location.end = sourcePos();
@@ -406,7 +406,7 @@ Token::Value Scanner::scanSlash()
return Token::Whitespace;
}
// we actually have a multiline documentation comment
- Token::Value comment;
+ Token comment;
m_nextSkippedComment.location.start = firstSlashPosition;
comment = scanMultiLineDocComment();
m_nextSkippedComment.location.end = sourcePos();
@@ -432,7 +432,7 @@ void Scanner::scanToken()
m_nextSkippedComment.literal.clear();
m_nextSkippedComment.extendedTokenInfo = make_tuple(0, 0);
- Token::Value token;
+ Token token;
// M and N are for the purposes of grabbing different type sizes
unsigned m;
unsigned n;
@@ -703,7 +703,7 @@ bool Scanner::isUnicodeLinebreak()
return false;
}
-Token::Value Scanner::scanString()
+Token Scanner::scanString()
{
char const quote = m_char;
advance(); // consume quote
@@ -727,7 +727,7 @@ Token::Value Scanner::scanString()
return Token::StringLiteral;
}
-Token::Value Scanner::scanHexString()
+Token Scanner::scanHexString()
{
char const quote = m_char;
advance(); // consume quote
@@ -760,7 +760,7 @@ void Scanner::scanDecimalDigits()
// Defer further validation of underscore to SyntaxChecker.
}
-Token::Value Scanner::scanNumber(char _charSeen)
+Token Scanner::scanNumber(char _charSeen)
{
enum { DECIMAL, HEX, BINARY } kind = DECIMAL;
LiteralScope literal(this, LITERAL_TYPE_NUMBER);
@@ -854,7 +854,7 @@ Token::Value Scanner::scanNumber(char _charSeen)
return Token::Number;
}
-tuple<Token::Value, unsigned, unsigned> Scanner::scanIdentifierOrKeyword()
+tuple<Token, unsigned, unsigned> Scanner::scanIdentifierOrKeyword()
{
solAssert(isIdentifierStart(m_char), "");
LiteralScope literal(this, LITERAL_TYPE_STRING);
@@ -863,7 +863,7 @@ tuple<Token::Value, unsigned, unsigned> Scanner::scanIdentifierOrKeyword()
while (isIdentifierPart(m_char)) //get full literal
addLiteralCharAndAdvance();
literal.complete();
- return Token::fromIdentifierOrKeyword(m_nextToken.literal);
+ return TokenTraits::fromIdentifierOrKeyword(m_nextToken.literal);
}
char CharStream::advanceAndGet(size_t _chars)
diff --git a/libsolidity/parsing/Scanner.h b/libsolidity/parsing/Scanner.h
index 7564c788..02e0553f 100644
--- a/libsolidity/parsing/Scanner.h
+++ b/libsolidity/parsing/Scanner.h
@@ -112,13 +112,13 @@ public:
void reset();
/// @returns the next token and advances input
- Token::Value next();
+ Token next();
///@{
///@name Information about the current token
/// @returns the current token
- Token::Value currentToken() const
+ Token currentToken() const
{
return m_currentToken.token;
}
@@ -149,7 +149,7 @@ public:
///@name Information about the next token
/// @returns the next token without advancing input.
- Token::Value peekNextToken() const { return m_nextToken.token; }
+ Token peekNextToken() const { return m_nextToken.token; }
SourceLocation peekLocation() const { return m_nextToken.location; }
std::string const& peekLiteral() const { return m_nextToken.literal; }
///@}
@@ -168,7 +168,7 @@ private:
/// Used for the current and look-ahead token and comments
struct TokenDesc
{
- Token::Value token;
+ Token token;
SourceLocation location;
std::string literal;
std::tuple<unsigned, unsigned> extendedTokenInfo;
@@ -185,9 +185,9 @@ private:
bool advance() { m_char = m_source.advanceAndGet(); return !m_source.isPastEndOfInput(); }
void rollback(int _amount) { m_char = m_source.rollback(_amount); }
- inline Token::Value selectToken(Token::Value _tok) { advance(); return _tok; }
+ inline Token selectToken(Token _tok) { advance(); return _tok; }
/// If the next character is _next, advance and return _then, otherwise return _else.
- inline Token::Value selectToken(char _next, Token::Value _then, Token::Value _else);
+ inline Token selectToken(char _next, Token _then, Token _else);
bool scanHexByte(char& o_scannedByte);
bool scanUnicode(unsigned& o_codepoint);
@@ -199,19 +199,19 @@ private:
bool skipWhitespace();
/// Skips all whitespace that are neither '\r' nor '\n'.
void skipWhitespaceExceptUnicodeLinebreak();
- Token::Value skipSingleLineComment();
- Token::Value skipMultiLineComment();
+ Token skipSingleLineComment();
+ Token skipMultiLineComment();
void scanDecimalDigits();
- Token::Value scanNumber(char _charSeen = 0);
- std::tuple<Token::Value, unsigned, unsigned> scanIdentifierOrKeyword();
+ Token scanNumber(char _charSeen = 0);
+ std::tuple<Token, unsigned, unsigned> scanIdentifierOrKeyword();
- Token::Value scanString();
- Token::Value scanHexString();
- Token::Value scanSingleLineDocComment();
- Token::Value scanMultiLineDocComment();
+ Token scanString();
+ Token scanHexString();
+ Token scanSingleLineDocComment();
+ Token scanMultiLineDocComment();
/// Scans a slash '/' and depending on the characters returns the appropriate token
- Token::Value scanSlash();
+ Token scanSlash();
/// Scans an escape-sequence which is part of a string and adds the
/// decoded character to the current literal. Returns true if a pattern
diff --git a/libsolidity/parsing/Token.cpp b/libsolidity/parsing/Token.cpp
index 27acb7d4..dccd9037 100644
--- a/libsolidity/parsing/Token.cpp
+++ b/libsolidity/parsing/Token.cpp
@@ -51,9 +51,9 @@ namespace dev
namespace solidity
{
-void ElementaryTypeNameToken::assertDetails(Token::Value _baseType, unsigned const& _first, unsigned const& _second)
+void ElementaryTypeNameToken::assertDetails(Token _baseType, unsigned const& _first, unsigned const& _second)
{
- solAssert(Token::isElementaryTypeName(_baseType), "Expected elementary type name: " + string(Token::toString(_baseType)));
+ solAssert(TokenTraits::isElementaryTypeName(_baseType), "Expected elementary type name: " + string(TokenTraits::toString(_baseType)));
if (_baseType == Token::BytesM)
{
solAssert(_second == 0, "There should not be a second size argument to type bytesM.");
@@ -61,17 +61,17 @@ void ElementaryTypeNameToken::assertDetails(Token::Value _baseType, unsigned con
}
else if (_baseType == Token::UIntM || _baseType == Token::IntM)
{
- solAssert(_second == 0, "There should not be a second size argument to type " + string(Token::toString(_baseType)) + ".");
+ solAssert(_second == 0, "There should not be a second size argument to type " + string(TokenTraits::toString(_baseType)) + ".");
solAssert(
_first <= 256 && _first % 8 == 0,
- "No elementary type " + string(Token::toString(_baseType)) + to_string(_first) + "."
+ "No elementary type " + string(TokenTraits::toString(_baseType)) + to_string(_first) + "."
);
}
else if (_baseType == Token::UFixedMxN || _baseType == Token::FixedMxN)
{
solAssert(
_first >= 8 && _first <= 256 && _first % 8 == 0 && _second <= 80,
- "No elementary type " + string(Token::toString(_baseType)) + to_string(_first) + "x" + to_string(_second) + "."
+ "No elementary type " + string(TokenTraits::toString(_baseType)) + to_string(_first) + "x" + to_string(_second) + "."
);
}
m_token = _baseType;
@@ -79,38 +79,54 @@ void ElementaryTypeNameToken::assertDetails(Token::Value _baseType, unsigned con
m_secondNumber = _second;
}
-#define T(name, string, precedence) #name,
-char const* const Token::m_name[NUM_TOKENS] =
+namespace TokenTraits
{
- TOKEN_LIST(T, T)
-};
-#undef T
+char const* toString(Token tok)
+{
+ switch (tok)
+ {
+#define T(name, string, precedence) case Token::name: return string;
+ TOKEN_LIST(T, T)
+#undef T
+ default: // Token::NUM_TOKENS:
+ return "";
+ }
+}
-#define T(name, string, precedence) string,
-char const* const Token::m_string[NUM_TOKENS] =
+char const* name(Token tok)
{
- TOKEN_LIST(T, T)
-};
+#define T(name, string, precedence) #name,
+ static char const* const names[TokenTraits::count()] = { TOKEN_LIST(T, T) };
#undef T
+ solAssert(static_cast<size_t>(tok) < TokenTraits::count(), "");
+ return names[static_cast<size_t>(tok)];
+}
-#define T(name, string, precedence) precedence,
-int8_t const Token::m_precedence[NUM_TOKENS] =
+std::string friendlyName(Token tok)
{
- TOKEN_LIST(T, T)
-};
-#undef T
+ char const* ret = toString(tok);
+ if (ret)
+ return std::string(ret);
+ ret = name(tok);
+ solAssert(ret != nullptr, "");
+ return std::string(ret);
+}
-#define KT(a, b, c) 'T',
-#define KK(a, b, c) 'K',
-char const Token::m_tokenType[] =
+#define T(name, string, precedence) precedence,
+int precedence(Token tok)
{
- TOKEN_LIST(KT, KK)
-};
+ int8_t const static precs[TokenTraits::count()] =
+ {
+ TOKEN_LIST(T, T)
+ };
+ return precs[static_cast<size_t>(tok)];
+}
+#undef T
-int Token::parseSize(string::const_iterator _begin, string::const_iterator _end)
+int parseSize(string::const_iterator _begin, string::const_iterator _end)
{
try
{
@@ -123,7 +139,20 @@ int Token::parseSize(string::const_iterator _begin, string::const_iterator _end)
}
}
-tuple<Token::Value, unsigned int, unsigned int> Token::fromIdentifierOrKeyword(string const& _literal)
+static Token keywordByName(string const& _name)
+{
+ // The following macros are used inside TOKEN_LIST and cause non-keyword tokens to be ignored
+ // and keywords to be put inside the keywords variable.
+#define KEYWORD(name, string, precedence) {string, Token::name},
+#define TOKEN(name, string, precedence)
+ static const map<string, Token> keywords({TOKEN_LIST(TOKEN, KEYWORD)});
+#undef KEYWORD
+#undef TOKEN
+ auto it = keywords.find(_name);
+ return it == keywords.end() ? Token::Identifier : it->second;
+}
+
+tuple<Token, unsigned int, unsigned int> fromIdentifierOrKeyword(string const& _literal)
{
auto positionM = find_if(_literal.begin(), _literal.end(), ::isdigit);
if (positionM != _literal.end())
@@ -131,7 +160,7 @@ tuple<Token::Value, unsigned int, unsigned int> Token::fromIdentifierOrKeyword(s
string baseType(_literal.begin(), positionM);
auto positionX = find_if_not(positionM, _literal.end(), ::isdigit);
int m = parseSize(positionM, positionX);
- Token::Value keyword = keywordByName(baseType);
+ Token keyword = keywordByName(baseType);
if (keyword == Token::Bytes)
{
if (0 < m && m <= 32 && positionX == _literal.end())
@@ -172,20 +201,7 @@ tuple<Token::Value, unsigned int, unsigned int> Token::fromIdentifierOrKeyword(s
return make_tuple(keywordByName(_literal), 0, 0);
}
-Token::Value Token::keywordByName(string const& _name)
-{
- // The following macros are used inside TOKEN_LIST and cause non-keyword tokens to be ignored
- // and keywords to be put inside the keywords variable.
-#define KEYWORD(name, string, precedence) {string, Token::name},
-#define TOKEN(name, string, precedence)
- static const map<string, Token::Value> keywords({TOKEN_LIST(TOKEN, KEYWORD)});
-#undef KEYWORD
-#undef TOKEN
- auto it = keywords.find(_name);
- return it == keywords.end() ? Token::Identifier : it->second;
-}
-#undef KT
-#undef KK
+}
}
}
diff --git a/libsolidity/parsing/Token.h b/libsolidity/parsing/Token.h
index 8ecc850a..81e8dd98 100644
--- a/libsolidity/parsing/Token.h
+++ b/libsolidity/parsing/Token.h
@@ -45,6 +45,7 @@
#include <libdevcore/Common.h>
#include <libsolidity/interface/Exceptions.h>
#include <libsolidity/parsing/UndefMacros.h>
+#include <iosfwd>
namespace dev
{
@@ -267,119 +268,95 @@ namespace solidity
/* Scanner-internal use only. */ \
T(Whitespace, NULL, 0)
-
-class Token
-{
-public:
- // All token values.
- // attention! msvc issue:
- // http://stackoverflow.com/questions/9567868/compile-errors-after-adding-v8-to-my-project-c2143-c2059
- // @todo: avoid TOKEN_LIST macro
+// All token values.
+// attention! msvc issue:
+// http://stackoverflow.com/questions/9567868/compile-errors-after-adding-v8-to-my-project-c2143-c2059
+// @todo: avoid TOKEN_LIST macro
+enum class Token : unsigned int {
#define T(name, string, precedence) name,
- enum Value
- {
- TOKEN_LIST(T, T)
- NUM_TOKENS
- };
+ TOKEN_LIST(T, T)
+ NUM_TOKENS
#undef T
+};
- // @returns a string corresponding to the C++ token name
- // (e.g. "LT" for the token LT).
- static char const* name(Value tok)
- {
- solAssert(tok < NUM_TOKENS, "");
- return m_name[tok];
- }
+namespace TokenTraits
+{
+ constexpr size_t count() { return static_cast<size_t>(Token::NUM_TOKENS); }
// Predicates
- static bool isElementaryTypeName(Value tok) { return Int <= tok && tok < TypesEnd; }
- static bool isAssignmentOp(Value tok) { return Assign <= tok && tok <= AssignMod; }
- static bool isBinaryOp(Value op) { return Comma <= op && op <= Exp; }
- static bool isCommutativeOp(Value op) { return op == BitOr || op == BitXor || op == BitAnd ||
- op == Add || op == Mul || op == Equal || op == NotEqual; }
- static bool isArithmeticOp(Value op) { return Add <= op && op <= Exp; }
- static bool isCompareOp(Value op) { return Equal <= op && op <= GreaterThanOrEqual; }
+ constexpr bool isElementaryTypeName(Token tok) { return Token::Int <= tok && tok < Token::TypesEnd; }
+ constexpr bool isAssignmentOp(Token tok) { return Token::Assign <= tok && tok <= Token::AssignMod; }
+ constexpr bool isBinaryOp(Token op) { return Token::Comma <= op && op <= Token::Exp; }
+ constexpr bool isCommutativeOp(Token op) { return op == Token::BitOr || op == Token::BitXor || op == Token::BitAnd ||
+ op == Token::Add || op == Token::Mul || op == Token::Equal || op == Token::NotEqual; }
+ constexpr bool isArithmeticOp(Token op) { return Token::Add <= op && op <= Token::Exp; }
+ constexpr bool isCompareOp(Token op) { return Token::Equal <= op && op <= Token::GreaterThanOrEqual; }
- static Value AssignmentToBinaryOp(Value op)
- {
- solAssert(isAssignmentOp(op) && op != Assign, "");
- return Value(op + (BitOr - AssignBitOr));
- }
+ constexpr bool isBitOp(Token op) { return (Token::BitOr <= op && op <= Token::BitAnd) || op == Token::BitNot; }
+ constexpr bool isBooleanOp(Token op) { return (Token::Or <= op && op <= Token::And) || op == Token::Not; }
+ constexpr bool isUnaryOp(Token op) { return (Token::Not <= op && op <= Token::Delete) || op == Token::Add || op == Token::Sub; }
+ constexpr bool isCountOp(Token op) { return op == Token::Inc || op == Token::Dec; }
+ constexpr bool isShiftOp(Token op) { return (Token::SHL <= op) && (op <= Token::SHR); }
+ constexpr bool isVariableVisibilitySpecifier(Token op) { return op == Token::Public || op == Token::Private || op == Token::Internal; }
+ constexpr bool isVisibilitySpecifier(Token op) { return isVariableVisibilitySpecifier(op) || op == Token::External; }
+ constexpr bool isLocationSpecifier(Token op) { return op == Token::Memory || op == Token::Storage || op == Token::CallData; }
- static bool isBitOp(Value op) { return (BitOr <= op && op <= BitAnd) || op == BitNot; }
- static bool isBooleanOp(Value op) { return (Or <= op && op <= And) || op == Not; }
- static bool isUnaryOp(Value op) { return (Not <= op && op <= Delete) || op == Add || op == Sub; }
- static bool isCountOp(Value op) { return op == Inc || op == Dec; }
- static bool isShiftOp(Value op) { return (SHL <= op) && (op <= SHR); }
- static bool isVisibilitySpecifier(Value op) { return isVariableVisibilitySpecifier(op) || op == External; }
- static bool isVariableVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Internal; }
- static bool isLocationSpecifier(Value op) { return op == Memory || op == Storage || op == CallData; }
- static bool isStateMutabilitySpecifier(Value op, bool _allowConstant = true)
+ constexpr bool isStateMutabilitySpecifier(Token op, bool _allowConstant = true)
{
- if (op == Constant && _allowConstant)
- return true;
- return op == Pure || op == View || op == Payable;
+ return (op == Token::Constant && _allowConstant)
+ || op == Token::Pure || op == Token::View || op == Token::Payable;
}
- static bool isEtherSubdenomination(Value op) { return op == SubWei || op == SubSzabo || op == SubFinney || op == SubEther; }
- static bool isTimeSubdenomination(Value op) { return op == SubSecond || op == SubMinute || op == SubHour || op == SubDay || op == SubWeek || op == SubYear; }
- static bool isReservedKeyword(Value op) { return (Abstract <= op && op <= Unchecked); }
- // @returns a string corresponding to the JS token string
- // (.e., "<" for the token LT) or NULL if the token doesn't
- // have a (unique) string (e.g. an IDENTIFIER).
- static char const* toString(Value tok)
- {
- solAssert(tok < NUM_TOKENS, "");
- return m_string[tok];
- }
+ constexpr bool isEtherSubdenomination(Token op) { return op == Token::SubWei || op == Token::SubSzabo || op == Token::SubFinney || op == Token::SubEther; }
+ constexpr bool isTimeSubdenomination(Token op) { return op == Token::SubSecond || op == Token::SubMinute || op == Token::SubHour || op == Token::SubDay || op == Token::SubWeek || op == Token::SubYear; }
+ constexpr bool isReservedKeyword(Token op) { return (Token::Abstract <= op && op <= Token::Unchecked); }
- static std::string friendlyName(Value tok)
+ inline Token AssignmentToBinaryOp(Token op)
{
- char const* ret = toString(tok);
- if (ret == nullptr)
- {
- ret = name(tok);
- solAssert(ret != nullptr, "");
- }
- return std::string(ret);
+ solAssert(isAssignmentOp(op) && op != Token::Assign, "");
+ return static_cast<Token>(static_cast<int>(op) + (static_cast<int>(Token::BitOr) - static_cast<int>(Token::AssignBitOr)));
}
// @returns the precedence > 0 for binary and compare
// operators; returns 0 otherwise.
- static int precedence(Value tok)
- {
- solAssert(tok < NUM_TOKENS, "");
- return m_precedence[tok];
- }
+ int precedence(Token tok);
- static std::tuple<Token::Value, unsigned int, unsigned int> fromIdentifierOrKeyword(std::string const& _literal);
+ std::tuple<Token, unsigned int, unsigned int> fromIdentifierOrKeyword(std::string const& _literal);
-private:
- // @returns -1 on error (invalid digit or number too large)
- static int parseSize(std::string::const_iterator _begin, std::string::const_iterator _end);
- // @returns the keyword with name @a _name or Token::Identifier of no such keyword exists.
- static Token::Value keywordByName(std::string const& _name);
- static char const* const m_name[NUM_TOKENS];
- static char const* const m_string[NUM_TOKENS];
- static int8_t const m_precedence[NUM_TOKENS];
- static char const m_tokenType[NUM_TOKENS];
-};
+ // @returns a string corresponding to the C++ token name
+ // (e.g. "LT" for the token LT).
+ char const* name(Token tok);
+
+ // @returns a string corresponding to the JS token string
+ // (.e., "<" for the token LT) or NULL if the token doesn't
+ // have a (unique) string (e.g. an IDENTIFIER).
+ char const* toString(Token tok);
+
+ std::string friendlyName(Token tok);
+}
+
+inline std::ostream& operator<<(std::ostream& os, Token token)
+{
+ os << TokenTraits::friendlyName(token);
+ return os;
+}
class ElementaryTypeNameToken
{
public:
- ElementaryTypeNameToken(Token::Value _token, unsigned const& _firstNumber, unsigned const& _secondNumber)
+ ElementaryTypeNameToken(Token _token, unsigned const& _firstNumber, unsigned const& _secondNumber)
{
assertDetails(_token, _firstNumber, _secondNumber);
}
unsigned int firstNumber() const { return m_firstNumber; }
unsigned int secondNumber() const { return m_secondNumber; }
- Token::Value token() const { return m_token; }
+ Token token() const { return m_token; }
+
///if tokValue is set to true, then returns the actual token type name, otherwise, returns full type
std::string toString(bool const& tokenValue = false) const
{
- std::string name = Token::toString(m_token);
+ std::string name = TokenTraits::toString(m_token);
if (tokenValue || (firstNumber() == 0 && secondNumber() == 0))
return name;
solAssert(name.size() >= 3, "Token name size should be greater than 3. Should not reach here.");
@@ -390,11 +367,11 @@ public:
}
private:
- Token::Value m_token;
+ Token m_token;
unsigned int m_firstNumber;
unsigned int m_secondNumber;
/// throws if type is not properly sized
- void assertDetails(Token::Value _baseType, unsigned const& _first, unsigned const& _second);
+ void assertDetails(Token _baseType, unsigned const& _first, unsigned const& _second);
};
}
diff --git a/libyul/optimiser/RedundantAssignEliminator.cpp b/libyul/optimiser/RedundantAssignEliminator.cpp
new file mode 100644
index 00000000..478858e4
--- /dev/null
+++ b/libyul/optimiser/RedundantAssignEliminator.cpp
@@ -0,0 +1,193 @@
+/*
+ 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/>.
+*/
+/**
+ * Optimiser component that removes assignments to variables that are not used
+ * until they go out of scope or are re-assigned.
+ */
+
+#include <libyul/optimiser/RedundantAssignEliminator.h>
+
+#include <libyul/optimiser/Semantics.h>
+
+#include <libsolidity/inlineasm/AsmData.h>
+
+#include <libdevcore/CommonData.h>
+
+#include <boost/range/algorithm_ext/erase.hpp>
+
+using namespace std;
+using namespace dev;
+using namespace dev::yul;
+using namespace dev::solidity;
+
+void RedundantAssignEliminator::operator()(Identifier const& _identifier)
+{
+ changeUndecidedTo(_identifier.name, State::Used);
+}
+
+void RedundantAssignEliminator::operator()(VariableDeclaration const& _variableDeclaration)
+{
+ ASTWalker::operator()(_variableDeclaration);
+
+ for (auto const& var: _variableDeclaration.variables)
+ m_declaredVariables.insert(var.name);
+}
+
+void RedundantAssignEliminator::operator()(Assignment const& _assignment)
+{
+ visit(*_assignment.value);
+ for (auto const& var: _assignment.variableNames)
+ changeUndecidedTo(var.name, State::Unused);
+
+ if (_assignment.variableNames.size() == 1)
+ // Default-construct it in "Undecided" state if it does not yet exist.
+ m_assignments[_assignment.variableNames.front().name][&_assignment];
+}
+
+void RedundantAssignEliminator::operator()(If const& _if)
+{
+ visit(*_if.condition);
+
+ RedundantAssignEliminator branch{*this};
+ branch(_if.body);
+
+ join(branch);
+}
+
+void RedundantAssignEliminator::operator()(Switch const& _switch)
+{
+ visit(*_switch.expression);
+
+ bool hasDefault = false;
+ vector<RedundantAssignEliminator> branches;
+ for (auto const& c: _switch.cases)
+ {
+ if (!c.value)
+ hasDefault = true;
+ branches.emplace_back(*this);
+ branches.back()(c.body);
+ }
+
+ if (hasDefault)
+ {
+ *this = std::move(branches.back());
+ branches.pop_back();
+ }
+ for (auto& branch: branches)
+ join(branch);
+}
+
+void RedundantAssignEliminator::operator()(FunctionDefinition const& _functionDefinition)
+{
+ (*this)(_functionDefinition.body);
+
+ for (auto const& param: _functionDefinition.parameters)
+ changeUndecidedTo(param.name, State::Unused);
+ for (auto const& retParam: _functionDefinition.returnVariables)
+ changeUndecidedTo(retParam.name, State::Used);
+}
+
+void RedundantAssignEliminator::operator()(ForLoop const& _forLoop)
+{
+ // This will set all variables that are declared in this
+ // block to "unused" when it is destroyed.
+ BlockScope scope(*this);
+
+ // We need to visit the statements directly because of the
+ // scoping rules.
+ walkVector(_forLoop.pre.statements);
+
+ // We just run the loop twice to account for the
+ // back edge.
+ // There need not be more runs because we only have three different states.
+
+ visit(*_forLoop.condition);
+
+ RedundantAssignEliminator zeroRuns{*this};
+
+ (*this)(_forLoop.body);
+ (*this)(_forLoop.post);
+
+ visit(*_forLoop.condition);
+
+ RedundantAssignEliminator oneRun{*this};
+
+ (*this)(_forLoop.body);
+ (*this)(_forLoop.post);
+
+ visit(*_forLoop.condition);
+
+ // Order does not matter because "max" is commutative and associative.
+ join(oneRun);
+ join(zeroRuns);
+}
+
+void RedundantAssignEliminator::operator()(Block const& _block)
+{
+ // This will set all variables that are declared in this
+ // block to "unused" when it is destroyed.
+ BlockScope scope(*this);
+
+ ASTWalker::operator()(_block);
+}
+
+void RedundantAssignEliminator::run(Block& _ast)
+{
+ RedundantAssignEliminator rae;
+ rae(_ast);
+
+ std::set<Assignment const*> assignmentsToRemove;
+ for (auto const& variables: rae.m_assignments)
+ for (auto const& assignment: variables.second)
+ {
+ assertThrow(assignment.second != State::Undecided, OptimizerException, "");
+ if (assignment.second == State::Unused && MovableChecker{*assignment.first->value}.movable())
+ assignmentsToRemove.insert(assignment.first);
+ }
+
+ AssignmentRemover remover{assignmentsToRemove};
+ remover(_ast);
+}
+
+void RedundantAssignEliminator::join(RedundantAssignEliminator& _other)
+{
+ for (auto& var: _other.m_assignments)
+ if (m_assignments.count(var.first))
+ {
+ map<Assignment const*, State>& assignmentsHere = m_assignments[var.first];
+ for (auto& assignment: var.second)
+ assignmentsHere[assignment.first].join(assignment.second);
+ }
+ else
+ m_assignments[var.first] = std::move(var.second);
+}
+
+void RedundantAssignEliminator::changeUndecidedTo(string const& _variable, RedundantAssignEliminator::State _newState)
+{
+ for (auto& assignment: m_assignments[_variable])
+ if (assignment.second == State{State::Undecided})
+ assignment.second = _newState;
+}
+
+void AssignmentRemover::operator()(Block& _block)
+{
+ boost::range::remove_erase_if(_block.statements, [=](Statement const& _statement) -> bool {
+ return _statement.type() == typeid(Assignment) && m_toRemove.count(&boost::get<Assignment>(_statement));
+ });
+
+ ASTModifier::operator()(_block);
+}
diff --git a/libyul/optimiser/RedundantAssignEliminator.h b/libyul/optimiser/RedundantAssignEliminator.h
new file mode 100644
index 00000000..52092138
--- /dev/null
+++ b/libyul/optimiser/RedundantAssignEliminator.h
@@ -0,0 +1,185 @@
+/*
+ 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/>.
+*/
+/**
+ * Optimiser component that removes assignments to variables that are not used
+ * until they go out of scope or are re-assigned.
+ */
+
+#pragma once
+
+#include <libyul/ASTDataForward.h>
+
+#include <libyul/optimiser/ASTWalker.h>
+
+#include <map>
+
+namespace dev
+{
+namespace yul
+{
+
+/**
+ * Optimiser component that removes assignments to variables that are not used
+ * until they go out of scope or are re-assigned. This component
+ * respects the control-flow and takes it into account for removal.
+ *
+ * Example:
+ *
+ * {
+ * let a
+ * a := 1
+ * a := 2
+ * b := 2
+ * if calldataload(0)
+ * {
+ * b := mload(a)
+ * }
+ * a := b
+ * }
+ *
+ * In the example, "a := 1" can be removed because the value from this assignment
+ * is not used in any control-flow branch (it is replaced right away).
+ * The assignment "a := 2" is also overwritten by "a := b" at the end,
+ * but there is a control-flow path (through the condition body) which uses
+ * the value from "a := 2" and thus, this assignment cannot be removed.
+ *
+ * Detailed rules:
+ *
+ * The AST is traversed twice: in an information gathering step and in the
+ * actual removal step. During information gathering, we maintain a
+ * mapping from assignment statements to the three states
+ * "unused", "undecided" and "used".
+ * When an assignment is visited, it is added to the mapping in the "undecided" state
+ * (see remark about for loops below) and every other assignment to the same variable
+ * that is still in the "undecided" state is changed to "unused".
+ * When a variable is referenced, the state of any assignment to that variable still
+ * in the "undecided" state is changed to "used".
+ * At points where control flow splits, a copy
+ * of the mapping is handed over to each branch. At points where control flow
+ * joins, the two mappings coming from the two branches are combined in the following way:
+ * Statements that are only in one mapping or have the same state are used unchanged.
+ * Conflicting values are resolved in the following way:
+ * "unused", "undecided" -> "undecided"
+ * "unused", "used" -> "used"
+ * "undecided, "used" -> "used".
+ *
+ * For for-loops, the condition, body and post-part are visited twice, taking
+ * the joining control-flow at the condition into account.
+ * In other words, we create three control flow paths: Zero runs of the loop,
+ * one run and two runs and then combine them at the end.
+ * Running at most twice is enough because there are only three different states.
+ *
+ * For switch statements that have a "default"-case, there is no control-flow
+ * part that skips the switch.
+ *
+ * When a variable goes out of scope, all statements still in the "undecided"
+ * state are changed to "unused", unless the variable is the return
+ * parameter of a function - there, the state changes to "used".
+ *
+ * In the second traversal, all assignments that are in the "unused" state are removed.
+ *
+ *
+ * This step is usually run right after the SSA transform to complete
+ * the generation of the pseudo-SSA.
+ *
+ * Prerequisite: Disambiguator.
+ */
+class RedundantAssignEliminator: public ASTWalker
+{
+public:
+ RedundantAssignEliminator(RedundantAssignEliminator const&) = default;
+ RedundantAssignEliminator& operator=(RedundantAssignEliminator const&) = default;
+ RedundantAssignEliminator(RedundantAssignEliminator&&) = default;
+ RedundantAssignEliminator& operator=(RedundantAssignEliminator&&) = default;
+
+ void operator()(Identifier const& _identifier) override;
+ void operator()(VariableDeclaration const& _variableDeclaration) override;
+ void operator()(Assignment const& _assignment) override;
+ void operator()(If const& _if) override;
+ void operator()(Switch const& _switch) override;
+ void operator()(FunctionDefinition const&) override;
+ void operator()(ForLoop const&) override;
+ void operator()(Block const& _block) override;
+
+ static void run(Block& _ast);
+
+private:
+ RedundantAssignEliminator() {}
+
+ class State
+ {
+ public:
+ enum Value { Unused, Undecided, Used };
+ State(Value _value = Undecided): m_value(_value) {}
+ bool operator==(State _other) const { return m_value == _other.m_value; }
+ bool operator!=(State _other) const { return !operator==(_other); }
+ void join(State _other)
+ {
+ // Using "max" works here because of the order of the values in the enum.
+ m_value = Value(std::max(int(_other.m_value), int(m_value)));
+ }
+ private:
+ Value m_value = Undecided;
+ };
+
+ /**
+ * Takes care about storing the list of declared variables and
+ * sets them to "unused" when it is destroyed.
+ */
+ class BlockScope
+ {
+ public:
+ explicit BlockScope(RedundantAssignEliminator& _rae): m_rae(_rae)
+ {
+ swap(m_rae.m_declaredVariables, m_outerDeclaredVariables);
+ }
+ ~BlockScope()
+ {
+ for (auto const& var: m_rae.m_declaredVariables)
+ m_rae.changeUndecidedTo(var, State::Unused);
+ swap(m_rae.m_declaredVariables, m_outerDeclaredVariables);
+ }
+
+ private:
+ RedundantAssignEliminator& m_rae;
+ std::set<std::string> m_outerDeclaredVariables;
+ };
+
+ /// Joins the assignment mapping with @a _other according to the rules laid out
+ /// above.
+ /// Will destroy @a _other.
+ void join(RedundantAssignEliminator& _other);
+ void changeUndecidedTo(std::string const& _variable, State _newState);
+
+ std::set<std::string> m_declaredVariables;
+ std::map<std::string, std::map<Assignment const*, State>> m_assignments;
+};
+
+class AssignmentRemover: public ASTModifier
+{
+public:
+ explicit AssignmentRemover(std::set<Assignment const*> const& _toRemove):
+ m_toRemove(_toRemove)
+ {}
+ void operator()(Block& _block) override;
+
+private:
+ std::set<Assignment const*> const& m_toRemove;
+};
+
+}
+}
diff --git a/libyul/optimiser/Suite.cpp b/libyul/optimiser/Suite.cpp
new file mode 100644
index 00000000..5b325afd
--- /dev/null
+++ b/libyul/optimiser/Suite.cpp
@@ -0,0 +1,113 @@
+/*
+ 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/>.
+*/
+/**
+ * Optimiser suite that combines all steps and also provides the settings for the heuristics.
+ */
+
+#include <libyul/optimiser/Suite.h>
+
+#include <libyul/optimiser/Disambiguator.h>
+#include <libyul/optimiser/FunctionGrouper.h>
+#include <libyul/optimiser/FunctionHoister.h>
+#include <libyul/optimiser/ExpressionSplitter.h>
+#include <libyul/optimiser/ExpressionJoiner.h>
+#include <libyul/optimiser/ExpressionInliner.h>
+#include <libyul/optimiser/FullInliner.h>
+#include <libyul/optimiser/Rematerialiser.h>
+#include <libyul/optimiser/UnusedPruner.h>
+#include <libyul/optimiser/ExpressionSimplifier.h>
+#include <libyul/optimiser/CommonSubexpressionEliminator.h>
+#include <libyul/optimiser/SSATransform.h>
+#include <libyul/optimiser/RedundantAssignEliminator.h>
+
+#include <libsolidity/inlineasm/AsmAnalysisInfo.h>
+#include <libsolidity/inlineasm/AsmData.h>
+
+#include <libsolidity/inlineasm/AsmPrinter.h>
+
+#include <libdevcore/CommonData.h>
+
+using namespace std;
+using namespace dev;
+using namespace dev::yul;
+
+void OptimiserSuite::run(
+ Block& _ast,
+ solidity::assembly::AsmAnalysisInfo const& _analysisInfo,
+ set<string> const& _externallyUsedIdentifiers
+)
+{
+ set<string> reservedIdentifiers = _externallyUsedIdentifiers;
+
+ Block ast = boost::get<Block>(Disambiguator(_analysisInfo, reservedIdentifiers)(_ast));
+
+ (FunctionHoister{})(ast);
+ (FunctionGrouper{})(ast);
+
+ NameDispenser dispenser{ast};
+
+ for (size_t i = 0; i < 4; i++)
+ {
+ ExpressionSplitter{dispenser}(ast);
+ SSATransform::run(ast, dispenser);
+ RedundantAssignEliminator::run(ast);
+ RedundantAssignEliminator::run(ast);
+
+ CommonSubexpressionEliminator{}(ast);
+ ExpressionSimplifier::run(ast);
+ SSATransform::run(ast, dispenser);
+ RedundantAssignEliminator::run(ast);
+ RedundantAssignEliminator::run(ast);
+ UnusedPruner::runUntilStabilised(ast, reservedIdentifiers);
+ CommonSubexpressionEliminator{}(ast);
+ UnusedPruner::runUntilStabilised(ast, reservedIdentifiers);
+ SSATransform::run(ast, dispenser);
+ RedundantAssignEliminator::run(ast);
+ RedundantAssignEliminator::run(ast);
+
+ ExpressionJoiner::run(ast);
+ ExpressionJoiner::run(ast);
+ ExpressionInliner(ast).run();
+ UnusedPruner::runUntilStabilised(ast);
+
+ ExpressionSplitter{dispenser}(ast);
+ SSATransform::run(ast, dispenser);
+ RedundantAssignEliminator::run(ast);
+ RedundantAssignEliminator::run(ast);
+ CommonSubexpressionEliminator{}(ast);
+ FullInliner{ast, dispenser}.run();
+ SSATransform::run(ast, dispenser);
+ RedundantAssignEliminator::run(ast);
+ RedundantAssignEliminator::run(ast);
+ ExpressionSimplifier::run(ast);
+ CommonSubexpressionEliminator{}(ast);
+ SSATransform::run(ast, dispenser);
+ RedundantAssignEliminator::run(ast);
+ RedundantAssignEliminator::run(ast);
+ UnusedPruner::runUntilStabilised(ast, reservedIdentifiers);
+ }
+ ExpressionJoiner::run(ast);
+ UnusedPruner::runUntilStabilised(ast);
+ ExpressionJoiner::run(ast);
+ UnusedPruner::runUntilStabilised(ast);
+ ExpressionJoiner::run(ast);
+ UnusedPruner::runUntilStabilised(ast);
+ ExpressionJoiner::run(ast);
+ UnusedPruner::runUntilStabilised(ast);
+
+ _ast = std::move(ast);
+}
diff --git a/libyul/optimiser/Suite.h b/libyul/optimiser/Suite.h
new file mode 100644
index 00000000..bb6274bd
--- /dev/null
+++ b/libyul/optimiser/Suite.h
@@ -0,0 +1,55 @@
+/*
+ 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/>.
+*/
+/**
+ * Optimiser suite that combines all steps and also provides the settings for the heuristics.
+ */
+
+#pragma once
+
+#include <libyul/ASTDataForward.h>
+
+#include <string>
+#include <map>
+#include <set>
+
+namespace dev
+{
+namespace solidity
+{
+namespace assembly
+{
+struct AsmAnalysisInfo;
+}
+}
+namespace yul
+{
+
+/**
+ * Optimiser suite that combines all steps and also provides the settings for the heuristics
+ */
+class OptimiserSuite
+{
+public:
+ static void run(
+ Block& _ast,
+ solidity::assembly::AsmAnalysisInfo const& _analysisInfo,
+ std::set<std::string> const& _externallyUsedIdentifiers = std::set<std::string>()
+ );
+};
+
+}
+}
diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh
index a8261693..b0b545f3 100755
--- a/test/cmdlineTests.sh
+++ b/test/cmdlineTests.sh
@@ -184,8 +184,6 @@ do
then
echo " - $dir"
cd "$dir"
- # Replace version pragmas
- find . -name '*.sol' -type f -print0 | xargs -0 sed -i -e 's/pragma solidity [\^0-9\.]*/pragma solidity >=0.0/'
compileFull -w *.sol */*.sol
cd ..
fi
diff --git a/test/compilationTests/MultiSigWallet/MultiSigWallet.sol b/test/compilationTests/MultiSigWallet/MultiSigWallet.sol
index dc6e98e4..78194b7b 100644
--- a/test/compilationTests/MultiSigWallet/MultiSigWallet.sol
+++ b/test/compilationTests/MultiSigWallet/MultiSigWallet.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.4;
+pragma solidity >=0.0;
/// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution.
diff --git a/test/compilationTests/MultiSigWallet/MultiSigWalletFactory.sol b/test/compilationTests/MultiSigWallet/MultiSigWalletFactory.sol
index 8d0c1a3f..00c165ea 100644
--- a/test/compilationTests/MultiSigWallet/MultiSigWalletFactory.sol
+++ b/test/compilationTests/MultiSigWallet/MultiSigWalletFactory.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.4;
+pragma solidity >=0.0;
import "Factory.sol";
import "MultiSigWallet.sol";
diff --git a/test/compilationTests/MultiSigWallet/MultiSigWalletWithDailyLimit.sol b/test/compilationTests/MultiSigWallet/MultiSigWalletWithDailyLimit.sol
index df2a1400..fc0a3bc5 100644
--- a/test/compilationTests/MultiSigWallet/MultiSigWalletWithDailyLimit.sol
+++ b/test/compilationTests/MultiSigWallet/MultiSigWalletWithDailyLimit.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.4;
+pragma solidity >=0.0;
import "MultiSigWallet.sol";
diff --git a/test/compilationTests/MultiSigWallet/MultiSigWalletWithDailyLimitFactory.sol b/test/compilationTests/MultiSigWallet/MultiSigWalletWithDailyLimitFactory.sol
index f897d938..4a038864 100644
--- a/test/compilationTests/MultiSigWallet/MultiSigWalletWithDailyLimitFactory.sol
+++ b/test/compilationTests/MultiSigWallet/MultiSigWalletWithDailyLimitFactory.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.4;
+pragma solidity >=0.0;
import "Factory.sol";
import "MultiSigWalletWithDailyLimit.sol";
diff --git a/test/compilationTests/MultiSigWallet/TestToken.sol b/test/compilationTests/MultiSigWallet/TestToken.sol
index a100b449..c9dd64f7 100644
--- a/test/compilationTests/MultiSigWallet/TestToken.sol
+++ b/test/compilationTests/MultiSigWallet/TestToken.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.4;
+pragma solidity >=0.0;
/// @title Test token contract - Allows testing of token transfers with multisig wallet.
diff --git a/test/compilationTests/corion/announcementTypes.sol b/test/compilationTests/corion/announcementTypes.sol
index 94f4a9dc..1619e182 100644
--- a/test/compilationTests/corion/announcementTypes.sol
+++ b/test/compilationTests/corion/announcementTypes.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
contract announcementTypes {
diff --git a/test/compilationTests/corion/ico.sol b/test/compilationTests/corion/ico.sol
index e660389b..c550fbef 100644
--- a/test/compilationTests/corion/ico.sol
+++ b/test/compilationTests/corion/ico.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "./safeMath.sol";
import "./token.sol";
diff --git a/test/compilationTests/corion/module.sol b/test/compilationTests/corion/module.sol
index bd6952b1..f663d9c2 100644
--- a/test/compilationTests/corion/module.sol
+++ b/test/compilationTests/corion/module.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
contract abstractModuleHandler {
function transfer(address payable from, address payable to, uint256 value, bool fee) external returns (bool success) {}
diff --git a/test/compilationTests/corion/moduleHandler.sol b/test/compilationTests/corion/moduleHandler.sol
index 6b0daf0d..76061a31 100644
--- a/test/compilationTests/corion/moduleHandler.sol
+++ b/test/compilationTests/corion/moduleHandler.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "./module.sol";
import "./announcementTypes.sol";
diff --git a/test/compilationTests/corion/multiOwner.sol b/test/compilationTests/corion/multiOwner.sol
index efda554a..b61289dd 100644
--- a/test/compilationTests/corion/multiOwner.sol
+++ b/test/compilationTests/corion/multiOwner.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "./safeMath.sol";
diff --git a/test/compilationTests/corion/owned.sol b/test/compilationTests/corion/owned.sol
index f5a11c44..f273e3b5 100644
--- a/test/compilationTests/corion/owned.sol
+++ b/test/compilationTests/corion/owned.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
contract ownedDB {
address private owner;
diff --git a/test/compilationTests/corion/premium.sol b/test/compilationTests/corion/premium.sol
index 4952a740..091e291a 100644
--- a/test/compilationTests/corion/premium.sol
+++ b/test/compilationTests/corion/premium.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "./safeMath.sol";
import "./tokenDB.sol";
diff --git a/test/compilationTests/corion/provider.sol b/test/compilationTests/corion/provider.sol
index b3b5e8ca..48ec3adb 100644
--- a/test/compilationTests/corion/provider.sol
+++ b/test/compilationTests/corion/provider.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "./module.sol";
import "./moduleHandler.sol";
diff --git a/test/compilationTests/corion/publisher.sol b/test/compilationTests/corion/publisher.sol
index 48090d02..991fc8f4 100644
--- a/test/compilationTests/corion/publisher.sol
+++ b/test/compilationTests/corion/publisher.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "./announcementTypes.sol";
import "./module.sol";
diff --git a/test/compilationTests/corion/safeMath.sol b/test/compilationTests/corion/safeMath.sol
index a6680f27..3e7e5578 100644
--- a/test/compilationTests/corion/safeMath.sol
+++ b/test/compilationTests/corion/safeMath.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
contract safeMath {
function safeAdd(uint256 a, uint256 b) internal returns(uint256) {
diff --git a/test/compilationTests/corion/schelling.sol b/test/compilationTests/corion/schelling.sol
index 2a327ba0..e70716bd 100644
--- a/test/compilationTests/corion/schelling.sol
+++ b/test/compilationTests/corion/schelling.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "./announcementTypes.sol";
import "./module.sol";
diff --git a/test/compilationTests/corion/token.sol b/test/compilationTests/corion/token.sol
index f55dc9e6..6ab22530 100644
--- a/test/compilationTests/corion/token.sol
+++ b/test/compilationTests/corion/token.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "./announcementTypes.sol";
import "./safeMath.sol";
diff --git a/test/compilationTests/corion/tokenDB.sol b/test/compilationTests/corion/tokenDB.sol
index 1632a89b..a77a1efa 100644
--- a/test/compilationTests/corion/tokenDB.sol
+++ b/test/compilationTests/corion/tokenDB.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "./safeMath.sol";
import "./owned.sol";
diff --git a/test/compilationTests/gnosis/Events/CategoricalEvent.sol b/test/compilationTests/gnosis/Events/CategoricalEvent.sol
index 4815e315..0d6d1b45 100644
--- a/test/compilationTests/gnosis/Events/CategoricalEvent.sol
+++ b/test/compilationTests/gnosis/Events/CategoricalEvent.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Events/Event.sol";
diff --git a/test/compilationTests/gnosis/Events/Event.sol b/test/compilationTests/gnosis/Events/Event.sol
index 0a40cf7e..b11dd15d 100644
--- a/test/compilationTests/gnosis/Events/Event.sol
+++ b/test/compilationTests/gnosis/Events/Event.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Tokens/Token.sol";
import "../Tokens/OutcomeToken.sol";
import "../Oracles/Oracle.sol";
diff --git a/test/compilationTests/gnosis/Events/EventFactory.sol b/test/compilationTests/gnosis/Events/EventFactory.sol
index cfe772ec..4f4efe35 100644
--- a/test/compilationTests/gnosis/Events/EventFactory.sol
+++ b/test/compilationTests/gnosis/Events/EventFactory.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Events/CategoricalEvent.sol";
import "../Events/ScalarEvent.sol";
diff --git a/test/compilationTests/gnosis/Events/ScalarEvent.sol b/test/compilationTests/gnosis/Events/ScalarEvent.sol
index 832c2ab1..325f4302 100644
--- a/test/compilationTests/gnosis/Events/ScalarEvent.sol
+++ b/test/compilationTests/gnosis/Events/ScalarEvent.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Events/Event.sol";
diff --git a/test/compilationTests/gnosis/MarketMakers/LMSRMarketMaker.sol b/test/compilationTests/gnosis/MarketMakers/LMSRMarketMaker.sol
index 4ad285eb..c305d168 100644
--- a/test/compilationTests/gnosis/MarketMakers/LMSRMarketMaker.sol
+++ b/test/compilationTests/gnosis/MarketMakers/LMSRMarketMaker.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Utils/Math.sol";
import "../MarketMakers/MarketMaker.sol";
diff --git a/test/compilationTests/gnosis/MarketMakers/MarketMaker.sol b/test/compilationTests/gnosis/MarketMakers/MarketMaker.sol
index ef5942cd..f61cdba8 100644
--- a/test/compilationTests/gnosis/MarketMakers/MarketMaker.sol
+++ b/test/compilationTests/gnosis/MarketMakers/MarketMaker.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Markets/Market.sol";
diff --git a/test/compilationTests/gnosis/Markets/Campaign.sol b/test/compilationTests/gnosis/Markets/Campaign.sol
index 119f8df2..b16d102c 100644
--- a/test/compilationTests/gnosis/Markets/Campaign.sol
+++ b/test/compilationTests/gnosis/Markets/Campaign.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Events/Event.sol";
import "../Markets/StandardMarketFactory.sol";
import "../Utils/Math.sol";
diff --git a/test/compilationTests/gnosis/Markets/CampaignFactory.sol b/test/compilationTests/gnosis/Markets/CampaignFactory.sol
index d80d7d63..c7afeded 100644
--- a/test/compilationTests/gnosis/Markets/CampaignFactory.sol
+++ b/test/compilationTests/gnosis/Markets/CampaignFactory.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Markets/Campaign.sol";
diff --git a/test/compilationTests/gnosis/Markets/Market.sol b/test/compilationTests/gnosis/Markets/Market.sol
index 7bcecfe5..963c2c94 100644
--- a/test/compilationTests/gnosis/Markets/Market.sol
+++ b/test/compilationTests/gnosis/Markets/Market.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Events/Event.sol";
import "../MarketMakers/MarketMaker.sol";
diff --git a/test/compilationTests/gnosis/Markets/MarketFactory.sol b/test/compilationTests/gnosis/Markets/MarketFactory.sol
index d368e8db..40d80db6 100644
--- a/test/compilationTests/gnosis/Markets/MarketFactory.sol
+++ b/test/compilationTests/gnosis/Markets/MarketFactory.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Events/Event.sol";
import "../MarketMakers/MarketMaker.sol";
import "../Markets/Market.sol";
diff --git a/test/compilationTests/gnosis/Markets/StandardMarket.sol b/test/compilationTests/gnosis/Markets/StandardMarket.sol
index 2f52a896..99648c90 100644
--- a/test/compilationTests/gnosis/Markets/StandardMarket.sol
+++ b/test/compilationTests/gnosis/Markets/StandardMarket.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Markets/Market.sol";
import "../Tokens/Token.sol";
import "../Events/Event.sol";
diff --git a/test/compilationTests/gnosis/Markets/StandardMarketFactory.sol b/test/compilationTests/gnosis/Markets/StandardMarketFactory.sol
index 88dcbe79..7245da89 100644
--- a/test/compilationTests/gnosis/Markets/StandardMarketFactory.sol
+++ b/test/compilationTests/gnosis/Markets/StandardMarketFactory.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Markets/MarketFactory.sol";
import "../Markets/StandardMarket.sol";
diff --git a/test/compilationTests/gnosis/Migrations.sol b/test/compilationTests/gnosis/Migrations.sol
index f1a3ea9d..396e3649 100644
--- a/test/compilationTests/gnosis/Migrations.sol
+++ b/test/compilationTests/gnosis/Migrations.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.4;
+pragma solidity >=0.0;
contract Migrations {
address public owner;
diff --git a/test/compilationTests/gnosis/Oracles/CentralizedOracle.sol b/test/compilationTests/gnosis/Oracles/CentralizedOracle.sol
index e175dfdb..ee0d50a3 100644
--- a/test/compilationTests/gnosis/Oracles/CentralizedOracle.sol
+++ b/test/compilationTests/gnosis/Oracles/CentralizedOracle.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Oracles/Oracle.sol";
diff --git a/test/compilationTests/gnosis/Oracles/CentralizedOracleFactory.sol b/test/compilationTests/gnosis/Oracles/CentralizedOracleFactory.sol
index be632070..649aaee5 100644
--- a/test/compilationTests/gnosis/Oracles/CentralizedOracleFactory.sol
+++ b/test/compilationTests/gnosis/Oracles/CentralizedOracleFactory.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Oracles/CentralizedOracle.sol";
diff --git a/test/compilationTests/gnosis/Oracles/DifficultyOracle.sol b/test/compilationTests/gnosis/Oracles/DifficultyOracle.sol
index 3d801da1..c1b43235 100644
--- a/test/compilationTests/gnosis/Oracles/DifficultyOracle.sol
+++ b/test/compilationTests/gnosis/Oracles/DifficultyOracle.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Oracles/Oracle.sol";
diff --git a/test/compilationTests/gnosis/Oracles/DifficultyOracleFactory.sol b/test/compilationTests/gnosis/Oracles/DifficultyOracleFactory.sol
index fc5dcc3b..e04f904a 100644
--- a/test/compilationTests/gnosis/Oracles/DifficultyOracleFactory.sol
+++ b/test/compilationTests/gnosis/Oracles/DifficultyOracleFactory.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Oracles/DifficultyOracle.sol";
diff --git a/test/compilationTests/gnosis/Oracles/FutarchyOracle.sol b/test/compilationTests/gnosis/Oracles/FutarchyOracle.sol
index 83d10b2e..ad56dcdc 100644
--- a/test/compilationTests/gnosis/Oracles/FutarchyOracle.sol
+++ b/test/compilationTests/gnosis/Oracles/FutarchyOracle.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Oracles/Oracle.sol";
import "../Events/EventFactory.sol";
import "../Markets/MarketFactory.sol";
diff --git a/test/compilationTests/gnosis/Oracles/FutarchyOracleFactory.sol b/test/compilationTests/gnosis/Oracles/FutarchyOracleFactory.sol
index 3c6e5c15..87bdf54b 100644
--- a/test/compilationTests/gnosis/Oracles/FutarchyOracleFactory.sol
+++ b/test/compilationTests/gnosis/Oracles/FutarchyOracleFactory.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Oracles/FutarchyOracle.sol";
diff --git a/test/compilationTests/gnosis/Oracles/MajorityOracle.sol b/test/compilationTests/gnosis/Oracles/MajorityOracle.sol
index 4dc1760d..6913713b 100644
--- a/test/compilationTests/gnosis/Oracles/MajorityOracle.sol
+++ b/test/compilationTests/gnosis/Oracles/MajorityOracle.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Oracles/Oracle.sol";
diff --git a/test/compilationTests/gnosis/Oracles/MajorityOracleFactory.sol b/test/compilationTests/gnosis/Oracles/MajorityOracleFactory.sol
index dbbccc4c..a4845a36 100644
--- a/test/compilationTests/gnosis/Oracles/MajorityOracleFactory.sol
+++ b/test/compilationTests/gnosis/Oracles/MajorityOracleFactory.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Oracles/MajorityOracle.sol";
diff --git a/test/compilationTests/gnosis/Oracles/Oracle.sol b/test/compilationTests/gnosis/Oracles/Oracle.sol
index 450aff00..835d889e 100644
--- a/test/compilationTests/gnosis/Oracles/Oracle.sol
+++ b/test/compilationTests/gnosis/Oracles/Oracle.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
/// @title Abstract oracle contract - Functions to be implemented by oracles
diff --git a/test/compilationTests/gnosis/Oracles/SignedMessageOracle.sol b/test/compilationTests/gnosis/Oracles/SignedMessageOracle.sol
index 284f420e..900067cd 100644
--- a/test/compilationTests/gnosis/Oracles/SignedMessageOracle.sol
+++ b/test/compilationTests/gnosis/Oracles/SignedMessageOracle.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Oracles/Oracle.sol";
diff --git a/test/compilationTests/gnosis/Oracles/SignedMessageOracleFactory.sol b/test/compilationTests/gnosis/Oracles/SignedMessageOracleFactory.sol
index ea70b2aa..18617faa 100644
--- a/test/compilationTests/gnosis/Oracles/SignedMessageOracleFactory.sol
+++ b/test/compilationTests/gnosis/Oracles/SignedMessageOracleFactory.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Oracles/SignedMessageOracle.sol";
diff --git a/test/compilationTests/gnosis/Oracles/UltimateOracle.sol b/test/compilationTests/gnosis/Oracles/UltimateOracle.sol
index 452a34ec..d4574715 100644
--- a/test/compilationTests/gnosis/Oracles/UltimateOracle.sol
+++ b/test/compilationTests/gnosis/Oracles/UltimateOracle.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Oracles/Oracle.sol";
import "../Tokens/Token.sol";
import "../Utils/Math.sol";
diff --git a/test/compilationTests/gnosis/Oracles/UltimateOracleFactory.sol b/test/compilationTests/gnosis/Oracles/UltimateOracleFactory.sol
index 51f5610e..352872ac 100644
--- a/test/compilationTests/gnosis/Oracles/UltimateOracleFactory.sol
+++ b/test/compilationTests/gnosis/Oracles/UltimateOracleFactory.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Oracles/UltimateOracle.sol";
diff --git a/test/compilationTests/gnosis/Tokens/EtherToken.sol b/test/compilationTests/gnosis/Tokens/EtherToken.sol
index 32e64583..987b62c6 100644
--- a/test/compilationTests/gnosis/Tokens/EtherToken.sol
+++ b/test/compilationTests/gnosis/Tokens/EtherToken.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Tokens/StandardToken.sol";
diff --git a/test/compilationTests/gnosis/Tokens/OutcomeToken.sol b/test/compilationTests/gnosis/Tokens/OutcomeToken.sol
index fccf05e5..11f4ece1 100644
--- a/test/compilationTests/gnosis/Tokens/OutcomeToken.sol
+++ b/test/compilationTests/gnosis/Tokens/OutcomeToken.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Tokens/StandardToken.sol";
diff --git a/test/compilationTests/gnosis/Tokens/StandardToken.sol b/test/compilationTests/gnosis/Tokens/StandardToken.sol
index 5fb20210..09916cc1 100644
--- a/test/compilationTests/gnosis/Tokens/StandardToken.sol
+++ b/test/compilationTests/gnosis/Tokens/StandardToken.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
import "../Tokens/Token.sol";
import "../Utils/Math.sol";
diff --git a/test/compilationTests/gnosis/Tokens/Token.sol b/test/compilationTests/gnosis/Tokens/Token.sol
index 70ecdff7..777a8d7c 100644
--- a/test/compilationTests/gnosis/Tokens/Token.sol
+++ b/test/compilationTests/gnosis/Tokens/Token.sol
@@ -1,5 +1,5 @@
/// Implements ERC 20 Token standard: https://github.com/ethereum/EIPs/issues/20
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
/// @title Abstract token contract - Functions to be implemented by token contracts
diff --git a/test/compilationTests/gnosis/Utils/Math.sol b/test/compilationTests/gnosis/Utils/Math.sol
index 47edcba4..2a741e53 100644
--- a/test/compilationTests/gnosis/Utils/Math.sol
+++ b/test/compilationTests/gnosis/Utils/Math.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.11;
+pragma solidity >=0.0;
/// @title Math library - Allows calculation of logarithmic and exponential functions
diff --git a/test/compilationTests/milestonetracker/MilestoneTracker.sol b/test/compilationTests/milestonetracker/MilestoneTracker.sol
index 41fa7404..891afcb1 100644
--- a/test/compilationTests/milestonetracker/MilestoneTracker.sol
+++ b/test/compilationTests/milestonetracker/MilestoneTracker.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.6;
+pragma solidity >=0.0;
/*
Copyright 2016, Jordi Baylina
diff --git a/test/compilationTests/milestonetracker/RLP.sol b/test/compilationTests/milestonetracker/RLP.sol
index 75e3902e..799233a1 100644
--- a/test/compilationTests/milestonetracker/RLP.sol
+++ b/test/compilationTests/milestonetracker/RLP.sol
@@ -1,4 +1,4 @@
-pragma solidity ^0.4.6;
+pragma solidity >=0.0;
/**
* @title RLPReader
diff --git a/test/compilationTests/stringutils/strings.sol b/test/compilationTests/stringutils/strings.sol
index f89a2527..9e0518a7 100644
--- a/test/compilationTests/stringutils/strings.sol
+++ b/test/compilationTests/stringutils/strings.sol
@@ -34,7 +34,7 @@
* corresponding to the left and right parts of the string.
*/
-pragma solidity ^0.4.14;
+pragma solidity >=0.0;
library strings {
struct slice {
diff --git a/test/compilationTests/zeppelin/Bounty.sol b/test/compilationTests/zeppelin/Bounty.sol
deleted file mode 100644
index d45e130c..00000000
--- a/test/compilationTests/zeppelin/Bounty.sol
+++ /dev/null
@@ -1,78 +0,0 @@
-pragma solidity ^0.4.11;
-
-
-import './payment/PullPayment.sol';
-import './lifecycle/Destructible.sol';
-
-
-/**
- * @title Bounty
- * @dev This bounty will pay out to a researcher if they break invariant logic of the contract.
- */
-contract Bounty is PullPayment, Destructible {
- bool public claimed;
- mapping(address => address) public researchers;
-
- event TargetCreated(address createdAddress);
-
- /**
- * @dev Fallback function allowing the contract to receive funds, if they haven't already been claimed.
- */
- function() external payable {
- if (claimed) {
- revert();
- }
- }
-
- /**
- * @dev Create and deploy the target contract (extension of Target contract), and sets the
- * msg.sender as a researcher
- * @return A target contract
- */
- function createTarget() public returns(Target) {
- Target target = Target(deployContract());
- researchers[address(target)] = msg.sender;
- emit TargetCreated(address(target));
- return target;
- }
-
- /**
- * @dev Internal function to deploy the target contract.
- * @return A target contract address
- */
- function deployContract() internal returns(address);
-
- /**
- * @dev Sends the contract funds to the researcher that proved the contract is broken.
- * @param target contract
- */
- function claim(Target target) public {
- address researcher = researchers[address(target)];
- if (researcher == address(0)) {
- revert();
- }
- // Check Target contract invariants
- if (target.checkInvariant()) {
- revert();
- }
- asyncSend(researcher, address(this).balance);
- claimed = true;
- }
-
-}
-
-
-/**
- * @title Target
- * @dev Your main contract should inherit from this class and implement the checkInvariant method.
- */
-contract Target {
-
- /**
- * @dev Checks all values a contract assumes to be true all the time. If this function returns
- * false, the contract is broken in some way and is in an inconsistent state.
- * In order to win the bounty, security researchers will try to cause this broken state.
- * @return True if all invariant values are correct, false otherwise.
- */
- function checkInvariant() public returns(bool);
-}
diff --git a/test/compilationTests/zeppelin/DayLimit.sol b/test/compilationTests/zeppelin/DayLimit.sol
deleted file mode 100644
index bc576c89..00000000
--- a/test/compilationTests/zeppelin/DayLimit.sol
+++ /dev/null
@@ -1,75 +0,0 @@
-pragma solidity ^0.4.11;
-
-/**
- * @title DayLimit
- * @dev Base contract that enables methods to be protected by placing a linear limit (specifiable)
- * on a particular resource per calendar day. Is multiowned to allow the limit to be altered.
- */
-contract DayLimit {
-
- uint256 public dailyLimit;
- uint256 public spentToday;
- uint256 public lastDay;
-
- /**
- * @dev Constructor that sets the passed value as a dailyLimit.
- * @param _limit uint256 to represent the daily limit.
- */
- constructor(uint256 _limit) public {
- dailyLimit = _limit;
- lastDay = today();
- }
-
- /**
- * @dev sets the daily limit. Does not alter the amount already spent today.
- * @param _newLimit uint256 to represent the new limit.
- */
- function _setDailyLimit(uint256 _newLimit) internal {
- dailyLimit = _newLimit;
- }
-
- /**
- * @dev Resets the amount already spent today.
- */
- function _resetSpentToday() internal {
- spentToday = 0;
- }
-
- /**
- * @dev Checks to see if there is enough resource to spend today. If true, the resource may be expended.
- * @param _value uint256 representing the amount of resource to spend.
- * @return A boolean that is True if the resource was spended and false otherwise.
- */
- function underLimit(uint256 _value) internal returns (bool) {
- // reset the spend limit if we're on a different day to last time.
- if (today() > lastDay) {
- spentToday = 0;
- lastDay = today();
- }
- // check to see if there's enough left - if so, subtract and return true.
- // overflow protection // dailyLimit check
- if (spentToday + _value >= spentToday && spentToday + _value <= dailyLimit) {
- spentToday += _value;
- return true;
- }
- return false;
- }
-
- /**
- * @dev Private function to determine today's index
- * @return uint256 of today's index.
- */
- function today() private view returns (uint256) {
- return now / 1 days;
- }
-
- /**
- * @dev Simple modifier for daily limit.
- */
- modifier limitedDaily(uint256 _value) {
- if (!underLimit(_value)) {
- revert();
- }
- _;
- }
-}
diff --git a/test/compilationTests/zeppelin/LICENSE b/test/compilationTests/zeppelin/LICENSE
deleted file mode 100644
index 85f53321..00000000
--- a/test/compilationTests/zeppelin/LICENSE
+++ /dev/null
@@ -1,22 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2016 Smart Contract Solutions, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be included
-in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/test/compilationTests/zeppelin/LimitBalance.sol b/test/compilationTests/zeppelin/LimitBalance.sol
deleted file mode 100644
index d07b3c2c..00000000
--- a/test/compilationTests/zeppelin/LimitBalance.sol
+++ /dev/null
@@ -1,33 +0,0 @@
-pragma solidity ^0.4.11;
-
-
-/**
- * @title LimitBalance
- * @dev Simple contract to limit the balance of child contract.
- * @dev Note this doesn't prevent other contracts to send funds by using selfdestruct(address);
- * @dev See: https://github.com/ConsenSys/smart-contract-best-practices#remember-that-ether-can-be-forcibly-sent-to-an-account
- */
-contract LimitBalance {
-
- uint256 public limit;
-
- /**
- * @dev Constructor that sets the passed value as a limit.
- * @param _limit uint256 to represent the limit.
- */
- constructor(uint256 _limit) public {
- limit = _limit;
- }
-
- /**
- * @dev Checks if limit was reached. Case true, it throws.
- */
- modifier limitedPayable() {
- if (address(this).balance > limit) {
- revert();
- }
- _;
-
- }
-
-}
diff --git a/test/compilationTests/zeppelin/MultisigWallet.sol b/test/compilationTests/zeppelin/MultisigWallet.sol
deleted file mode 100644
index 74a54c7f..00000000
--- a/test/compilationTests/zeppelin/MultisigWallet.sol
+++ /dev/null
@@ -1,125 +0,0 @@
-pragma solidity ^0.4.11;
-
-
-import "./ownership/Multisig.sol";
-import "./ownership/Shareable.sol";
-import "./DayLimit.sol";
-
-
-/**
- * MultisigWallet
- * Usage:
- * bytes32 h = Wallet(w).from(oneOwner).execute(to, value, data);
- * Wallet(w).from(anotherOwner).confirm(h);
- */
-contract MultisigWallet is Multisig, Shareable, DayLimit {
-
- struct Transaction {
- address to;
- uint256 value;
- bytes data;
- }
-
- /**
- * Constructor, sets the owners addresses, number of approvals required, and daily spending limit
- * @param _owners A list of owners.
- * @param _required The amount required for a transaction to be approved.
- */
- constructor(address[] memory _owners, uint256 _required, uint256 _daylimit)
- Shareable(_owners, _required)
- DayLimit(_daylimit) public { }
-
- /**
- * @dev destroys the contract sending everything to `_to`.
- */
- function destroy(address payable _to) onlymanyowners(keccak256(msg.data)) external {
- selfdestruct(_to);
- }
-
- /**
- * @dev Fallback function, receives value and emits a deposit event.
- */
- function() external payable {
- // just being sent some cash?
- if (msg.value > 0)
- emit Deposit(msg.sender, msg.value);
- }
-
- /**
- * @dev Outside-visible transaction entry point. Executes transaction immediately if below daily
- * spending limit. If not, goes into multisig process. We provide a hash on return to allow the
- * sender to provide shortcuts for the other confirmations (allowing them to avoid replicating
- * the _to, _value, and _data arguments). They still get the option of using them if they want,
- * anyways.
- * @param _to The receiver address
- * @param _value The value to send
- * @param _data The data part of the transaction
- */
- function execute(address _to, uint256 _value, bytes calldata _data) external onlyOwner returns (bytes32 _r) {
- // first, take the opportunity to check that we're under the daily limit.
- if (underLimit(_value)) {
- emit SingleTransact(msg.sender, _value, _to, _data);
- // yes - just execute the call.
- (bool success,) = _to.call.value(_value)(_data);
- require(success);
- return 0;
- }
- // determine our operation hash.
- _r = keccak256(abi.encodePacked(msg.data, block.number));
- if (!confirm(_r) && txs[_r].to == address(0)) {
- txs[_r].to = _to;
- txs[_r].value = _value;
- txs[_r].data = _data;
- emit ConfirmationNeeded(_r, msg.sender, _value, _to, _data);
- }
- }
-
- /**
- * @dev Confirm a transaction by providing just the hash. We use the previous transactions map,
- * txs, in order to determine the body of the transaction from the hash provided.
- * @param _h The transaction hash to approve.
- */
- function confirm(bytes32 _h) onlymanyowners(_h) public returns (bool) {
- if (txs[_h].to != address(0)) {
- (bool success,) = txs[_h].to.call.value(txs[_h].value)(txs[_h].data);
- require(success);
- emit MultiTransact(msg.sender, _h, txs[_h].value, txs[_h].to, txs[_h].data);
- delete txs[_h];
- return true;
- }
- }
-
- /**
- * @dev Updates the daily limit value.
- * @param _newLimit uint256 to represent the new limit.
- */
- function setDailyLimit(uint256 _newLimit) onlymanyowners(keccak256(msg.data)) external {
- _setDailyLimit(_newLimit);
- }
-
- /**
- * @dev Resets the value spent to enable more spending
- */
- function resetSpentToday() onlymanyowners(keccak256(msg.data)) external {
- _resetSpentToday();
- }
-
-
- // INTERNAL METHODS
- /**
- * @dev Clears the list of transactions pending approval.
- */
- function clearPending() internal {
- uint256 length = pendingsIndex.length;
- for (uint256 i = 0; i < length; ++i) {
- delete txs[pendingsIndex[i]];
- }
- super.clearPending();
- }
-
-
- // FIELDS
-
- // pending transactions we have at present.
- mapping (bytes32 => Transaction) txs;
-}
diff --git a/test/compilationTests/zeppelin/README.md b/test/compilationTests/zeppelin/README.md
deleted file mode 100644
index dee2f5ca..00000000
--- a/test/compilationTests/zeppelin/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Zeppelin contracts, originally from
-
-https://github.com/OpenZeppelin/zeppelin-solidity
diff --git a/test/compilationTests/zeppelin/ReentrancyGuard.sol b/test/compilationTests/zeppelin/ReentrancyGuard.sol
deleted file mode 100644
index f7abb698..00000000
--- a/test/compilationTests/zeppelin/ReentrancyGuard.sol
+++ /dev/null
@@ -1,34 +0,0 @@
-pragma solidity ^0.4.11;
-
-/**
- * @title Helps contracts guard against rentrancy attacks.
- * @author Remco Bloemen <remco@2Ï€.com>
- * @notice If you mark a function `nonReentrant`, you should also
- * mark it `external`.
- */
-contract ReentrancyGuard {
-
- /**
- * @dev We use a single lock for the whole contract.
- */
- bool private rentrancy_lock = false;
-
- /**
- * @dev Prevents a contract from calling itself, directly or indirectly.
- * @notice If you mark a function `nonReentrant`, you should also
- * mark it `external`. Calling one nonReentrant function from
- * another is not supported. Instead, you can implement a
- * `private` function doing the actual work, and a `external`
- * wrapper marked as `nonReentrant`.
- */
- modifier nonReentrant() {
- if(rentrancy_lock == false) {
- rentrancy_lock = true;
- _;
- rentrancy_lock = false;
- } else {
- revert();
- }
- }
-
-}
diff --git a/test/compilationTests/zeppelin/crowdsale/CappedCrowdsale.sol b/test/compilationTests/zeppelin/crowdsale/CappedCrowdsale.sol
deleted file mode 100644
index 98c8c3d4..00000000
--- a/test/compilationTests/zeppelin/crowdsale/CappedCrowdsale.sol
+++ /dev/null
@@ -1,33 +0,0 @@
-pragma solidity ^0.4.11;
-
-import '../math/SafeMath.sol';
-import './Crowdsale.sol';
-
-/**
- * @title CappedCrowdsale
- * @dev Extension of Crowsdale with a max amount of funds raised
- */
-contract CappedCrowdsale is Crowdsale {
- using SafeMath for uint256;
-
- uint256 public cap;
-
- constructor(uint256 _cap) public {
- cap = _cap;
- }
-
- // overriding Crowdsale#validPurchase to add extra cap logic
- // @return true if investors can buy at the moment
- function validPurchase() internal view returns (bool) {
- bool withinCap = weiRaised.add(msg.value) <= cap;
- return super.validPurchase() && withinCap;
- }
-
- // overriding Crowdsale#hasEnded to add cap logic
- // @return true if crowdsale event has ended
- function hasEnded() public view returns (bool) {
- bool capReached = weiRaised >= cap;
- return super.hasEnded() || capReached;
- }
-
-}
diff --git a/test/compilationTests/zeppelin/crowdsale/Crowdsale.sol b/test/compilationTests/zeppelin/crowdsale/Crowdsale.sol
deleted file mode 100644
index 612afc25..00000000
--- a/test/compilationTests/zeppelin/crowdsale/Crowdsale.sol
+++ /dev/null
@@ -1,108 +0,0 @@
-pragma solidity ^0.4.11;
-
-import '../token/MintableToken.sol';
-import '../math/SafeMath.sol';
-
-/**
- * @title Crowdsale
- * @dev Crowdsale is a base contract for managing a token crowdsale.
- * Crowdsales have a start and end block, where investors can make
- * token purchases and the crowdsale will assign them tokens based
- * on a token per ETH rate. Funds collected are forwarded to a wallet
- * as they arrive.
- */
-contract Crowdsale {
- using SafeMath for uint256;
-
- // The token being sold
- MintableToken public token;
-
- // start and end block where investments are allowed (both inclusive)
- uint256 public startBlock;
- uint256 public endBlock;
-
- // address where funds are collected
- address payable public wallet;
-
- // how many token units a buyer gets per wei
- uint256 public rate;
-
- // amount of raised money in wei
- uint256 public weiRaised;
-
- /**
- * event for token purchase logging
- * @param purchaser who paid for the tokens
- * @param beneficiary who got the tokens
- * @param value weis paid for purchase
- * @param amount amount of tokens purchased
- */
- event TokenPurchase(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount);
-
-
- constructor(uint256 _startBlock, uint256 _endBlock, uint256 _rate, address payable _wallet) public {
- require(_startBlock >= block.number);
- require(_endBlock >= _startBlock);
- require(_rate > 0);
- require(_wallet != address(0x0));
-
- token = createTokenContract();
- startBlock = _startBlock;
- endBlock = _endBlock;
- rate = _rate;
- wallet = _wallet;
- }
-
- // creates the token to be sold.
- // override this method to have crowdsale of a specific mintable token.
- function createTokenContract() internal returns (MintableToken) {
- return new MintableToken();
- }
-
-
- // fallback function can be used to buy tokens
- function () external payable {
- buyTokens(msg.sender);
- }
-
- // low level token purchase function
- function buyTokens(address beneficiary) public payable {
- require(beneficiary != address(0x0));
- require(validPurchase());
-
- uint256 weiAmount = msg.value;
- uint256 updatedWeiRaised = weiRaised.add(weiAmount);
-
- // calculate token amount to be created
- uint256 tokens = weiAmount.mul(rate);
-
- // update state
- weiRaised = updatedWeiRaised;
-
- token.mint(beneficiary, tokens);
- emit TokenPurchase(msg.sender, beneficiary, weiAmount, tokens);
-
- forwardFunds();
- }
-
- // send ether to the fund collection wallet
- // override to create custom fund forwarding mechanisms
- function forwardFunds() internal {
- wallet.transfer(msg.value);
- }
-
- // @return true if the transaction can buy tokens
- function validPurchase() internal view returns (bool) {
- uint256 current = block.number;
- bool withinPeriod = current >= startBlock && current <= endBlock;
- bool nonZeroPurchase = msg.value != 0;
- return withinPeriod && nonZeroPurchase;
- }
-
- // @return true if crowdsale event has ended
- function hasEnded() public view returns (bool) {
- return block.number > endBlock;
- }
-
-
-}
diff --git a/test/compilationTests/zeppelin/crowdsale/FinalizableCrowdsale.sol b/test/compilationTests/zeppelin/crowdsale/FinalizableCrowdsale.sol
deleted file mode 100644
index e94fc9fb..00000000
--- a/test/compilationTests/zeppelin/crowdsale/FinalizableCrowdsale.sol
+++ /dev/null
@@ -1,39 +0,0 @@
-pragma solidity ^0.4.11;
-
-import '../math/SafeMath.sol';
-import '../ownership/Ownable.sol';
-import './Crowdsale.sol';
-
-/**
- * @title FinalizableCrowdsale
- * @dev Extension of Crowsdale where an owner can do extra work
- * after finishing. By default, it will end token minting.
- */
-contract FinalizableCrowdsale is Crowdsale, Ownable {
- using SafeMath for uint256;
-
- bool public isFinalized = false;
-
- event Finalized();
-
- // should be called after crowdsale ends, to do
- // some extra finalization work
- function finalize() public onlyOwner {
- require(!isFinalized);
- require(hasEnded());
-
- finalization();
- emit Finalized();
-
- isFinalized = true;
- }
-
- // end token minting on finalization
- // override this with custom logic if needed
- function finalization() internal {
- token.finishMinting();
- }
-
-
-
-}
diff --git a/test/compilationTests/zeppelin/crowdsale/RefundVault.sol b/test/compilationTests/zeppelin/crowdsale/RefundVault.sol
deleted file mode 100644
index ef1d8061..00000000
--- a/test/compilationTests/zeppelin/crowdsale/RefundVault.sol
+++ /dev/null
@@ -1,56 +0,0 @@
-pragma solidity ^0.4.11;
-
-import '../math/SafeMath.sol';
-import '../ownership/Ownable.sol';
-
-/**
- * @title RefundVault
- * @dev This contract is used for storing funds while a crowdsale
- * is in progress. Supports refunding the money if crowdsale fails,
- * and forwarding it if crowdsale is successful.
- */
-contract RefundVault is Ownable {
- using SafeMath for uint256;
-
- enum State { Active, Refunding, Closed }
-
- mapping (address => uint256) public deposited;
- address payable public wallet;
- State public state;
-
- event Closed();
- event RefundsEnabled();
- event Refunded(address indexed beneficiary, uint256 weiAmount);
-
- constructor(address payable _wallet) public {
- require(_wallet != address(0x0));
- wallet = _wallet;
- state = State.Active;
- }
-
- function deposit(address payable investor) public onlyOwner payable {
- require(state == State.Active);
- deposited[investor] = deposited[investor].add(msg.value);
- }
-
- function close() public onlyOwner {
- require(state == State.Active);
- state = State.Closed;
- emit Closed();
- wallet.transfer(address(this).balance);
- }
-
- function enableRefunds() public onlyOwner {
- require(state == State.Active);
- state = State.Refunding;
- emit RefundsEnabled();
- }
-
- function refund(address payable investor) public {
- require(state == State.Refunding);
- uint256 depositedValue = deposited[investor];
- deposited[investor] = 0;
- investor.transfer(depositedValue);
- emit Refunded(investor, depositedValue);
- }
-}
diff --git a/test/compilationTests/zeppelin/crowdsale/RefundableCrowdsale.sol b/test/compilationTests/zeppelin/crowdsale/RefundableCrowdsale.sol
deleted file mode 100644
index 94e3af99..00000000
--- a/test/compilationTests/zeppelin/crowdsale/RefundableCrowdsale.sol
+++ /dev/null
@@ -1,59 +0,0 @@
-pragma solidity ^0.4.11;
-
-
-import '../math/SafeMath.sol';
-import './FinalizableCrowdsale.sol';
-import './RefundVault.sol';
-
-
-/**
- * @title RefundableCrowdsale
- * @dev Extension of Crowdsale contract that adds a funding goal, and
- * the possibility of users getting a refund if goal is not met.
- * Uses a RefundVault as the crowdsale's vault.
- */
-contract RefundableCrowdsale is FinalizableCrowdsale {
- using SafeMath for uint256;
-
- // minimum amount of funds to be raised in weis
- uint256 public goal;
-
- // refund vault used to hold funds while crowdsale is running
- RefundVault public vault;
-
- constructor(uint256 _goal) public {
- vault = new RefundVault(wallet);
- goal = _goal;
- }
-
- // We're overriding the fund forwarding from Crowdsale.
- // In addition to sending the funds, we want to call
- // the RefundVault deposit function
- function forwardFunds() internal {
- vault.deposit.value(msg.value)(msg.sender);
- }
-
- // if crowdsale is unsuccessful, investors can claim refunds here
- function claimRefund() public {
- require(isFinalized);
- require(!goalReached());
-
- vault.refund(msg.sender);
- }
-
- // vault finalization task, called when owner calls finalize()
- function finalization() internal {
- if (goalReached()) {
- vault.close();
- } else {
- vault.enableRefunds();
- }
-
- super.finalization();
- }
-
- function goalReached() public view returns (bool) {
- return weiRaised >= goal;
- }
-
-}
diff --git a/test/compilationTests/zeppelin/lifecycle/Destructible.sol b/test/compilationTests/zeppelin/lifecycle/Destructible.sol
deleted file mode 100644
index 9b9d8223..00000000
--- a/test/compilationTests/zeppelin/lifecycle/Destructible.sol
+++ /dev/null
@@ -1,25 +0,0 @@
-pragma solidity ^0.4.11;
-
-
-import "../ownership/Ownable.sol";
-
-
-/**
- * @title Destructible
- * @dev Base contract that can be destroyed by owner. All funds in contract will be sent to the owner.
- */
-contract Destructible is Ownable {
-
- constructor() public payable { }
-
- /**
- * @dev Transfers the current balance to the owner and terminates the contract.
- */
- function destroy() public onlyOwner {
- selfdestruct(owner);
- }
-
- function destroyAndSend(address payable _recipient) public onlyOwner {
- selfdestruct(_recipient);
- }
-}
diff --git a/test/compilationTests/zeppelin/lifecycle/Migrations.sol b/test/compilationTests/zeppelin/lifecycle/Migrations.sol
deleted file mode 100644
index 4ca95d36..00000000
--- a/test/compilationTests/zeppelin/lifecycle/Migrations.sol
+++ /dev/null
@@ -1,21 +0,0 @@
-pragma solidity ^0.4.11;
-
-
-import '../ownership/Ownable.sol';
-
-/**
- * @title Migrations
- * @dev This is a truffle contract, needed for truffle integration, not meant for use by Zeppelin users.
- */
-contract Migrations is Ownable {
- uint256 public lastCompletedMigration;
-
- function setCompleted(uint256 completed) public onlyOwner {
- lastCompletedMigration = completed;
- }
-
- function upgrade(address newAddress) public onlyOwner {
- Migrations upgraded = Migrations(newAddress);
- upgraded.setCompleted(lastCompletedMigration);
- }
-}
diff --git a/test/compilationTests/zeppelin/lifecycle/Pausable.sol b/test/compilationTests/zeppelin/lifecycle/Pausable.sol
deleted file mode 100644
index 0c48f2f6..00000000
--- a/test/compilationTests/zeppelin/lifecycle/Pausable.sol
+++ /dev/null
@@ -1,51 +0,0 @@
-pragma solidity ^0.4.11;
-
-
-import "../ownership/Ownable.sol";
-
-
-/**
- * @title Pausable
- * @dev Base contract which allows children to implement an emergency stop mechanism.
- */
-contract Pausable is Ownable {
- event Pause();
- event Unpause();
-
- bool public paused = false;
-
-
- /**
- * @dev modifier to allow actions only when the contract IS paused
- */
- modifier whenNotPaused() {
- if (paused) revert();
- _;
- }
-
- /**
- * @dev modifier to allow actions only when the contract IS NOT paused
- */
- modifier whenPaused {
- if (!paused) revert();
- _;
- }
-
- /**
- * @dev called by the owner to pause, triggers stopped state
- */
- function pause() public onlyOwner whenNotPaused returns (bool) {
- paused = true;
- emit Pause();
- return true;
- }
-
- /**
- * @dev called by the owner to unpause, returns to normal state
- */
- function unpause() public onlyOwner whenPaused returns (bool) {
- paused = false;
- emit Unpause();
- return true;
- }
-}
diff --git a/test/compilationTests/zeppelin/lifecycle/TokenDestructible.sol b/test/compilationTests/zeppelin/lifecycle/TokenDestructible.sol
deleted file mode 100644
index eb141587..00000000
--- a/test/compilationTests/zeppelin/lifecycle/TokenDestructible.sol
+++ /dev/null
@@ -1,36 +0,0 @@
-pragma solidity ^0.4.11;
-
-
-import "../ownership/Ownable.sol";
-import "../token/ERC20Basic.sol";
-
-/**
- * @title TokenDestructible:
- * @author Remco Bloemen <remco@2Ï€.com>
- * @dev Base contract that can be destroyed by owner. All funds in contract including
- * listed tokens will be sent to the owner.
- */
-contract TokenDestructible is Ownable {
-
- constructor() public payable { }
-
- /**
- * @notice Terminate contract and refund to owner
- * @param tokens List of addresses of ERC20 or ERC20Basic token contracts to
- refund.
- * @notice The called token contracts could try to re-enter this contract. Only
- supply token contracts you trust.
- */
- function destroy(address[] memory tokens) public onlyOwner {
-
- // Transfer tokens to owner
- for(uint256 i = 0; i < tokens.length; i++) {
- ERC20Basic token = ERC20Basic(tokens[i]);
- uint256 balance = token.balanceOf(address(this));
- token.transfer(owner, balance);
- }
-
- // Transfer Eth to owner and terminate contract
- selfdestruct(owner);
- }
-}
diff --git a/test/compilationTests/zeppelin/math/Math.sol b/test/compilationTests/zeppelin/math/Math.sol
deleted file mode 100644
index 9997998a..00000000
--- a/test/compilationTests/zeppelin/math/Math.sol
+++ /dev/null
@@ -1,24 +0,0 @@
-pragma solidity ^0.4.11;
-
-/**
- * @title Math
- * @dev Assorted math operations
- */
-
-library Math {
- function max64(uint64 a, uint64 b) internal pure returns (uint64) {
- return a >= b ? a : b;
- }
-
- function min64(uint64 a, uint64 b) internal pure returns (uint64) {
- return a < b ? a : b;
- }
-
- function max256(uint256 a, uint256 b) internal pure returns (uint256) {
- return a >= b ? a : b;
- }
-
- function min256(uint256 a, uint256 b) internal pure returns (uint256) {
- return a < b ? a : b;
- }
-}
diff --git a/test/compilationTests/zeppelin/math/SafeMath.sol b/test/compilationTests/zeppelin/math/SafeMath.sol
deleted file mode 100644
index a98635e2..00000000
--- a/test/compilationTests/zeppelin/math/SafeMath.sol
+++ /dev/null
@@ -1,32 +0,0 @@
-pragma solidity ^0.4.11;
-
-
-/**
- * @title SafeMath
- * @dev Math operations with safety checks that throw on error
- */
-library SafeMath {
- function mul(uint256 a, uint256 b) internal pure returns (uint256) {
- uint256 c = a * b;
- assert(a == 0 || c / a == b);
- return c;
- }
-
- function div(uint256 a, uint256 b) internal pure returns (uint256) {
- // assert(b > 0); // Solidity automatically throws when dividing by 0
- uint256 c = a / b;
- // assert(a == b * c + a % b); // There is no case in which this doesn't hold
- return c;
- }
-
- function sub(uint256 a, uint256 b) internal pure returns (uint256) {
- assert(b <= a);
- return a - b;
- }
-
- function add(uint256 a, uint256 b) internal pure returns (uint256) {
- uint256 c = a + b;
- assert(c >= a);
- return c;
- }
-}
diff --git a/test/compilationTests/zeppelin/ownership/Claimable.sol b/test/compilationTests/zeppelin/ownership/Claimable.sol
deleted file mode 100644
index 148ad535..00000000
--- a/test/compilationTests/zeppelin/ownership/Claimable.sol
+++ /dev/null
@@ -1,40 +0,0 @@
-pragma solidity ^0.4.11;
-
-
-import './Ownable.sol';
-
-
-/**
- * @title Claimable
- * @dev Extension for the Ownable contract, where the ownership needs to be claimed.
- * This allows the new owner to accept the transfer.
- */
-contract Claimable is Ownable {
- address payable public pendingOwner;
-
- /**
- * @dev Modifier throws if called by any account other than the pendingOwner.
- */
- modifier onlyPendingOwner() {
- if (msg.sender != pendingOwner) {
- revert();
- }
- _;
- }
-
- /**
- * @dev Allows the current owner to set the pendingOwner address.
- * @param newOwner The address to transfer ownership to.
- */
- function transferOwnership(address payable newOwner) public onlyOwner {
- pendingOwner = newOwner;
- }
-
- /**
- * @dev Allows the pendingOwner address to finalize the transfer.
- */
- function claimOwnership() public onlyPendingOwner {
- owner = pendingOwner;
- pendingOwner = address(0x0);
- }
-}
diff --git a/test/compilationTests/zeppelin/ownership/Contactable.sol b/test/compilationTests/zeppelin/ownership/Contactable.sol
deleted file mode 100644
index 5053494d..00000000
--- a/test/compilationTests/zeppelin/ownership/Contactable.sol
+++ /dev/null
@@ -1,21 +0,0 @@
-pragma solidity ^0.4.11;
-
-import './Ownable.sol';
-
-/**
- * @title Contactable token
- * @dev Basic version of a contactable contract, allowing the owner to provide a string with their
- * contact information.
- */
-contract Contactable is Ownable{
-
- string public contactInformation;
-
- /**
- * @dev Allows the owner to set a string with their contact information.
- * @param info The contact information to attach to the contract.
- */
- function setContactInformation(string memory info) public onlyOwner{
- contactInformation = info;
- }
-}
diff --git a/test/compilationTests/zeppelin/ownership/DelayedClaimable.sol b/test/compilationTests/zeppelin/ownership/DelayedClaimable.sol
deleted file mode 100644
index f4c8a681..00000000
--- a/test/compilationTests/zeppelin/ownership/DelayedClaimable.sol
+++ /dev/null
@@ -1,43 +0,0 @@
-pragma solidity ^0.4.11;
-
-
-import './Claimable.sol';
-
-
-/**
- * @title DelayedClaimable
- * @dev Extension for the Claimable contract, where the ownership needs to be claimed before/after
- * a certain block number.
- */
-contract DelayedClaimable is Claimable {
-
- uint256 public end;
- uint256 public start;
-
- /**
- * @dev Used to specify the time period during which a pending
- * owner can claim ownership.
- * @param _start The earliest time ownership can be claimed.
- * @param _end The latest time ownership can be claimed.
- */
- function setLimits(uint256 _start, uint256 _end) public onlyOwner {
- if (_start > _end)
- revert();
- end = _end;
- start = _start;
- }
-
-
- /**
- * @dev Allows the pendingOwner address to finalize the transfer, as long as it is called within
- * the specified start and end time.
- */
- function claimOwnership() public onlyPendingOwner {
- if ((block.number > end) || (block.number < start))
- revert();
- owner = pendingOwner;
- pendingOwner = address(0x0);
- end = 0;
- }
-
-}
diff --git a/test/compilationTests/zeppelin/ownership/HasNoContracts.sol b/test/compilationTests/zeppelin/ownership/HasNoContracts.sol
deleted file mode 100644
index 19b363d4..00000000
--- a/test/compilationTests/zeppelin/ownership/HasNoContracts.sol
+++ /dev/null
@@ -1,21 +0,0 @@
-pragma solidity ^0.4.11;
-
-import "./Ownable.sol";
-
-/**
- * @title Contracts that should not own Contracts
- * @author Remco Bloemen <remco@2Ï€.com>
- * @dev Should contracts (anything Ownable) end up being owned by this contract, it allows the owner
- * of this contract to reclaim ownership of the contracts.
- */
-contract HasNoContracts is Ownable {
-
- /**
- * @dev Reclaim ownership of Ownable contracts
- * @param contractAddr The address of the Ownable to be reclaimed.
- */
- function reclaimContract(address contractAddr) external onlyOwner {
- Ownable contractInst = Ownable(contractAddr);
- contractInst.transferOwnership(owner);
- }
-}
diff --git a/test/compilationTests/zeppelin/ownership/HasNoEther.sol b/test/compilationTests/zeppelin/ownership/HasNoEther.sol
deleted file mode 100644
index 5e3d27d2..00000000
--- a/test/compilationTests/zeppelin/ownership/HasNoEther.sol
+++ /dev/null
@@ -1,44 +0,0 @@
-pragma solidity ^0.4.11;
-
-import "./Ownable.sol";
-
-/**
- * @title Contracts that should not own Ether
- * @author Remco Bloemen <remco@2Ï€.com>
- * @dev This tries to block incoming ether to prevent accidental loss of Ether. Should Ether end up
- * in the contract, it will allow the owner to reclaim this ether.
- * @notice Ether can still be send to this contract by:
- * calling functions labeled `payable`
- * `selfdestruct(contract_address)`
- * mining directly to the contract address
-*/
-contract HasNoEther is Ownable {
-
- /**
- * @dev Constructor that rejects incoming Ether
- * @dev The `payable` flag is added so we can access `msg.value` without compiler warning. If we
- * leave out payable, then Solidity will allow inheriting contracts to implement a payable
- * constructor. By doing it this way we prevent a payable constructor from working. Alternatively
- * we could use assembly to access msg.value.
- */
- constructor() public payable {
- if(msg.value > 0) {
- revert();
- }
- }
-
- /**
- * @dev Disallows direct send by settings a default function without the `payable` flag.
- */
- function() external {
- }
-
- /**
- * @dev Transfer all Ether held by the contract to the owner.
- */
- function reclaimEther() external onlyOwner {
- if(!owner.send(address(this).balance)) {
- revert();
- }
- }
-}
diff --git a/test/compilationTests/zeppelin/ownership/HasNoTokens.sol b/test/compilationTests/zeppelin/ownership/HasNoTokens.sol
deleted file mode 100644
index 079cef7c..00000000
--- a/test/compilationTests/zeppelin/ownership/HasNoTokens.sol
+++ /dev/null
@@ -1,34 +0,0 @@
-pragma solidity ^0.4.11;
-
-import "./Ownable.sol";
-import "../token/ERC20Basic.sol";
-
-/**
- * @title Contracts that should not own Tokens
- * @author Remco Bloemen <remco@2Ï€.com>
- * @dev This blocks incoming ERC23 tokens to prevent accidental loss of tokens.
- * Should tokens (any ERC20Basic compatible) end up in the contract, it allows the
- * owner to reclaim the tokens.
- */
-contract HasNoTokens is Ownable {
-
- /**
- * @dev Reject all ERC23 compatible tokens
- * @param from_ address The address that is transferring the tokens
- * @param value_ uint256 the amount of the specified token
- * @param data_ Bytes The data passed from the caller.
- */
- function tokenFallback(address from_, uint256 value_, bytes calldata data_) external {
- revert();
- }
-
- /**
- * @dev Reclaim all ERC20Basic compatible tokens
- * @param tokenAddr address The address of the token contract
- */
- function reclaimToken(address tokenAddr) external onlyOwner {
- ERC20Basic tokenInst = ERC20Basic(tokenAddr);
- uint256 balance = tokenInst.balanceOf(address(this));
- tokenInst.transfer(owner, balance);
- }
-}
diff --git a/test/compilationTests/zeppelin/ownership/Multisig.sol b/test/compilationTests/zeppelin/ownership/Multisig.sol
deleted file mode 100644
index 2eb0f4bc..00000000
--- a/test/compilationTests/zeppelin/ownership/Multisig.sol
+++ /dev/null
@@ -1,28 +0,0 @@
-pragma solidity ^0.4.11;
-
-
-/**
- * @title Multisig
- * @dev Interface contract for multisig proxy contracts; see below for docs.
- */
-contract Multisig {
- // EVENTS
-
- // logged events:
- // Funds has arrived into the wallet (record how much).
- event Deposit(address _from, uint256 value);
- // Single transaction going out of the wallet (record who signed for it, how much, and to whom it's going).
- event SingleTransact(address owner, uint256 value, address to, bytes data);
- // Multi-sig transaction going out of the wallet (record who signed for it last, the operation hash, how much, and to whom it's going).
- event MultiTransact(address owner, bytes32 operation, uint256 value, address to, bytes data);
- // Confirmation still needed for a transaction.
- event ConfirmationNeeded(bytes32 operation, address initiator, uint256 value, address to, bytes data);
-
-
- // FUNCTIONS
-
- // TODO: document
- function changeOwner(address _from, address _to) external;
- function execute(address _to, uint256 _value, bytes calldata _data) external returns (bytes32);
- function confirm(bytes32 _h) public returns (bool);
-}
diff --git a/test/compilationTests/zeppelin/ownership/NoOwner.sol b/test/compilationTests/zeppelin/ownership/NoOwner.sol
deleted file mode 100644
index c0ef7f4d..00000000
--- a/test/compilationTests/zeppelin/ownership/NoOwner.sol
+++ /dev/null
@@ -1,14 +0,0 @@
-pragma solidity ^0.4.11;
-
-import "./HasNoEther.sol";
-import "./HasNoTokens.sol";
-import "./HasNoContracts.sol";
-
-/**
- * @title Base contract for contracts that should not own things.
- * @author Remco Bloemen <remco@2Ï€.com>
- * @dev Solves a class of errors where a contract accidentally becomes owner of Ether, Tokens or
- * Owned contracts. See respective base contracts for details.
- */
-contract NoOwner is HasNoEther, HasNoTokens, HasNoContracts {
-}
diff --git a/test/compilationTests/zeppelin/ownership/Ownable.sol b/test/compilationTests/zeppelin/ownership/Ownable.sol
deleted file mode 100644
index 3c95127d..00000000
--- a/test/compilationTests/zeppelin/ownership/Ownable.sol
+++ /dev/null
@@ -1,43 +0,0 @@
-pragma solidity ^0.4.11;
-
-
-/**
- * @title Ownable
- * @dev The Ownable contract has an owner address, and provides basic authorization control
- * functions, this simplifies the implementation of "user permissions".
- */
-contract Ownable {
- address payable public owner;
-
-
- /**
- * @dev The Ownable constructor sets the original `owner` of the contract to the sender
- * account.
- */
- constructor() public {
- owner = msg.sender;
- }
-
-
- /**
- * @dev Throws if called by any account other than the owner.
- */
- modifier onlyOwner() {
- if (msg.sender != owner) {
- revert();
- }
- _;
- }
-
-
- /**
- * @dev Allows the current owner to transfer control of the contract to a newOwner.
- * @param newOwner The address to transfer ownership to.
- */
- function transferOwnership(address payable newOwner) public onlyOwner {
- if (newOwner != address(0)) {
- owner = newOwner;
- }
- }
-
-}
diff --git a/test/compilationTests/zeppelin/ownership/Shareable.sol b/test/compilationTests/zeppelin/ownership/Shareable.sol
deleted file mode 100644
index b2cb165d..00000000
--- a/test/compilationTests/zeppelin/ownership/Shareable.sol
+++ /dev/null
@@ -1,189 +0,0 @@
-pragma solidity ^0.4.11;
-
-
-/**
- * @title Shareable
- * @dev inheritable "property" contract that enables methods to be protected by requiring the
- * acquiescence of either a single, or, crucially, each of a number of, designated owners.
- * @dev Usage: use modifiers onlyowner (just own owned) or onlymanyowners(hash), whereby the same hash must be provided by some number (specified in constructor) of the set of owners (specified in the constructor) before the interior is executed.
- */
-contract Shareable {
-
- // struct for the status of a pending operation.
- struct PendingState {
- uint256 yetNeeded;
- uint256 ownersDone;
- uint256 index;
- }
-
- // the number of owners that must confirm the same operation before it is run.
- uint256 public required;
-
- // list of owners
- address[256] owners;
- // index on the list of owners to allow reverse lookup
- mapping(address => uint256) ownerIndex;
- // the ongoing operations.
- mapping(bytes32 => PendingState) pendings;
- bytes32[] pendingsIndex;
-
-
- // this contract only has six types of events: it can accept a confirmation, in which case
- // we record owner and operation (hash) alongside it.
- event Confirmation(address owner, bytes32 operation);
- event Revoke(address owner, bytes32 operation);
-
-
- // simple single-sig function modifier.
- modifier onlyOwner {
- if (!isOwner(msg.sender)) {
- revert();
- }
- _;
- }
-
- /**
- * @dev Modifier for multisig functions.
- * @param _operation The operation must have an intrinsic hash in order that later attempts can be
- * realised as the same underlying operation and thus count as confirmations.
- */
- modifier onlymanyowners(bytes32 _operation) {
- if (confirmAndCheck(_operation)) {
- _;
- }
- }
-
- /**
- * @dev Constructor is given the number of sigs required to do protected "onlymanyowners"
- * transactions as well as the selection of addresses capable of confirming them.
- * @param _owners A list of owners.
- * @param _required The amount required for a transaction to be approved.
- */
- constructor(address[] memory _owners, uint256 _required) public {
- owners[1] = msg.sender;
- ownerIndex[msg.sender] = 1;
- for (uint256 i = 0; i < _owners.length; ++i) {
- owners[2 + i] = _owners[i];
- ownerIndex[_owners[i]] = 2 + i;
- }
- required = _required;
- if (required > owners.length) {
- revert();
- }
- }
-
- /**
- * @dev Revokes a prior confirmation of the given operation.
- * @param _operation A string identifying the operation.
- */
- function revoke(bytes32 _operation) external {
- uint256 index = ownerIndex[msg.sender];
- // make sure they're an owner
- if (index == 0) {
- return;
- }
- uint256 ownerIndexBit = 2**index;
- PendingState memory pending = pendings[_operation];
- if (pending.ownersDone & ownerIndexBit > 0) {
- pending.yetNeeded++;
- pending.ownersDone -= ownerIndexBit;
- emit Revoke(msg.sender, _operation);
- }
- }
-
- /**
- * @dev Gets an owner by 0-indexed position (using numOwners as the count)
- * @param ownerIndex uint256 The index of the owner
- * @return The address of the owner
- */
- function getOwner(uint256 ownerIndex) external view returns (address) {
- return address(owners[ownerIndex + 1]);
- }
-
- /**
- * @dev Checks if given address is an owner.
- * @param _addr address The address which you want to check.
- * @return True if the address is an owner and fase otherwise.
- */
- function isOwner(address _addr) public view returns (bool) {
- return ownerIndex[_addr] > 0;
- }
-
- /**
- * @dev Function to check is specific owner has already confirme the operation.
- * @param _operation The operation identifier.
- * @param _owner The owner address.
- * @return True if the owner has confirmed and false otherwise.
- */
- function hasConfirmed(bytes32 _operation, address _owner) public view returns (bool) {
- PendingState memory pending = pendings[_operation];
- uint256 index = ownerIndex[_owner];
-
- // make sure they're an owner
- if (index == 0) {
- return false;
- }
-
- // determine the bit to set for this owner.
- uint256 ownerIndexBit = 2**index;
- return !(pending.ownersDone & ownerIndexBit == 0);
- }
-
- /**
- * @dev Confirm and operation and checks if it's already executable.
- * @param _operation The operation identifier.
- * @return Returns true when operation can be executed.
- */
- function confirmAndCheck(bytes32 _operation) internal returns (bool) {
- // determine what index the present sender is:
- uint256 index = ownerIndex[msg.sender];
- // make sure they're an owner
- if (index == 0) {
- revert();
- }
-
- PendingState memory pending = pendings[_operation];
- // if we're not yet working on this operation, switch over and reset the confirmation status.
- if (pending.yetNeeded == 0) {
- // reset count of confirmations needed.
- pending.yetNeeded = required;
- // reset which owners have confirmed (none) - set our bitmap to 0.
- pending.ownersDone = 0;
- pending.index = pendingsIndex.length++;
- pendingsIndex[pending.index] = _operation;
- }
- // determine the bit to set for this owner.
- uint256 ownerIndexBit = 2**index;
- // make sure we (the message sender) haven't confirmed this operation previously.
- if (pending.ownersDone & ownerIndexBit == 0) {
- emit Confirmation(msg.sender, _operation);
- // ok - check if count is enough to go ahead.
- if (pending.yetNeeded <= 1) {
- // enough confirmations: reset and run interior.
- delete pendingsIndex[pendings[_operation].index];
- delete pendings[_operation];
- return true;
- } else {
- // not enough: record that this owner in particular confirmed.
- pending.yetNeeded--;
- pending.ownersDone |= ownerIndexBit;
- }
- }
- return false;
- }
-
-
- /**
- * @dev Clear the pending list.
- */
- function clearPending() internal {
- uint256 length = pendingsIndex.length;
- for (uint256 i = 0; i < length; ++i) {
- if (pendingsIndex[i] != 0) {
- delete pendings[pendingsIndex[i]];
- }
- }
- delete pendingsIndex;
- }
-
-}
diff --git a/test/compilationTests/zeppelin/payment/PullPayment.sol b/test/compilationTests/zeppelin/payment/PullPayment.sol
deleted file mode 100644
index 5682d3c2..00000000
--- a/test/compilationTests/zeppelin/payment/PullPayment.sol
+++ /dev/null
@@ -1,50 +0,0 @@
-pragma solidity ^0.4.11;
-
-
-import '../math/SafeMath.sol';
-
-
-/**
- * @title PullPayment
- * @dev Base contract supporting async send for pull payments. Inherit from this
- * contract and use asyncSend instead of send.
- */
-contract PullPayment {
- using SafeMath for uint256;
-
- mapping(address => uint256) public payments;
- uint256 public totalPayments;
-
- /**
- * @dev Called by the payer to store the sent amount as credit to be pulled.
- * @param dest The destination address of the funds.
- * @param amount The amount to transfer.
- */
- function asyncSend(address dest, uint256 amount) internal {
- payments[dest] = payments[dest].add(amount);
- totalPayments = totalPayments.add(amount);
- }
-
- /**
- * @dev withdraw accumulated balance, called by payee.
- */
- function withdrawPayments() public {
- address payable payee = msg.sender;
- uint256 payment = payments[payee];
-
- if (payment == 0) {
- revert();
- }
-
- if (address(this).balance < payment) {
- revert();
- }
-
- totalPayments = totalPayments.sub(payment);
- payments[payee] = 0;
-
- if (!payee.send(payment)) {
- revert();
- }
- }
-}
diff --git a/test/compilationTests/zeppelin/token/BasicToken.sol b/test/compilationTests/zeppelin/token/BasicToken.sol
deleted file mode 100644
index 3d5646a4..00000000
--- a/test/compilationTests/zeppelin/token/BasicToken.sol
+++ /dev/null
@@ -1,37 +0,0 @@
-pragma solidity ^0.4.11;
-
-
-import './ERC20Basic.sol';
-import '../math/SafeMath.sol';
-
-
-/**
- * @title Basic token
- * @dev Basic version of StandardToken, with no allowances.
- */
-contract BasicToken is ERC20Basic {
- using SafeMath for uint256;
-
- mapping(address => uint256) balances;
-
- /**
- * @dev transfer token for a specified address
- * @param _to The address to transfer to.
- * @param _value The amount to be transferred.
- */
- function transfer(address _to, uint256 _value) public {
- balances[msg.sender] = balances[msg.sender].sub(_value);
- balances[_to] = balances[_to].add(_value);
- emit Transfer(msg.sender, _to, _value);
- }
-
- /**
- * @dev Gets the balance of the specified address.
- * @param _owner The address to query the the balance of.
- * @return An uint256 representing the amount owned by the passed address.
- */
- function balanceOf(address _owner) public view returns (uint256 balance) {
- return balances[_owner];
- }
-
-}
diff --git a/test/compilationTests/zeppelin/token/ERC20.sol b/test/compilationTests/zeppelin/token/ERC20.sol
deleted file mode 100644
index 5b5dc748..00000000
--- a/test/compilationTests/zeppelin/token/ERC20.sol
+++ /dev/null
@@ -1,16 +0,0 @@
-pragma solidity ^0.4.11;
-
-
-import './ERC20Basic.sol';
-
-
-/**
- * @title ERC20 interface
- * @dev see https://github.com/ethereum/EIPs/issues/20
- */
-contract ERC20 is ERC20Basic {
- function allowance(address owner, address spender) public view returns (uint256);
- function transferFrom(address from, address to, uint256 value) public;
- function approve(address spender, uint256 value) public;
- event Approval(address indexed owner, address indexed spender, uint256 value);
-}
diff --git a/test/compilationTests/zeppelin/token/ERC20Basic.sol b/test/compilationTests/zeppelin/token/ERC20Basic.sol
deleted file mode 100644
index fbe33134..00000000
--- a/test/compilationTests/zeppelin/token/ERC20Basic.sol
+++ /dev/null
@@ -1,14 +0,0 @@
-pragma solidity ^0.4.11;
-
-
-/**
- * @title ERC20Basic
- * @dev Simpler version of ERC20 interface
- * @dev see https://github.com/ethereum/EIPs/issues/20
- */
-contract ERC20Basic {
- uint256 public totalSupply;
- function balanceOf(address who) public view returns (uint256);
- function transfer(address to, uint256 value) public;
- event Transfer(address indexed from, address indexed to, uint256 value);
-}
diff --git a/test/compilationTests/zeppelin/token/LimitedTransferToken.sol b/test/compilationTests/zeppelin/token/LimitedTransferToken.sol
deleted file mode 100644
index d668b86f..00000000
--- a/test/compilationTests/zeppelin/token/LimitedTransferToken.sol
+++ /dev/null
@@ -1,57 +0,0 @@
-pragma solidity ^0.4.11;
-
-import "./ERC20.sol";
-
-/**
- * @title LimitedTransferToken
- * @dev LimitedTransferToken defines the generic interface and the implementation to limit token
- * transferability for different events. It is intended to be used as a base class for other token
- * contracts.
- * LimitedTransferToken has been designed to allow for different limiting factors,
- * this can be achieved by recursively calling super.transferableTokens() until the base class is
- * hit. For example:
- * function transferableTokens(address holder, uint64 time) view public returns (uint256) {
- * return min256(unlockedTokens, super.transferableTokens(holder, time));
- * }
- * A working example is VestedToken.sol:
- * https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/token/VestedToken.sol
- */
-
-contract LimitedTransferToken is ERC20 {
-
- /**
- * @dev Checks whether it can transfer or otherwise throws.
- */
- modifier canTransfer(address _sender, uint256 _value) {
- if (_value > transferableTokens(_sender, uint64(now))) revert();
- _;
- }
-
- /**
- * @dev Checks modifier and allows transfer if tokens are not locked.
- * @param _to The address that will receive the tokens.
- * @param _value The amount of tokens to be transferred.
- */
- function transfer(address _to, uint256 _value) canTransfer(msg.sender, _value) public {
- super.transfer(_to, _value);
- }
-
- /**
- * @dev Checks modifier and allows transfer if tokens are not locked.
- * @param _from The address that will send the tokens.
- * @param _to The address that will receive the tokens.
- * @param _value The amount of tokens to be transferred.
- */
- function transferFrom(address _from, address _to, uint256 _value) public canTransfer(_from, _value) {
- super.transferFrom(_from, _to, _value);
- }
-
- /**
- * @dev Default transferable tokens function returns all tokens for a holder (no limit).
- * @dev Overwriting transferableTokens(address holder, uint64 time) is the way to provide the
- * specific logic for limiting token transferability for a holder over time.
- */
- function transferableTokens(address holder, uint64 time) view public returns (uint256) {
- return balanceOf(holder);
- }
-}
diff --git a/test/compilationTests/zeppelin/token/MintableToken.sol b/test/compilationTests/zeppelin/token/MintableToken.sol
deleted file mode 100644
index 24b8c807..00000000
--- a/test/compilationTests/zeppelin/token/MintableToken.sol
+++ /dev/null
@@ -1,50 +0,0 @@
-pragma solidity ^0.4.11;
-
-
-import './StandardToken.sol';
-import '../ownership/Ownable.sol';
-
-
-
-/**
- * @title Mintable token
- * @dev Simple ERC20 Token example, with mintable token creation
- * @dev Issue: * https://github.com/OpenZeppelin/zeppelin-solidity/issues/120
- * Based on code by TokenMarketNet: https://github.com/TokenMarketNet/ico/blob/master/contracts/MintableToken.sol
- */
-
-contract MintableToken is StandardToken, Ownable {
- event Mint(address indexed to, uint256 amount);
- event MintFinished();
-
- bool public mintingFinished = false;
-
-
- modifier canMint() {
- if(mintingFinished) revert();
- _;
- }
-
- /**
- * @dev Function to mint tokens
- * @param _to The address that will receive the minted tokens.
- * @param _amount The amount of tokens to mint.
- * @return A boolean that indicates if the operation was successful.
- */
- function mint(address _to, uint256 _amount) public onlyOwner canMint returns (bool) {
- totalSupply = totalSupply.add(_amount);
- balances[_to] = balances[_to].add(_amount);
- emit Mint(_to, _amount);
- return true;
- }
-
- /**
- * @dev Function to stop minting new tokens.
- * @return True if the operation was successful.
- */
- function finishMinting() public onlyOwner returns (bool) {
- mintingFinished = true;
- emit MintFinished();
- return true;
- }
-}
diff --git a/test/compilationTests/zeppelin/token/PausableToken.sol b/test/compilationTests/zeppelin/token/PausableToken.sol
deleted file mode 100644
index 66f80b80..00000000
--- a/test/compilationTests/zeppelin/token/PausableToken.sol
+++ /dev/null
@@ -1,21 +0,0 @@
-pragma solidity ^0.4.11;
-
-import './StandardToken.sol';
-import '../lifecycle/Pausable.sol';
-
-/**
- * Pausable token
- *
- * Simple ERC20 Token example, with pausable token creation
- **/
-
-contract PausableToken is StandardToken, Pausable {
-
- function transfer(address _to, uint _value) public whenNotPaused {
- super.transfer(_to, _value);
- }
-
- function transferFrom(address _from, address _to, uint _value) public whenNotPaused {
- super.transferFrom(_from, _to, _value);
- }
-}
diff --git a/test/compilationTests/zeppelin/token/SimpleToken.sol b/test/compilationTests/zeppelin/token/SimpleToken.sol
deleted file mode 100644
index d8717562..00000000
--- a/test/compilationTests/zeppelin/token/SimpleToken.sol
+++ /dev/null
@@ -1,28 +0,0 @@
-pragma solidity ^0.4.11;
-
-
-import "./StandardToken.sol";
-
-
-/**
- * @title SimpleToken
- * @dev Very simple ERC20 Token example, where all tokens are pre-assigned to the creator.
- * Note they can later distribute these tokens as they wish using `transfer` and other
- * `StandardToken` functions.
- */
-contract SimpleToken is StandardToken {
-
- string public name = "SimpleToken";
- string public symbol = "SIM";
- uint256 public decimals = 18;
- uint256 public INITIAL_SUPPLY = 10000;
-
- /**
- * @dev Constructor that gives msg.sender all of existing tokens.
- */
- constructor() public {
- totalSupply = INITIAL_SUPPLY;
- balances[msg.sender] = INITIAL_SUPPLY;
- }
-
-}
diff --git a/test/compilationTests/zeppelin/token/StandardToken.sol b/test/compilationTests/zeppelin/token/StandardToken.sol
deleted file mode 100644
index 56f4a5f3..00000000
--- a/test/compilationTests/zeppelin/token/StandardToken.sol
+++ /dev/null
@@ -1,65 +0,0 @@
-pragma solidity ^0.4.11;
-
-
-import './BasicToken.sol';
-import './ERC20.sol';
-
-
-/**
- * @title Standard ERC20 token
- *
- * @dev Implementation of the basic standard token.
- * @dev https://github.com/ethereum/EIPs/issues/20
- * @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
- */
-contract StandardToken is ERC20, BasicToken {
-
- mapping (address => mapping (address => uint256)) allowed;
-
-
- /**
- * @dev Transfer tokens from one address to another
- * @param _from address The address which you want to send tokens from
- * @param _to address The address which you want to transfer to
- * @param _value uint256 the amount of tokens to be transferred
- */
- function transferFrom(address _from, address _to, uint256 _value) public {
- uint256 _allowance = allowed[_from][msg.sender];
-
- // Check is not needed because sub(_allowance, _value) will already throw if this condition is not met
- // if (_value > _allowance) revert();
-
- balances[_to] = balances[_to].add(_value);
- balances[_from] = balances[_from].sub(_value);
- allowed[_from][msg.sender] = _allowance.sub(_value);
- emit Transfer(_from, _to, _value);
- }
-
- /**
- * @dev Aprove the passed address to spend the specified amount of tokens on behalf of msg.sender.
- * @param _spender The address which will spend the funds.
- * @param _value The amount of tokens to be spent.
- */
- function approve(address _spender, uint256 _value) public {
-
- // To change the approve amount you first have to reduce the addresses`
- // allowance to zero by calling `approve(_spender, 0)` if it is not
- // already 0 to mitigate the race condition described here:
- // https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
- if ((_value != 0) && (allowed[msg.sender][_spender] != 0)) revert();
-
- allowed[msg.sender][_spender] = _value;
- emit Approval(msg.sender, _spender, _value);
- }
-
- /**
- * @dev Function to check the amount of tokens that an owner allowed to a spender.
- * @param _owner address The address which owns the funds.
- * @param _spender address The address which will spend the funds.
- * @return A uint256 specifying the amount of tokens still available for the spender.
- */
- function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
- return allowed[_owner][_spender];
- }
-
-}
diff --git a/test/compilationTests/zeppelin/token/TokenTimelock.sol b/test/compilationTests/zeppelin/token/TokenTimelock.sol
deleted file mode 100644
index 4847b648..00000000
--- a/test/compilationTests/zeppelin/token/TokenTimelock.sol
+++ /dev/null
@@ -1,41 +0,0 @@
-pragma solidity ^0.4.11;
-
-
-import './ERC20Basic.sol';
-
-/**
- * @title TokenTimelock
- * @dev TokenTimelock is a token holder contract that will allow a
- * beneficiary to extract the tokens after a given release time
- */
-contract TokenTimelock {
-
- // ERC20 basic token contract being held
- ERC20Basic token;
-
- // beneficiary of tokens after they are released
- address beneficiary;
-
- // timestamp when token release is enabled
- uint releaseTime;
-
- constructor(ERC20Basic _token, address _beneficiary, uint _releaseTime) public {
- require(_releaseTime > now);
- token = _token;
- beneficiary = _beneficiary;
- releaseTime = _releaseTime;
- }
-
- /**
- * @dev beneficiary claims tokens held by time lock
- */
- function claim() public {
- require(msg.sender == beneficiary);
- require(now >= releaseTime);
-
- uint amount = token.balanceOf(address(this));
- require(amount > 0);
-
- token.transfer(beneficiary, amount);
- }
-}
diff --git a/test/compilationTests/zeppelin/token/VestedToken.sol b/test/compilationTests/zeppelin/token/VestedToken.sol
deleted file mode 100644
index c9469f16..00000000
--- a/test/compilationTests/zeppelin/token/VestedToken.sol
+++ /dev/null
@@ -1,248 +0,0 @@
-pragma solidity ^0.4.11;
-
-import "../math/Math.sol";
-import "./StandardToken.sol";
-import "./LimitedTransferToken.sol";
-
-/**
- * @title Vested token
- * @dev Tokens that can be vested for a group of addresses.
- */
-contract VestedToken is StandardToken, LimitedTransferToken {
-
- uint256 MAX_GRANTS_PER_ADDRESS = 20;
-
- struct TokenGrant {
- address granter; // 20 bytes
- uint256 value; // 32 bytes
- uint64 cliff;
- uint64 vesting;
- uint64 start; // 3 * 8 = 24 bytes
- bool revokable;
- bool burnsOnRevoke; // 2 * 1 = 2 bits? or 2 bytes?
- } // total 78 bytes = 3 sstore per operation (32 per sstore)
-
- mapping (address => TokenGrant[]) public grants;
-
- event NewTokenGrant(address indexed from, address indexed to, uint256 value, uint256 grantId);
-
- /**
- * @dev Grant tokens to a specified address
- * @param _to address The address which the tokens will be granted to.
- * @param _value uint256 The amount of tokens to be granted.
- * @param _start uint64 Time of the beginning of the grant.
- * @param _cliff uint64 Time of the cliff period.
- * @param _vesting uint64 The vesting period.
- */
- function grantVestedTokens(
- address _to,
- uint256 _value,
- uint64 _start,
- uint64 _cliff,
- uint64 _vesting,
- bool _revokable,
- bool _burnsOnRevoke
- ) public {
-
- // Check for date inconsistencies that may cause unexpected behavior
- if (_cliff < _start || _vesting < _cliff) {
- revert();
- }
-
- if (tokenGrantsCount(_to) > MAX_GRANTS_PER_ADDRESS) revert(); // To prevent a user being spammed and have his balance locked (out of gas attack when calculating vesting).
-
- uint256 count = grants[_to].push(
- TokenGrant(
- _revokable ? msg.sender : 0x0000000000000000000000000000000000000000, // avoid storing an extra 20 bytes when it is non-revokable
- _value,
- _cliff,
- _vesting,
- _start,
- _revokable,
- _burnsOnRevoke
- )
- );
-
- transfer(_to, _value);
-
- emit NewTokenGrant(msg.sender, _to, _value, count - 1);
- }
-
- /**
- * @dev Revoke the grant of tokens of a specified address.
- * @param _holder The address which will have its tokens revoked.
- * @param _grantId The id of the token grant.
- */
- function revokeTokenGrant(address _holder, uint256 _grantId) public {
- TokenGrant storage grant = grants[_holder][_grantId];
-
- if (!grant.revokable) { // Check if grant was revokable
- revert();
- }
-
- if (grant.granter != msg.sender) { // Only granter can revoke it
- revert();
- }
-
- address receiver = grant.burnsOnRevoke ? 0x000000000000000000000000000000000000dEaD : msg.sender;
-
- uint256 nonVested = nonVestedTokens(grant, uint64(now));
-
- // remove grant from array
- delete grants[_holder][_grantId];
- grants[_holder][_grantId] = grants[_holder][grants[_holder].length.sub(1)];
- grants[_holder].length -= 1;
-
- balances[receiver] = balances[receiver].add(nonVested);
- balances[_holder] = balances[_holder].sub(nonVested);
-
- emit Transfer(_holder, receiver, nonVested);
- }
-
-
- /**
- * @dev Calculate the total amount of transferable tokens of a holder at a given time
- * @param holder address The address of the holder
- * @param time uint64 The specific time.
- * @return An uint256 representing a holder's total amount of transferable tokens.
- */
- function transferableTokens(address holder, uint64 time) view public returns (uint256) {
- uint256 grantIndex = tokenGrantsCount(holder);
-
- if (grantIndex == 0) return balanceOf(holder); // shortcut for holder without grants
-
- // Iterate through all the grants the holder has, and add all non-vested tokens
- uint256 nonVested = 0;
- for (uint256 i = 0; i < grantIndex; i++) {
- nonVested = SafeMath.add(nonVested, nonVestedTokens(grants[holder][i], time));
- }
-
- // Balance - totalNonVested is the amount of tokens a holder can transfer at any given time
- uint256 vestedTransferable = SafeMath.sub(balanceOf(holder), nonVested);
-
- // Return the minimum of how many vested can transfer and other value
- // in case there are other limiting transferability factors (default is balanceOf)
- return Math.min256(vestedTransferable, super.transferableTokens(holder, time));
- }
-
- /**
- * @dev Check the amount of grants that an address has.
- * @param _holder The holder of the grants.
- * @return A uint256 representing the total amount of grants.
- */
- function tokenGrantsCount(address _holder) public view returns (uint256 index) {
- return grants[_holder].length;
- }
-
- /**
- * @dev Calculate amount of vested tokens at a specific time.
- * @param tokens uint256 The amount of tokens granted.
- * @param time uint64 The time to be checked
- * @param start uint64 A time representing the beginning of the grant
- * @param cliff uint64 The cliff period.
- * @param vesting uint64 The vesting period.
- * @return An uint256 representing the amount of vested tokens of a specific grant.
- * transferableTokens
- * | _/-------- vestedTokens rect
- * | _/
- * | _/
- * | _/
- * | _/
- * | /
- * | .|
- * | . |
- * | . |
- * | . |
- * | . |
- * | . |
- * +===+===========+---------+----------> time
- * Start Clift Vesting
- */
- function calculateVestedTokens(
- uint256 tokens,
- uint256 time,
- uint256 start,
- uint256 cliff,
- uint256 vesting) public view returns (uint256)
- {
- // Shortcuts for before cliff and after vesting cases.
- if (time < cliff) return 0;
- if (time >= vesting) return tokens;
-
- // Interpolate all vested tokens.
- // As before cliff the shortcut returns 0, we can use just calculate a value
- // in the vesting rect (as shown in above's figure)
-
- // vestedTokens = tokens * (time - start) / (vesting - start)
- uint256 vestedTokens = SafeMath.div(
- SafeMath.mul(
- tokens,
- SafeMath.sub(time, start)
- ),
- SafeMath.sub(vesting, start)
- );
-
- return vestedTokens;
- }
-
- /**
- * @dev Get all information about a specific grant.
- * @param _holder The address which will have its tokens revoked.
- * @param _grantId The id of the token grant.
- * @return Returns all the values that represent a TokenGrant(address, value, start, cliff,
- * revokability, burnsOnRevoke, and vesting) plus the vested value at the current time.
- */
- function tokenGrant(address _holder, uint256 _grantId) public view returns (address granter, uint256 value, uint256 vested, uint64 start, uint64 cliff, uint64 vesting, bool revokable, bool burnsOnRevoke) {
- TokenGrant storage grant = grants[_holder][_grantId];
-
- granter = grant.granter;
- value = grant.value;
- start = grant.start;
- cliff = grant.cliff;
- vesting = grant.vesting;
- revokable = grant.revokable;
- burnsOnRevoke = grant.burnsOnRevoke;
-
- vested = vestedTokens(grant, uint64(now));
- }
-
- /**
- * @dev Get the amount of vested tokens at a specific time.
- * @param grant TokenGrant The grant to be checked.
- * @param time The time to be checked
- * @return An uint256 representing the amount of vested tokens of a specific grant at a specific time.
- */
- function vestedTokens(TokenGrant memory grant, uint64 time) private view returns (uint256) {
- return calculateVestedTokens(
- grant.value,
- uint256(time),
- uint256(grant.start),
- uint256(grant.cliff),
- uint256(grant.vesting)
- );
- }
-
- /**
- * @dev Calculate the amount of non vested tokens at a specific time.
- * @param grant TokenGrant The grant to be checked.
- * @param time uint64 The time to be checked
- * @return An uint256 representing the amount of non vested tokens of a specific grant on the
- * passed time frame.
- */
- function nonVestedTokens(TokenGrant memory grant, uint64 time) private view returns (uint256) {
- return grant.value.sub(vestedTokens(grant, time));
- }
-
- /**
- * @dev Calculate the date when the holder can transfer all its tokens
- * @param holder address The address of the holder
- * @return An uint256 representing the date of the last transferable tokens.
- */
- function lastTokenIsTransferableDate(address holder) view public returns (uint64 date) {
- date = uint64(now);
- uint256 grantIndex = grants[holder].length;
- for (uint256 i = 0; i < grantIndex; i++) {
- date = Math.max64(grants[holder][i].vesting, date);
- }
- }
-}
diff --git a/test/libsolidity/SMTChecker.cpp b/test/libsolidity/SMTChecker.cpp
index c7e60256..195004cb 100644
--- a/test/libsolidity/SMTChecker.cpp
+++ b/test/libsolidity/SMTChecker.cpp
@@ -133,23 +133,6 @@ BOOST_AUTO_TEST_CASE(assignment_in_declaration)
CHECK_SUCCESS_NO_WARNINGS(text);
}
-BOOST_AUTO_TEST_CASE(function_call_does_not_clear_local_vars)
-{
- string text = R"(
- contract C {
- function g() public pure {}
- function f() public view {
- uint a = 3;
- this.g();
- assert(a == 3);
- g();
- assert(a == 3);
- }
- }
- )";
- CHECK_WARNING(text, "Assertion checker does not yet implement this type of function call");
-}
-
BOOST_AUTO_TEST_CASE(branches_merge_variables)
{
// Branch does not touch variable a
diff --git a/test/libsolidity/SemVerMatcher.cpp b/test/libsolidity/SemVerMatcher.cpp
index 07f8fba6..43951f73 100644
--- a/test/libsolidity/SemVerMatcher.cpp
+++ b/test/libsolidity/SemVerMatcher.cpp
@@ -42,13 +42,13 @@ SemVerMatchExpression parseExpression(string const& _input)
{
Scanner scanner{CharStream(_input)};
vector<string> literals;
- vector<Token::Value> tokens;
+ vector<Token> tokens;
while (scanner.currentToken() != Token::EOS)
{
auto token = scanner.currentToken();
string literal = scanner.currentLiteral();
- if (literal.empty() && Token::toString(token))
- literal = Token::toString(token);
+ if (literal.empty() && TokenTraits::toString(token))
+ literal = TokenTraits::toString(token);
literals.push_back(literal);
tokens.push_back(token);
scanner.next();
diff --git a/test/libsolidity/smtCheckerTests/special/blockhash.sol b/test/libsolidity/smtCheckerTests/special/blockhash.sol
new file mode 100644
index 00000000..d0f263eb
--- /dev/null
+++ b/test/libsolidity/smtCheckerTests/special/blockhash.sol
@@ -0,0 +1,14 @@
+pragma experimental SMTChecker;
+
+contract C
+{
+ function f() public payable {
+ assert(blockhash(2) > 0);
+ }
+}
+// ----
+// Warning: (86-98): Assertion checker does not yet support this special variable.
+// Warning: (86-98): Assertion checker does not yet implement this type.
+// Warning: (86-102): Assertion checker does not yet implement the type bytes32 for comparisons
+// Warning: (86-102): Internal error: Expression undefined for SMT solver.
+// Warning: (79-103): Assertion violation happens here
diff --git a/test/libsolidity/smtCheckerTests/special/difficulty.sol b/test/libsolidity/smtCheckerTests/special/difficulty.sol
new file mode 100644
index 00000000..4469d4e5
--- /dev/null
+++ b/test/libsolidity/smtCheckerTests/special/difficulty.sol
@@ -0,0 +1,10 @@
+pragma experimental SMTChecker;
+
+contract C
+{
+ function f(uint difficulty) public view {
+ assert(block.difficulty == difficulty);
+ }
+}
+// ----
+// Warning: (91-129): Assertion violation happens here
diff --git a/test/libsolidity/smtCheckerTests/special/gasleft.sol b/test/libsolidity/smtCheckerTests/special/gasleft.sol
new file mode 100644
index 00000000..857230fe
--- /dev/null
+++ b/test/libsolidity/smtCheckerTests/special/gasleft.sol
@@ -0,0 +1,14 @@
+pragma experimental SMTChecker;
+
+contract C
+{
+ function f() public view {
+ assert(gasleft() > 0);
+ uint g = gasleft();
+ assert(g < gasleft());
+ assert(g >= gasleft());
+ }
+}
+// ----
+// Warning: (76-97): Assertion violation happens here
+// Warning: (123-144): Assertion violation happens here
diff --git a/test/libsolidity/smtCheckerTests/special/many.sol b/test/libsolidity/smtCheckerTests/special/many.sol
new file mode 100644
index 00000000..40e5d987
--- /dev/null
+++ b/test/libsolidity/smtCheckerTests/special/many.sol
@@ -0,0 +1,25 @@
+pragma experimental SMTChecker;
+
+contract C
+{
+ function f() public payable {
+ assert(msg.sender == block.coinbase);
+ assert(block.difficulty == block.gaslimit);
+ assert(block.number == block.timestamp);
+ assert(tx.gasprice == msg.value);
+ assert(tx.origin == msg.sender);
+ uint x = block.number;
+ assert(x + 2 > block.number);
+ assert(now > 10);
+ assert(gasleft() > 100);
+ }
+}
+// ----
+// Warning: (79-115): Assertion violation happens here
+// Warning: (119-161): Assertion violation happens here
+// Warning: (165-204): Assertion violation happens here
+// Warning: (208-240): Assertion violation happens here
+// Warning: (244-275): Assertion violation happens here
+// Warning: (311-316): Overflow (resulting value larger than 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) happens here
+// Warning: (336-352): Assertion violation happens here
+// Warning: (356-379): Assertion violation happens here
diff --git a/test/libsolidity/smtCheckerTests/special/msg_data.sol b/test/libsolidity/smtCheckerTests/special/msg_data.sol
new file mode 100644
index 00000000..7e748f09
--- /dev/null
+++ b/test/libsolidity/smtCheckerTests/special/msg_data.sol
@@ -0,0 +1,14 @@
+pragma experimental SMTChecker;
+
+contract C
+{
+ function f() public payable {
+ assert(msg.data.length > 0);
+ }
+}
+// ----
+// Warning: (86-101): Assertion checker does not yet support this expression.
+// Warning: (86-94): Assertion checker does not yet support this special variable.
+// Warning: (86-94): Assertion checker does not yet implement this type.
+// Warning: (86-101): Internal error: Expression undefined for SMT solver.
+// Warning: (79-106): Assertion violation happens here
diff --git a/test/libsolidity/smtCheckerTests/special/msg_sender_1.sol b/test/libsolidity/smtCheckerTests/special/msg_sender_1.sol
new file mode 100644
index 00000000..dd2366e2
--- /dev/null
+++ b/test/libsolidity/smtCheckerTests/special/msg_sender_1.sol
@@ -0,0 +1,10 @@
+pragma experimental SMTChecker;
+
+contract C
+{
+ function f() public view {
+ address a = msg.sender;
+ address b = msg.sender;
+ assert(a == b);
+ }
+}
diff --git a/test/libsolidity/smtCheckerTests/special/msg_sender_2.sol b/test/libsolidity/smtCheckerTests/special/msg_sender_2.sol
new file mode 100644
index 00000000..ad45d076
--- /dev/null
+++ b/test/libsolidity/smtCheckerTests/special/msg_sender_2.sol
@@ -0,0 +1,14 @@
+pragma experimental SMTChecker;
+
+contract C
+{
+ function f() public view {
+ require(msg.sender != address(0));
+ address a = msg.sender;
+ address b = msg.sender;
+ assert(a == b);
+ }
+}
+// ----
+// Warning: (98-108): Assertion checker does not yet implement this expression.
+// Warning: (98-108): Internal error: Expression undefined for SMT solver.
diff --git a/test/libsolidity/smtCheckerTests/special/msg_sender_fail_1.sol b/test/libsolidity/smtCheckerTests/special/msg_sender_fail_1.sol
new file mode 100644
index 00000000..9a4eefd5
--- /dev/null
+++ b/test/libsolidity/smtCheckerTests/special/msg_sender_fail_1.sol
@@ -0,0 +1,13 @@
+pragma experimental SMTChecker;
+
+contract C
+{
+ function f(address c) public view {
+ address a = msg.sender;
+ address b = msg.sender;
+ assert(a == b);
+ assert(c == msg.sender);
+ }
+}
+// ----
+// Warning: (155-178): Assertion violation happens here
diff --git a/test/libsolidity/smtCheckerTests/special/msg_sig.sol b/test/libsolidity/smtCheckerTests/special/msg_sig.sol
new file mode 100644
index 00000000..6f832179
--- /dev/null
+++ b/test/libsolidity/smtCheckerTests/special/msg_sig.sol
@@ -0,0 +1,14 @@
+pragma experimental SMTChecker;
+
+contract C
+{
+ function f() public payable {
+ assert(msg.sig == 0x00000000);
+ }
+}
+// ----
+// Warning: (86-93): Assertion checker does not yet support this special variable.
+// Warning: (86-93): Assertion checker does not yet implement this type.
+// Warning: (86-107): Assertion checker does not yet implement the type bytes4 for comparisons
+// Warning: (86-107): Internal error: Expression undefined for SMT solver.
+// Warning: (79-108): Assertion violation happens here
diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp
index 6782f412..0378764d 100644
--- a/test/libyul/YulOptimizerTest.cpp
+++ b/test/libyul/YulOptimizerTest.cpp
@@ -36,6 +36,8 @@
#include <libyul/optimiser/UnusedPruner.h>
#include <libyul/optimiser/ExpressionJoiner.h>
#include <libyul/optimiser/SSATransform.h>
+#include <libyul/optimiser/RedundantAssignEliminator.h>
+#include <libyul/optimiser/Suite.h>
#include <libsolidity/parsing/Scanner.h>
#include <libsolidity/inlineasm/AsmPrinter.h>
@@ -178,6 +180,20 @@ bool YulOptimizerTest::run(ostream& _stream, string const& _linePrefix, bool con
NameDispenser nameDispenser(*m_ast);
SSATransform::run(*m_ast, nameDispenser);
}
+ else if (m_optimizerStep == "redundantAssignEliminator")
+ {
+ disambiguate();
+ RedundantAssignEliminator::run(*m_ast);
+ }
+ else if (m_optimizerStep == "ssaPlusCleanup")
+ {
+ disambiguate();
+ NameDispenser nameDispenser(*m_ast);
+ SSATransform::run(*m_ast, nameDispenser);
+ RedundantAssignEliminator::run(*m_ast);
+ }
+ else if (m_optimizerStep == "fullSuite")
+ OptimiserSuite::run(*m_ast, *m_analysisInfo);
else
{
FormattedScope(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Invalid optimizer step: " << m_optimizerStep << endl;
diff --git a/test/libyul/yulOptimizerTests/fullSuite/medium.yul b/test/libyul/yulOptimizerTests/fullSuite/medium.yul
new file mode 100644
index 00000000..45cc555d
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/fullSuite/medium.yul
@@ -0,0 +1,26 @@
+{
+ function allocate(size) -> p {
+ p := mload(0x40)
+ mstore(0x40, add(p, size))
+ }
+ function array_index_access(array, index) -> p {
+ p := add(array, mul(index, 0x20))
+ }
+ pop(allocate(0x20))
+ let x := allocate(0x40)
+ mstore(array_index_access(x, 3), 2)
+}
+// ----
+// fullSuite
+// {
+// {
+// let _12 := 0x20
+// let allocate__7 := 0x40
+// let allocate_p_2 := mload(allocate__7)
+// mstore(allocate__7, add(allocate_p_2, _12))
+// pop(allocate_p_2)
+// let allocate_p_2_1 := mload(allocate__7)
+// mstore(allocate__7, add(allocate_p_2_1, allocate__7))
+// mstore(add(allocate_p_2_1, 96), 2)
+// }
+// }
diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for.yul
new file mode 100644
index 00000000..d9bbd86d
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for.yul
@@ -0,0 +1,26 @@
+{
+ for {
+ let a := 2
+ // Should not be removed, even though you might think
+ // it goes out of scope
+ a := 3
+ } a { a := add(a, 1) }
+ {
+ a := 7
+ }
+}
+// ----
+// redundantAssignEliminator
+// {
+// for {
+// let a := 2
+// a := 3
+// }
+// a
+// {
+// a := add(a, 1)
+// }
+// {
+// a := 7
+// }
+// }
diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_branch.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_branch.yul
new file mode 100644
index 00000000..7f5e97ce
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_branch.yul
@@ -0,0 +1,31 @@
+{
+ let x
+ let y
+ // Cannot be removed, because we might skip the loop
+ x := 1
+ for { } calldataload(0) { }
+ {
+ // Cannot be removed
+ x := 2
+ // Can be removed
+ y := 3
+ }
+ y := 8
+ mstore(x, 0)
+}
+// ----
+// redundantAssignEliminator
+// {
+// let x
+// let y
+// x := 1
+// for {
+// }
+// calldataload(0)
+// {
+// }
+// {
+// x := 2
+// }
+// mstore(x, 0)
+// }
diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_rerun.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_rerun.yul
new file mode 100644
index 00000000..65eb2838
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_rerun.yul
@@ -0,0 +1,27 @@
+{
+ let x
+ // Cannot be removed, because we might run the loop only once
+ x := 1
+ for { } calldataload(0) { }
+ {
+ mstore(x, 2)
+ // Cannot be removed because of the line above
+ x := 2
+ }
+ x := 3
+}
+// ----
+// redundantAssignEliminator
+// {
+// let x
+// x := 1
+// for {
+// }
+// calldataload(0)
+// {
+// }
+// {
+// mstore(x, 2)
+// x := 2
+// }
+// }
diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/function.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/function.yul
new file mode 100644
index 00000000..5bb920ec
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/function.yul
@@ -0,0 +1,23 @@
+{
+ let r
+ r := 1
+ function f(x, y) -> a, b {
+ // Can be removed, is param
+ x := 1
+ y := 2
+ // Cannot be removed, is return param
+ a := 3
+ b := 4
+ }
+ r := 2
+}
+// ----
+// redundantAssignEliminator
+// {
+// let r
+// function f(x, y) -> a, b
+// {
+// a := 3
+// b := 4
+// }
+// }
diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/if.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/if.yul
new file mode 100644
index 00000000..958bfc66
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/if.yul
@@ -0,0 +1,24 @@
+{
+ let c
+ let d
+ c := calldataload(0)
+ d := 1
+ if c {
+ d := 2
+ }
+ // This enforces that none of the assignments above can be removed.
+ mstore(0, d)
+}
+// ----
+// redundantAssignEliminator
+// {
+// let c
+// let d
+// c := calldataload(0)
+// d := 1
+// if c
+// {
+// d := 2
+// }
+// mstore(0, d)
+// }
diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/if_overwrite_all_branches.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/if_overwrite_all_branches.yul
new file mode 100644
index 00000000..e47c31d1
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/if_overwrite_all_branches.yul
@@ -0,0 +1,24 @@
+{
+ let c
+ let d
+ c := calldataload(0)
+ // This assignment will be overwritten in all branches and thus can be removed.
+ d := 1
+ if c {
+ d := 2
+ }
+ d := 3
+ mstore(0, d)
+}
+// ----
+// redundantAssignEliminator
+// {
+// let c
+// let d
+// c := calldataload(0)
+// if c
+// {
+// }
+// d := 3
+// mstore(0, d)
+// }
diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/if_used_in_one_branch.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/if_used_in_one_branch.yul
new file mode 100644
index 00000000..00065ed2
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/if_used_in_one_branch.yul
@@ -0,0 +1,25 @@
+{
+ let c
+ let d
+ c := calldataload(0)
+ d := 1
+ if c {
+ // Uses the assignment above
+ d := d
+ }
+ d := 3
+ mstore(0, d)
+}
+// ----
+// redundantAssignEliminator
+// {
+// let c
+// let d
+// c := calldataload(0)
+// d := 1
+// if c
+// {
+// }
+// d := 3
+// mstore(0, d)
+// }
diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/multi_assign.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/multi_assign.yul
new file mode 100644
index 00000000..26bcfc72
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/multi_assign.yul
@@ -0,0 +1,19 @@
+{
+ function f() -> a, b {}
+ let x, y
+ x := 1
+ x := 2
+ // Will not be used, but is a multi-assign, so not removed.
+ x, y := f()
+ x := 3
+ y := 4
+}
+// ----
+// redundantAssignEliminator
+// {
+// function f() -> a, b
+// {
+// }
+// let x, y
+// x, y := f()
+// }
diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/multivar.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/multivar.yul
new file mode 100644
index 00000000..cf646126
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/multivar.yul
@@ -0,0 +1,15 @@
+{
+ let a := 2
+ a := 7
+ let b := 8
+ b := a
+ a := b
+}
+// ----
+// redundantAssignEliminator
+// {
+// let a := 2
+// a := 7
+// let b := 8
+// b := a
+// }
diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/non_movable.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/non_movable.yul
new file mode 100644
index 00000000..ae3e5226
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/non_movable.yul
@@ -0,0 +1,11 @@
+{
+ let a
+ a := 0
+ a := mload(0)
+}
+// ----
+// redundantAssignEliminator
+// {
+// let a
+// a := mload(0)
+// }
diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/scopes.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/scopes.yul
new file mode 100644
index 00000000..702f854d
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/scopes.yul
@@ -0,0 +1,16 @@
+{
+ let a
+ {
+ let b
+ b := 2
+ a := 2
+ }
+}
+// ----
+// redundantAssignEliminator
+// {
+// let a
+// {
+// let b
+// }
+// }
diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/simple.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/simple.yul
new file mode 100644
index 00000000..913a7694
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/simple.yul
@@ -0,0 +1,10 @@
+{
+ let a
+ a := 1
+ a := 2
+}
+// ----
+// redundantAssignEliminator
+// {
+// let a
+// }
diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_in_all.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_in_all.yul
new file mode 100644
index 00000000..96265576
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_in_all.yul
@@ -0,0 +1,22 @@
+{
+ let x
+ // Will be overwritten in all branches
+ x := 1
+ switch calldataload(0)
+ case 0 { x := 2 }
+ default { x := 3 }
+ mstore(x, 0)
+}
+// ----
+// redundantAssignEliminator
+// {
+// let x
+// switch calldataload(0)
+// case 0 {
+// x := 2
+// }
+// default {
+// x := 3
+// }
+// mstore(x, 0)
+// }
diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_in_one.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_in_one.yul
new file mode 100644
index 00000000..cbe859ed
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_in_one.yul
@@ -0,0 +1,19 @@
+{
+ let x
+ // Will NOT be overwritten in all branches
+ x := 1
+ switch calldataload(0)
+ case 0 { x := 2 }
+ mstore(x, 0)
+}
+// ----
+// redundantAssignEliminator
+// {
+// let x
+// x := 1
+// switch calldataload(0)
+// case 0 {
+// x := 2
+// }
+// mstore(x, 0)
+// }
diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_use_combination.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_use_combination.yul
new file mode 100644
index 00000000..1a3b26eb
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_use_combination.yul
@@ -0,0 +1,23 @@
+{
+ let x
+ // Will be used in some and overwritten in others
+ x := 1
+ switch calldataload(0)
+ case 0 { x := 2 }
+ default { mstore(x, 1) }
+ mstore(x, 0)
+}
+// ----
+// redundantAssignEliminator
+// {
+// let x
+// x := 1
+// switch calldataload(0)
+// case 0 {
+// x := 2
+// }
+// default {
+// mstore(x, 1)
+// }
+// mstore(x, 0)
+// }
diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_unused.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_unused.yul
new file mode 100644
index 00000000..cc78b74d
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_unused.yul
@@ -0,0 +1,16 @@
+{
+ let x
+ // Not referenced anywhere.
+ x := 1
+ switch calldataload(0)
+ case 0 { mstore(0, 1) }
+}
+// ----
+// redundantAssignEliminator
+// {
+// let x
+// switch calldataload(0)
+// case 0 {
+// mstore(0, 1)
+// }
+// }
diff --git a/test/libyul/yulOptimizerTests/ssaPlusCleanup/control_structures.yul b/test/libyul/yulOptimizerTests/ssaPlusCleanup/control_structures.yul
new file mode 100644
index 00000000..51d1627f
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/ssaPlusCleanup/control_structures.yul
@@ -0,0 +1,35 @@
+{
+ function copy(from, to) -> length {
+ length := mload(from)
+ mstore(to, length)
+ from := add(from, 0x20)
+ to := add(to, 0x20)
+ for { let x := 1 } lt(x, length) { x := add(x, 0x20) } {
+ mstore(add(to, x), mload(add(from, x)))
+ }
+ }
+}
+// ----
+// ssaPlusCleanup
+// {
+// function copy(from, to) -> length
+// {
+// let length_1 := mload(from)
+// length := length_1
+// mstore(to, length_1)
+// let from_1 := add(from, 0x20)
+// let to_1 := add(to, 0x20)
+// for {
+// let x_1 := 1
+// let x := x_1
+// }
+// lt(x, length_1)
+// {
+// let x_2 := add(x, 0x20)
+// x := x_2
+// }
+// {
+// mstore(add(to_1, x), mload(add(from_1, x)))
+// }
+// }
+// }
diff --git a/test/libyul/yulOptimizerTests/ssaPlusCleanup/multi_reassign.yul b/test/libyul/yulOptimizerTests/ssaPlusCleanup/multi_reassign.yul
new file mode 100644
index 00000000..ddb33aa0
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/ssaPlusCleanup/multi_reassign.yul
@@ -0,0 +1,17 @@
+{
+ let a := 1
+ a := 2
+ a := 3
+ a := 4
+ mstore(0, a)
+}
+// ----
+// ssaPlusCleanup
+// {
+// let a_1 := 1
+// let a := a_1
+// let a_2 := 2
+// let a_3 := 3
+// let a_4 := 4
+// mstore(0, a_4)
+// }
diff --git a/test/libyul/yulOptimizerTests/ssaPlusCleanup/multi_reassign_with_use.yul b/test/libyul/yulOptimizerTests/ssaPlusCleanup/multi_reassign_with_use.yul
new file mode 100644
index 00000000..67a6c5d3
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/ssaPlusCleanup/multi_reassign_with_use.yul
@@ -0,0 +1,17 @@
+{
+ let a := 1
+ a := add(a, 2)
+ a := add(a, 3)
+ a := mload(add(a, 4))
+ mstore(0, a)
+}
+// ----
+// ssaPlusCleanup
+// {
+// let a_1 := 1
+// let a := a_1
+// let a_2 := add(a_1, 2)
+// let a_3 := add(a_2, 3)
+// let a_4 := mload(add(a_3, 4))
+// mstore(0, a_4)
+// }