diff options
117 files changed, 934 insertions, 620 deletions
diff --git a/Changelog.md b/Changelog.md index 5bbf5af6..3eeb6fa8 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,13 +1,16 @@ ### 0.5.2 (unreleased) Language Features: + * Control Flow Graph: Detect every access to uninitialized storage pointers. Compiler Features: * Inline Assembly: Improve error messages around invalid function argument count. * Code Generator: Use codecopy for string constants more aggressively. * Code Generator: Use binary search for dispatch function if more efficient. The size/speed tradeoff can be tuned using ``--optimize-runs``. + * Compiler Interface: Disallow unknown keys in standard JSON input. * SMTChecker: Support mathematical and cryptographic functions in an uninterpreted way. + * Static Analyzer: Do not warn about unused variables or state mutability for functions with an empty body. * Type Checker: Add an additional reason to be displayed when type conversion fails. * Yul: Support object access via ``datasize``, ``dataoffset`` and ``datacopy`` in standalone assembly mode. @@ -15,6 +18,9 @@ Compiler Features: Bugfixes: +Build System: + * Replace the trusty PPA build by a static build on cosmic that is used for the trusty package instead. + ### 0.5.1 (2018-12-03) Language Features: diff --git a/ReleaseChecklist.md b/ReleaseChecklist.md index b84ae4c4..04734544 100644 --- a/ReleaseChecklist.md +++ b/ReleaseChecklist.md @@ -10,6 +10,7 @@ Checklist for making a release: - [ ] Thank voluntary contributors in the Github release page (use ``git shortlog -s -n -e origin/release..origin/develop``). - [ ] Wait for the CI runs on the tag itself (they should push artifacts onto the Github release page). - [ ] Run ``scripts/release_ppa.sh release`` to create the PPA release (you need the relevant openssl key). + - [ ] Once the ``~ethereum/ubuntu/ethereum-static`` PPA build is finished and published for all platforms (make sure not to do this earlier), copy the static package to the ``~ethereum/ubuntu/ethereum`` PPA for the destination series ``Trusty`` while selecting ``Copy existing binaries``. - [ ] Check that the Docker release was pushed to Docker Hub (this still seems to have problems, run ``./scripts/docker_deploy_manual.sh release``). - [ ] Update the homebrew realease in https://github.com/ethereum/homebrew-ethereum/blob/master/solidity.rb (version and hash) - [ ] Update the default version on readthedocs. diff --git a/docs/contributing.rst b/docs/contributing.rst index 12dea7d1..47d0d070 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -90,7 +90,7 @@ The option ``--no-smt`` disables the tests that require ``libz3`` and ``--no-ipc`` disables those that require ``aleth``. If you want to run the ipc tests (that test the semantics of the generated code), -you need to install `aleth <https://github.com/ethereum/cpp-ethereum/releases/download/solidityTester/aleth_2018-06-20_artful>`_ and run it in testing mode: ``aleth --test -d /tmp/testeth`` (make sure to rename it). +you need to install `aleth <https://github.com/ethereum/aleth/releases/download/v1.5.0-alpha.7/aleth-1.5.0-alpha.7-linux-x86_64.tar.gz>`_ and run it in testing mode: ``aleth --test -d /tmp/testeth`` (make sure to rename it). To run the actual tests, use: ``./scripts/soltest.sh --ipcpath /tmp/testeth/geth.ipc``. @@ -124,7 +124,7 @@ The CI runs additional tests (including ``solc-js`` and testing third party Soli You can not use some versions of ``aleth`` for testing. We suggest using the same version that the Solidity continuous integration tests use. - Currently the CI uses ``d661ac4fec0aeffbedcdc195f67f5ded0c798278`` of ``aleth``. + Currently the CI uses version ``1.5.0-alpha.7`` of ``aleth``. Writing and running syntax tests -------------------------------- diff --git a/docs/frequently-asked-questions.rst b/docs/frequently-asked-questions.rst index b0072348..d263e0c6 100644 --- a/docs/frequently-asked-questions.rst +++ b/docs/frequently-asked-questions.rst @@ -9,35 +9,6 @@ This list was originally compiled by `fivedogit <mailto:fivedogit@gmail.com>`_. Basic Questions *************** -What is the transaction "payload"? -================================== - -This is just the bytecode "data" sent along with the request. - - -Create a contract that can be killed and return funds -===================================================== - -First, a word of warning: Killing contracts sounds like a good idea, because "cleaning up" -is always good, but as seen above, it does not really clean up. Furthermore, -if Ether is sent to removed contracts, the Ether will be forever lost. - -If you want to deactivate your contracts, it is preferable to **disable** them by changing some -internal state which causes all functions to throw. This will make it impossible -to use the contract and ether sent to the contract will be returned automatically. - -Now to answering the question: Inside a constructor, ``msg.sender`` is the -creator. Save it. Then ``selfdestruct(creator);`` to kill and return funds. - -`example <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/05_greeter.sol>`_ - -Note that if you ``import "mortal"`` at the top of your contracts and declare -``contract SomeContract is mortal { ...`` and compile with a compiler that already -has it (which includes `Remix <https://remix.ethereum.org/>`_), then -``kill()`` is taken care of for you. Once a contract is "mortal", then you can -``contractname.kill.sendTransaction({from:eth.coinbase})``, just the same as my -examples. - If I return an ``enum``, I only get integer values in web3.js. How to get the named values? =========================================================================================== diff --git a/docs/layout-of-source-files.rst b/docs/layout-of-source-files.rst index ad84b200..fa36fc6a 100644 --- a/docs/layout-of-source-files.rst +++ b/docs/layout-of-source-files.rst @@ -267,7 +267,7 @@ Single-line comments (``//``) and multi-line comments (``/*...*/``) are possible (these are NEL, LS and PS), it will lead to a parser error. Additionally, there is another type of comment called a natspec comment, -for which the documentation is not yet written. They are written with a +which is detailed in the :ref:`style guide<natspec>`. They are written with a triple slash (``///``) or a double asterisk block(``/** ... */``) and they should be used directly above function declarations or statements. You can use `Doxygen <https://en.wikipedia.org/wiki/Doxygen>`_-style tags inside these comments to document diff --git a/docs/style-guide.rst b/docs/style-guide.rst index 68fee871..bf1be93e 100644 --- a/docs/style-guide.rst +++ b/docs/style-guide.rst @@ -1093,3 +1093,64 @@ General Recommendations ======================= TODO + +.. _natspec: + +******* +NatSpec +******* + +Solidity contracts can have a form of comments that are the basis of the +Ethereum Natural Language Specification Format. + +Add comments above functions or contracts following `doxygen <http://www.doxygen.nl>`_ notation +of one or multiple lines starting with `///` or a +multiline comment starting with `/**` and ending with `*/`. + +For example, the contract from `a simple smart contract <simple-smart-contract>`_ with the comments +added looks like the one below:: + + pragma solidity >=0.4.0 <0.6.0; + + /// @author The Solidity Team + /// @title A simple storage example + contract SimpleStorage { + uint storedData; + + /// Store `x`. + /// @param x the new value to store + /// @dev stores the number in the state variable `storedData` + function set(uint x) public { + storedData = x; + } + + /// Return the stored value. + /// @dev retrieves the value of the state variable `storedData` + /// @return the stored value + function get() public view returns (uint) { + return storedData; + } + } + +Natspec uses doxygen style tags with some special meaning. +If no tag is used, then the comment applies to ``@notice``. +The ``@notice`` tag is the main NatSpec tag and its audience is +users of the contract who have never seen the source code, so it should make +as little assumptions about the inner details as possible. +All tags are optional. + ++-------------+-------------------------------------------+-------------------------------+ +| Tag | Description | Context | ++=============+===========================================+===============================+ +| ``@title`` | A title that describes the contract | contract, interface | ++-------------+-------------------------------------------+-------------------------------+ +| ``@author`` | The name of the author | contract, interface, function | ++-------------+-------------------------------------------+-------------------------------+ +| ``@notice`` | Explanation of functionality | contract, interface, function | ++-------------+-------------------------------------------+-------------------------------+ +| ``@dev`` | Any extra details | contract, interface, function | ++-------------+-------------------------------------------+-------------------------------+ +| ``@param`` | Parameter type followed by parameter name | function | ++-------------+-------------------------------------------+-------------------------------+ +| ``@return`` | The return value of a contract's function | function | ++-------------+-------------------------------------------+-------------------------------+ diff --git a/libsolc/libsolc.h b/libsolc/libsolc.h index 4b0ec639..b58ee805 100644 --- a/libsolc/libsolc.h +++ b/libsolc/libsolc.h @@ -20,6 +20,8 @@ * Public compiler API. */ +#pragma once + #include <stdbool.h> #ifdef __cplusplus diff --git a/libsolidity/analysis/ControlFlowAnalyzer.cpp b/libsolidity/analysis/ControlFlowAnalyzer.cpp index fe58f0aa..a7e1ed97 100644 --- a/libsolidity/analysis/ControlFlowAnalyzer.cpp +++ b/libsolidity/analysis/ControlFlowAnalyzer.cpp @@ -17,6 +17,7 @@ #include <libsolidity/analysis/ControlFlowAnalyzer.h> #include <liblangutil/SourceLocation.h> +#include <boost/range/algorithm/sort.hpp> using namespace std; using namespace langutil; @@ -33,131 +34,112 @@ bool ControlFlowAnalyzer::visit(FunctionDefinition const& _function) if (_function.isImplemented()) { auto const& functionFlow = m_cfg.functionFlow(_function); - checkUnassignedStorageReturnValues(_function, functionFlow.entry, functionFlow.exit); + checkUninitializedAccess(functionFlow.entry, functionFlow.exit); } return false; } -set<VariableDeclaration const*> ControlFlowAnalyzer::variablesAssignedInNode(CFGNode const *node) +void ControlFlowAnalyzer::checkUninitializedAccess(CFGNode const* _entry, CFGNode const* _exit) const { - set<VariableDeclaration const*> result; - for (auto expression: node->block.expressions) + struct NodeInfo { - if (auto const* assignment = dynamic_cast<Assignment const*>(expression)) + set<VariableDeclaration const*> unassignedVariablesAtEntry; + set<VariableDeclaration const*> unassignedVariablesAtExit; + set<VariableOccurrence const*> uninitializedVariableAccesses; + /// Propagate the information from another node to this node. + /// To be used to propagate information from a node to its exit nodes. + /// Returns true, if new variables were added and thus the current node has + /// to be traversed again. + bool propagateFrom(NodeInfo const& _entryNode) { - stack<Expression const*> expressions; - expressions.push(&assignment->leftHandSide()); - while (!expressions.empty()) - { - Expression const* expression = expressions.top(); - expressions.pop(); - - if (auto const *tuple = dynamic_cast<TupleExpression const*>(expression)) - for (auto const& component: tuple->components()) - expressions.push(component.get()); - else if (auto const* identifier = dynamic_cast<Identifier const*>(expression)) - if (auto const* variableDeclaration = dynamic_cast<VariableDeclaration const*>( - identifier->annotation().referencedDeclaration - )) - result.insert(variableDeclaration); - } + size_t previousUnassignedVariablesAtEntry = unassignedVariablesAtEntry.size(); + size_t previousUninitializedVariableAccessess = uninitializedVariableAccesses.size(); + unassignedVariablesAtEntry += _entryNode.unassignedVariablesAtExit; + uninitializedVariableAccesses += _entryNode.uninitializedVariableAccesses; + return + unassignedVariablesAtEntry.size() > previousUnassignedVariablesAtEntry || + uninitializedVariableAccesses.size() > previousUninitializedVariableAccessess + ; } - } - return result; -} - -void ControlFlowAnalyzer::checkUnassignedStorageReturnValues( - FunctionDefinition const& _function, - CFGNode const* _functionEntry, - CFGNode const* _functionExit -) const -{ - if (_function.returnParameterList()->parameters().empty()) - return; - - map<CFGNode const*, set<VariableDeclaration const*>> unassigned; - - { - auto& unassignedAtFunctionEntry = unassigned[_functionEntry]; - for (auto const& returnParameter: _function.returnParameterList()->parameters()) - if ( - returnParameter->type()->dataStoredIn(DataLocation::Storage) || - returnParameter->type()->category() == Type::Category::Mapping - ) - unassignedAtFunctionEntry.insert(returnParameter.get()); - } - - stack<CFGNode const*> nodesToTraverse; - nodesToTraverse.push(_functionEntry); - - // walk all paths from entry with maximal set of unassigned return values + }; + map<CFGNode const*, NodeInfo> nodeInfos; + set<CFGNode const*> nodesToTraverse; + nodesToTraverse.insert(_entry); + + // Walk all paths starting from the nodes in ``nodesToTraverse`` until ``NodeInfo::propagateFrom`` + // returns false for all exits, i.e. until all paths have been walked with maximal sets of unassigned + // variables and accesses. while (!nodesToTraverse.empty()) { - auto node = nodesToTraverse.top(); - nodesToTraverse.pop(); - - auto& unassignedAtNode = unassigned[node]; + CFGNode const* currentNode = *nodesToTraverse.begin(); + nodesToTraverse.erase(nodesToTraverse.begin()); - if (node->block.returnStatement != nullptr) - if (node->block.returnStatement->expression()) - unassignedAtNode.clear(); - if (!unassignedAtNode.empty()) + auto& nodeInfo = nodeInfos[currentNode]; + auto unassignedVariables = nodeInfo.unassignedVariablesAtEntry; + for (auto const& variableOccurrence: currentNode->variableOccurrences) { - // kill all return values to which a value is assigned - for (auto const* variableDeclaration: variablesAssignedInNode(node)) - unassignedAtNode.erase(variableDeclaration); - - // kill all return values referenced in inline assembly - // a reference is enough, checking whether there actually was an assignment might be overkill - for (auto assembly: node->block.inlineAssemblyStatements) - for (auto const& ref: assembly->annotation().externalReferences) - if (auto variableDeclaration = dynamic_cast<VariableDeclaration const*>(ref.second.declaration)) - unassignedAtNode.erase(variableDeclaration); + switch (variableOccurrence.kind()) + { + case VariableOccurrence::Kind::Assignment: + unassignedVariables.erase(&variableOccurrence.declaration()); + break; + case VariableOccurrence::Kind::InlineAssembly: + // We consider all variables referenced in inline assembly as accessed. + // So far any reference is enough, but we might want to actually analyze + // the control flow in the assembly at some point. + case VariableOccurrence::Kind::Access: + case VariableOccurrence::Kind::Return: + if (unassignedVariables.count(&variableOccurrence.declaration())) + { + if (variableOccurrence.declaration().type()->dataStoredIn(DataLocation::Storage)) + // Merely store the unassigned access. We do not generate an error right away, since this + // path might still always revert. It is only an error if this is propagated to the exit + // node of the function (i.e. there is a path with an uninitialized access). + nodeInfo.uninitializedVariableAccesses.insert(&variableOccurrence); + } + break; + case VariableOccurrence::Kind::Declaration: + unassignedVariables.insert(&variableOccurrence.declaration()); + break; + } } + nodeInfo.unassignedVariablesAtExit = std::move(unassignedVariables); - for (auto const& exit: node->exits) - { - auto& unassignedAtExit = unassigned[exit]; - auto oldSize = unassignedAtExit.size(); - unassignedAtExit.insert(unassignedAtNode.begin(), unassignedAtNode.end()); - // (re)traverse an exit, if we are on a path with new unassigned return values to consider - // this will terminate, since there is only a finite number of unassigned return values - if (unassignedAtExit.size() > oldSize) - nodesToTraverse.push(exit); - } + // Propagate changes to all exits and queue them for traversal, if needed. + for (auto const& exit: currentNode->exits) + if (nodeInfos[exit].propagateFrom(nodeInfo)) + nodesToTraverse.insert(exit); } - if (!unassigned[_functionExit].empty()) + auto const& exitInfo = nodeInfos[_exit]; + if (!exitInfo.uninitializedVariableAccesses.empty()) { - vector<VariableDeclaration const*> unassignedOrdered( - unassigned[_functionExit].begin(), - unassigned[_functionExit].end() - ); - sort( - unassignedOrdered.begin(), - unassignedOrdered.end(), - [](VariableDeclaration const* lhs, VariableDeclaration const* rhs) -> bool { - return lhs->id() < rhs->id(); + vector<VariableOccurrence const*> uninitializedAccessesOrdered( + exitInfo.uninitializedVariableAccesses.begin(), + exitInfo.uninitializedVariableAccesses.end() + ); + boost::range::sort( + uninitializedAccessesOrdered, + [](VariableOccurrence const* lhs, VariableOccurrence const* rhs) -> bool + { + return *lhs < *rhs; } ); - for (auto const* returnVal: unassignedOrdered) + + for (auto const* variableOccurrence: uninitializedAccessesOrdered) { SecondarySourceLocation ssl; - for (CFGNode* lastNodeBeforeExit: _functionExit->entries) - if (unassigned[lastNodeBeforeExit].count(returnVal)) - { - if (!!lastNodeBeforeExit->block.returnStatement) - ssl.append("Problematic return:", lastNodeBeforeExit->block.returnStatement->location()); - else - ssl.append("Problematic end of function:", _function.location()); - } + if (variableOccurrence->occurrence()) + ssl.append("The variable was declared here.", variableOccurrence->declaration().location()); m_errorReporter.typeError( - returnVal->location(), + variableOccurrence->occurrence() ? + variableOccurrence->occurrence()->location() : + variableOccurrence->declaration().location(), ssl, - "This variable is of storage pointer type and might be returned without assignment and " - "could be used uninitialized. Assign the variable (potentially from itself) " - "to fix this error." + string("This variable is of storage pointer type and can be ") + + (variableOccurrence->kind() == VariableOccurrence::Kind::Return ? "returned" : "accessed") + + " without prior assignment." ); } } diff --git a/libsolidity/analysis/ControlFlowAnalyzer.h b/libsolidity/analysis/ControlFlowAnalyzer.h index 411d57ff..859d826a 100644 --- a/libsolidity/analysis/ControlFlowAnalyzer.h +++ b/libsolidity/analysis/ControlFlowAnalyzer.h @@ -37,12 +37,8 @@ public: bool visit(FunctionDefinition const& _function) override; private: - static std::set<VariableDeclaration const*> variablesAssignedInNode(CFGNode const *node); - void checkUnassignedStorageReturnValues( - FunctionDefinition const& _function, - CFGNode const* _functionEntry, - CFGNode const* _functionExit - ) const; + /// Checks for uninitialized variable accesses in the control flow between @param _entry and @param _exit. + void checkUninitializedAccess(CFGNode const* _entry, CFGNode const* _exit) const; CFG const& m_cfg; langutil::ErrorReporter& m_errorReporter; diff --git a/libsolidity/analysis/ControlFlowBuilder.cpp b/libsolidity/analysis/ControlFlowBuilder.cpp index 5bd39da3..3dab8b16 100644 --- a/libsolidity/analysis/ControlFlowBuilder.cpp +++ b/libsolidity/analysis/ControlFlowBuilder.cpp @@ -22,7 +22,10 @@ using namespace solidity; using namespace std; ControlFlowBuilder::ControlFlowBuilder(CFG::NodeContainer& _nodeContainer, FunctionFlow const& _functionFlow): - m_nodeContainer(_nodeContainer), m_currentFunctionFlow(_functionFlow), m_currentNode(_functionFlow.entry) + m_nodeContainer(_nodeContainer), + m_currentNode(_functionFlow.entry), + m_returnNode(_functionFlow.exit), + m_revertNode(_functionFlow.revert) { } @@ -37,26 +40,8 @@ unique_ptr<FunctionFlow> ControlFlowBuilder::createFunctionFlow( functionFlow->revert = _nodeContainer.newNode(); ControlFlowBuilder builder(_nodeContainer, *functionFlow); builder.appendControlFlow(_function); - connect(builder.m_currentNode, functionFlow->exit); - return functionFlow; -} - -unique_ptr<ModifierFlow> ControlFlowBuilder::createModifierFlow( - CFG::NodeContainer& _nodeContainer, - ModifierDefinition const& _modifier -) -{ - auto modifierFlow = unique_ptr<ModifierFlow>(new ModifierFlow()); - modifierFlow->entry = _nodeContainer.newNode(); - modifierFlow->exit = _nodeContainer.newNode(); - modifierFlow->revert = _nodeContainer.newNode(); - modifierFlow->placeholderEntry = _nodeContainer.newNode(); - modifierFlow->placeholderExit = _nodeContainer.newNode(); - ControlFlowBuilder builder(_nodeContainer, *modifierFlow); - builder.appendControlFlow(_modifier); - connect(builder.m_currentNode, modifierFlow->exit); - return modifierFlow; + return functionFlow; } bool ControlFlowBuilder::visit(BinaryOperation const& _operation) @@ -219,64 +204,24 @@ bool ControlFlowBuilder::visit(Continue const&) bool ControlFlowBuilder::visit(Throw const&) { solAssert(!!m_currentNode, ""); - solAssert(!!m_currentFunctionFlow.revert, ""); - connect(m_currentNode, m_currentFunctionFlow.revert); + solAssert(!!m_revertNode, ""); + connect(m_currentNode, m_revertNode); m_currentNode = newLabel(); return false; } -bool ControlFlowBuilder::visit(Block const&) -{ - solAssert(!!m_currentNode, ""); - createLabelHere(); - return true; -} - -void ControlFlowBuilder::endVisit(Block const&) -{ - solAssert(!!m_currentNode, ""); - createLabelHere(); -} - -bool ControlFlowBuilder::visit(Return const& _return) -{ - solAssert(!!m_currentNode, ""); - solAssert(!!m_currentFunctionFlow.exit, ""); - solAssert(!m_currentNode->block.returnStatement, ""); - m_currentNode->block.returnStatement = &_return; - connect(m_currentNode, m_currentFunctionFlow.exit); - m_currentNode = newLabel(); - return true; -} - - bool ControlFlowBuilder::visit(PlaceholderStatement const&) { solAssert(!!m_currentNode, ""); - auto modifierFlow = dynamic_cast<ModifierFlow const*>(&m_currentFunctionFlow); - solAssert(!!modifierFlow, ""); - - connect(m_currentNode, modifierFlow->placeholderEntry); + solAssert(!!m_placeholderEntry, ""); + solAssert(!!m_placeholderExit, ""); + connect(m_currentNode, m_placeholderEntry); m_currentNode = newLabel(); - - connect(modifierFlow->placeholderExit, m_currentNode); + connect(m_placeholderExit, m_currentNode); return false; } -bool ControlFlowBuilder::visitNode(ASTNode const& node) -{ - solAssert(!!m_currentNode, ""); - if (auto const* expression = dynamic_cast<Expression const*>(&node)) - m_currentNode->block.expressions.emplace_back(expression); - else if (auto const* variableDeclaration = dynamic_cast<VariableDeclaration const*>(&node)) - m_currentNode->block.variableDeclarations.emplace_back(variableDeclaration); - else if (auto const* assembly = dynamic_cast<InlineAssembly const*>(&node)) - m_currentNode->block.inlineAssemblyStatements.emplace_back(assembly); - - return true; -} - bool ControlFlowBuilder::visit(FunctionCall const& _functionCall) { solAssert(!!m_currentNode, ""); @@ -286,19 +231,19 @@ bool ControlFlowBuilder::visit(FunctionCall const& _functionCall) switch (functionType->kind()) { case FunctionType::Kind::Revert: - solAssert(!!m_currentFunctionFlow.revert, ""); + solAssert(!!m_revertNode, ""); _functionCall.expression().accept(*this); ASTNode::listAccept(_functionCall.arguments(), *this); - connect(m_currentNode, m_currentFunctionFlow.revert); + connect(m_currentNode, m_revertNode); m_currentNode = newLabel(); return false; case FunctionType::Kind::Require: case FunctionType::Kind::Assert: { - solAssert(!!m_currentFunctionFlow.revert, ""); + solAssert(!!m_revertNode, ""); _functionCall.expression().accept(*this); ASTNode::listAccept(_functionCall.arguments(), *this); - connect(m_currentNode, m_currentFunctionFlow.revert); + connect(m_currentNode, m_revertNode); auto nextNode = newLabel(); connect(m_currentNode, nextNode); m_currentNode = nextNode; @@ -310,6 +255,183 @@ bool ControlFlowBuilder::visit(FunctionCall const& _functionCall) return ASTConstVisitor::visit(_functionCall); } +bool ControlFlowBuilder::visit(ModifierInvocation const& _modifierInvocation) +{ + if (auto arguments = _modifierInvocation.arguments()) + for (auto& argument: *arguments) + appendControlFlow(*argument); + + auto modifierDefinition = dynamic_cast<ModifierDefinition const*>( + _modifierInvocation.name()->annotation().referencedDeclaration + ); + if (!modifierDefinition) return false; + solAssert(!!modifierDefinition, ""); + solAssert(!!m_returnNode, ""); + + m_placeholderEntry = newLabel(); + m_placeholderExit = newLabel(); + + appendControlFlow(*modifierDefinition); + connect(m_currentNode, m_returnNode); + + m_currentNode = m_placeholderEntry; + m_returnNode = m_placeholderExit; + + m_placeholderEntry = nullptr; + m_placeholderExit = nullptr; + + return false; +} + +bool ControlFlowBuilder::visit(FunctionDefinition const& _functionDefinition) +{ + for (auto const& parameter: _functionDefinition.parameters()) + appendControlFlow(*parameter); + + for (auto const& returnParameter: _functionDefinition.returnParameters()) + { + appendControlFlow(*returnParameter); + m_returnNode->variableOccurrences.emplace_back( + *returnParameter, + VariableOccurrence::Kind::Return, + nullptr + ); + + } + + for (auto const& modifier: _functionDefinition.modifiers()) + appendControlFlow(*modifier); + + appendControlFlow(_functionDefinition.body()); + + connect(m_currentNode, m_returnNode); + m_currentNode = nullptr; + + return false; +} + +bool ControlFlowBuilder::visit(Return const& _return) +{ + solAssert(!!m_currentNode, ""); + solAssert(!!m_returnNode, ""); + if (_return.expression()) + { + appendControlFlow(*_return.expression()); + // Returns with return expression are considered to be assignments to the return parameters. + for (auto returnParameter: _return.annotation().functionReturnParameters->parameters()) + m_currentNode->variableOccurrences.emplace_back( + *returnParameter, + VariableOccurrence::Kind::Assignment, + &_return + ); + } + connect(m_currentNode, m_returnNode); + m_currentNode = newLabel(); + return true; +} + +bool ControlFlowBuilder::visit(FunctionTypeName const&) +{ + // Do not visit the parameters and return values of a function type name. + // We do not want to consider them as variable declarations for the control flow graph. + return false; +} + +bool ControlFlowBuilder::visit(InlineAssembly const& _inlineAssembly) +{ + solAssert(!!m_currentNode, ""); + for (auto const& ref: _inlineAssembly.annotation().externalReferences) + { + if (auto variableDeclaration = dynamic_cast<VariableDeclaration const*>(ref.second.declaration)) + m_currentNode->variableOccurrences.emplace_back( + *variableDeclaration, + VariableOccurrence::Kind::InlineAssembly, + &_inlineAssembly + ); + } + return true; +} + +bool ControlFlowBuilder::visit(VariableDeclaration const& _variableDeclaration) +{ + solAssert(!!m_currentNode, ""); + + m_currentNode->variableOccurrences.emplace_back( + _variableDeclaration, + VariableOccurrence::Kind::Declaration, + nullptr + ); + + // Handle declaration with immediate assignment. + if (_variableDeclaration.value()) + m_currentNode->variableOccurrences.emplace_back( + _variableDeclaration, + VariableOccurrence::Kind::Assignment, + _variableDeclaration.value().get() + ); + // Function arguments are considered to be immediately assigned as well (they are "externally assigned"). + else if (_variableDeclaration.isCallableParameter() && !_variableDeclaration.isReturnParameter()) + m_currentNode->variableOccurrences.emplace_back( + _variableDeclaration, + VariableOccurrence::Kind::Assignment, + nullptr + ); + return true; +} + +bool ControlFlowBuilder::visit(VariableDeclarationStatement const& _variableDeclarationStatement) +{ + solAssert(!!m_currentNode, ""); + + for (auto const& var: _variableDeclarationStatement.declarations()) + if (var) + var->accept(*this); + if (_variableDeclarationStatement.initialValue()) + { + _variableDeclarationStatement.initialValue()->accept(*this); + for (size_t i = 0; i < _variableDeclarationStatement.declarations().size(); i++) + if (auto const& var = _variableDeclarationStatement.declarations()[i]) + { + auto expression = _variableDeclarationStatement.initialValue(); + if (auto tupleExpression = dynamic_cast<TupleExpression const*>(expression)) + if (tupleExpression->components().size() > 1) + { + solAssert(tupleExpression->components().size() > i, ""); + expression = tupleExpression->components()[i].get(); + } + while (auto tupleExpression = dynamic_cast<TupleExpression const*>(expression)) + if (tupleExpression->components().size() == 1) + expression = tupleExpression->components().front().get(); + else + break; + m_currentNode->variableOccurrences.emplace_back( + *var, + VariableOccurrence::Kind::Assignment, + expression + ); + } + } + return false; +} + +bool ControlFlowBuilder::visit(Identifier const& _identifier) +{ + solAssert(!!m_currentNode, ""); + + if (auto const* variableDeclaration = dynamic_cast<VariableDeclaration const*>(_identifier.annotation().referencedDeclaration)) + m_currentNode->variableOccurrences.emplace_back( + *variableDeclaration, + static_cast<Expression const&>(_identifier).annotation().lValueRequested ? + VariableOccurrence::Kind::Assignment : + VariableOccurrence::Kind::Access, + &_identifier + ); + + return true; +} + + + void ControlFlowBuilder::appendControlFlow(ASTNode const& _node) { _node.accept(*this); diff --git a/libsolidity/analysis/ControlFlowBuilder.h b/libsolidity/analysis/ControlFlowBuilder.h index 40605e00..f196e5fc 100644 --- a/libsolidity/analysis/ControlFlowBuilder.h +++ b/libsolidity/analysis/ControlFlowBuilder.h @@ -38,14 +38,11 @@ public: CFG::NodeContainer& _nodeContainer, FunctionDefinition const& _function ); - static std::unique_ptr<ModifierFlow> createModifierFlow( - CFG::NodeContainer& _nodeContainer, - ModifierDefinition const& _modifier - ); private: explicit ControlFlowBuilder(CFG::NodeContainer& _nodeContainer, FunctionFlow const& _functionFlow); + // Visits for constructing the control flow. bool visit(BinaryOperation const& _operation) override; bool visit(Conditional const& _conditional) override; bool visit(IfStatement const& _ifStatement) override; @@ -54,12 +51,20 @@ private: bool visit(Break const&) override; bool visit(Continue const&) override; bool visit(Throw const&) override; - bool visit(Block const&) override; - void endVisit(Block const&) override; - bool visit(Return const& _return) override; bool visit(PlaceholderStatement const&) override; bool visit(FunctionCall const& _functionCall) override; + bool visit(ModifierInvocation const& _modifierInvocation) override; + + // Visits for constructing the control flow as well as filling variable occurrences. + bool visit(FunctionDefinition const& _functionDefinition) override; + bool visit(Return const& _return) override; + // Visits for filling variable occurrences. + bool visit(FunctionTypeName const& _functionTypeName) override; + bool visit(InlineAssembly const& _inlineAssembly) override; + bool visit(VariableDeclaration const& _variableDeclaration) override; + bool visit(VariableDeclarationStatement const& _variableDeclarationStatement) override; + bool visit(Identifier const& _identifier) override; /// Appends the control flow of @a _node to the current control flow. void appendControlFlow(ASTNode const& _node); @@ -73,9 +78,6 @@ private: static void connect(CFGNode* _from, CFGNode* _to); -protected: - bool visitNode(ASTNode const& node) override; - private: /// Splits the control flow starting at the current node into n paths. @@ -114,17 +116,18 @@ private: CFG::NodeContainer& m_nodeContainer; - /// The control flow of the function that is currently parsed. - /// Note: this can also be a ModifierFlow - FunctionFlow const& m_currentFunctionFlow; - CFGNode* m_currentNode = nullptr; + CFGNode* m_returnNode = nullptr; + CFGNode* m_revertNode = nullptr; /// The current jump destination of break Statements. CFGNode* m_breakJump = nullptr; /// The current jump destination of continue Statements. CFGNode* m_continueJump = nullptr; + CFGNode* m_placeholderEntry = nullptr; + CFGNode* m_placeholderExit = nullptr; + /// Helper class that replaces the break and continue jump destinations for the /// current scope and restores the originals at the end of the scope. class BreakContinueScope diff --git a/libsolidity/analysis/ControlFlowGraph.cpp b/libsolidity/analysis/ControlFlowGraph.cpp index b8860158..a7cc9508 100644 --- a/libsolidity/analysis/ControlFlowGraph.cpp +++ b/libsolidity/analysis/ControlFlowGraph.cpp @@ -29,20 +29,14 @@ using namespace dev::solidity; bool CFG::constructFlow(ASTNode const& _astRoot) { _astRoot.accept(*this); - applyModifiers(); return Error::containsOnlyWarnings(m_errorReporter.errors()); } -bool CFG::visit(ModifierDefinition const& _modifier) -{ - m_modifierControlFlow[&_modifier] = ControlFlowBuilder::createModifierFlow(m_nodeContainer, _modifier); - return false; -} - bool CFG::visit(FunctionDefinition const& _function) { - m_functionControlFlow[&_function] = ControlFlowBuilder::createFunctionFlow(m_nodeContainer, _function); + if (_function.isImplemented()) + m_functionControlFlow[&_function] = ControlFlowBuilder::createFunctionFlow(m_nodeContainer, _function); return false; } @@ -57,81 +51,3 @@ CFGNode* CFG::NodeContainer::newNode() m_nodes.emplace_back(new CFGNode()); return m_nodes.back().get(); } - -void CFG::applyModifiers() -{ - for (auto const& function: m_functionControlFlow) - { - for (auto const& modifierInvocation: boost::adaptors::reverse(function.first->modifiers())) - { - if (auto modifierDefinition = dynamic_cast<ModifierDefinition const*>( - modifierInvocation->name()->annotation().referencedDeclaration - )) - { - solAssert(m_modifierControlFlow.count(modifierDefinition), ""); - applyModifierFlowToFunctionFlow(*m_modifierControlFlow[modifierDefinition], function.second.get()); - } - } - } -} - -void CFG::applyModifierFlowToFunctionFlow( - ModifierFlow const& _modifierFlow, - FunctionFlow* _functionFlow -) -{ - solAssert(!!_functionFlow, ""); - - map<CFGNode*, CFGNode*> copySrcToCopyDst; - - // inherit the revert node of the function - copySrcToCopyDst[_modifierFlow.revert] = _functionFlow->revert; - - // replace the placeholder nodes by the function entry and exit - copySrcToCopyDst[_modifierFlow.placeholderEntry] = _functionFlow->entry; - copySrcToCopyDst[_modifierFlow.placeholderExit] = _functionFlow->exit; - - stack<CFGNode*> nodesToCopy; - nodesToCopy.push(_modifierFlow.entry); - - // map the modifier entry to a new node that will become the new function entry - copySrcToCopyDst[_modifierFlow.entry] = m_nodeContainer.newNode(); - - while (!nodesToCopy.empty()) - { - CFGNode* copySrcNode = nodesToCopy.top(); - nodesToCopy.pop(); - - solAssert(copySrcToCopyDst.count(copySrcNode), ""); - - CFGNode* copyDstNode = copySrcToCopyDst[copySrcNode]; - - copyDstNode->block = copySrcNode->block; - for (auto const& entry: copySrcNode->entries) - { - if (!copySrcToCopyDst.count(entry)) - { - copySrcToCopyDst[entry] = m_nodeContainer.newNode(); - nodesToCopy.push(entry); - } - copyDstNode->entries.emplace_back(copySrcToCopyDst[entry]); - } - for (auto const& exit: copySrcNode->exits) - { - if (!copySrcToCopyDst.count(exit)) - { - copySrcToCopyDst[exit] = m_nodeContainer.newNode(); - nodesToCopy.push(exit); - } - copyDstNode->exits.emplace_back(copySrcToCopyDst[exit]); - } - } - - // if the modifier control flow never reached its exit node, - // we need to create a new (disconnected) exit node now - if (!copySrcToCopyDst.count(_modifierFlow.exit)) - copySrcToCopyDst[_modifierFlow.exit] = m_nodeContainer.newNode(); - - _functionFlow->entry = copySrcToCopyDst[_modifierFlow.entry]; - _functionFlow->exit = copySrcToCopyDst[_modifierFlow.exit]; -} diff --git a/libsolidity/analysis/ControlFlowGraph.h b/libsolidity/analysis/ControlFlowGraph.h index 8fe9fe8e..db8e1565 100644 --- a/libsolidity/analysis/ControlFlowGraph.h +++ b/libsolidity/analysis/ControlFlowGraph.h @@ -31,25 +31,57 @@ namespace dev namespace solidity { -/** Basic Control Flow Block. - * Basic block of control flow. Consists of a set of (unordered) AST nodes - * for which control flow is always linear. A basic control flow block - * encompasses at most one scope. Reverts are considered to break the control - * flow. - * @todo Handle function calls correctly. So far function calls are not considered - * to change the control flow. - */ -struct ControlFlowBlock +/** Occurrence of a variable in a block of control flow. + * Stores the declaration of the referenced variable, the + * kind of the occurrence and possibly the node at which + * it occurred. + */ +class VariableOccurrence { - /// All variable declarations inside this control flow block. - std::vector<VariableDeclaration const*> variableDeclarations; - /// All expressions inside this control flow block (this includes all subexpressions!). - std::vector<Expression const*> expressions; - /// All inline assembly statements inside in this control flow block. - std::vector<InlineAssembly const*> inlineAssemblyStatements; - /// If control flow returns in this node, the return statement is stored in returnStatement, - /// otherwise returnStatement is nullptr. - Return const* returnStatement = nullptr; +public: + enum class Kind + { + Declaration, + Access, + Return, + Assignment, + InlineAssembly + }; + VariableOccurrence(VariableDeclaration const& _declaration, Kind _kind, ASTNode const* _occurrence): + m_declaration(_declaration), m_occurrenceKind(_kind), m_occurrence(_occurrence) + { + } + + /// Defines a deterministic order on variable occurrences. + bool operator<(VariableOccurrence const& _rhs) const + { + if (m_occurrence && _rhs.m_occurrence) + { + if (m_occurrence->id() < _rhs.m_occurrence->id()) return true; + if (_rhs.m_occurrence->id() < m_occurrence->id()) return false; + } + else if (_rhs.m_occurrence) + return true; + else if (m_occurrence) + return false; + + using KindCompareType = std::underlying_type<VariableOccurrence::Kind>::type; + return + std::make_pair(m_declaration.id(), static_cast<KindCompareType>(m_occurrenceKind)) < + std::make_pair(_rhs.m_declaration.id(), static_cast<KindCompareType>(_rhs.m_occurrenceKind)) + ; + } + + VariableDeclaration const& declaration() const { return m_declaration; } + Kind kind() const { return m_occurrenceKind; }; + ASTNode const* occurrence() const { return m_occurrence; } +private: + /// Declaration of the occurring variable. + VariableDeclaration const& m_declaration; + /// Kind of occurrence. + Kind m_occurrenceKind = Kind::Access; + /// AST node at which the variable occurred, if available (may be nullptr). + ASTNode const* m_occurrence = nullptr; }; /** Node of the Control Flow Graph. @@ -64,8 +96,8 @@ struct CFGNode /// Exit nodes. All CFG nodes to which control flow may continue after this node. std::vector<CFGNode*> exits; - /// Control flow in the node. - ControlFlowBlock block; + /// Variable occurrences in the node. + std::vector<VariableOccurrence> variableOccurrences; }; /** Describes the control flow of a function. */ @@ -85,19 +117,6 @@ struct FunctionFlow CFGNode* revert = nullptr; }; -/** Describes the control flow of a modifier. - * Every placeholder breaks the control flow. The node preceding the - * placeholder is assigned placeholderEntry as exit and the node - * following the placeholder is assigned placeholderExit as entry. - */ -struct ModifierFlow: FunctionFlow -{ - /// Control flow leading towards a placeholder exit in placeholderEntry. - CFGNode* placeholderEntry = nullptr; - /// Control flow coming from a placeholder enter from placeholderExit. - CFGNode* placeholderExit = nullptr; -}; - class CFG: private ASTConstVisitor { public: @@ -105,7 +124,6 @@ public: bool constructFlow(ASTNode const& _astRoot); - bool visit(ModifierDefinition const& _modifier) override; bool visit(FunctionDefinition const& _function) override; FunctionFlow const& functionFlow(FunctionDefinition const& _function) const; @@ -118,20 +136,6 @@ public: std::vector<std::unique_ptr<CFGNode>> m_nodes; }; private: - /// Initially the control flow for all functions *ignoring* modifiers and for - /// all modifiers is constructed. Afterwards the control flow of functions - /// is adjusted by applying all modifiers. - void applyModifiers(); - - /// Creates a copy of the modifier flow @a _modifierFlow, while replacing the - /// placeholder entry and exit with the function entry and exit, as well as - /// replacing the modifier revert node with the function's revert node. - /// The resulting control flow is the new function flow with the modifier applied. - /// @a _functionFlow is updated in-place. - void applyModifierFlowToFunctionFlow( - ModifierFlow const& _modifierFlow, - FunctionFlow* _functionFlow - ); langutil::ErrorReporter& m_errorReporter; @@ -141,7 +145,6 @@ private: NodeContainer m_nodeContainer; std::map<FunctionDefinition const*, std::unique_ptr<FunctionFlow>> m_functionControlFlow; - std::map<ModifierDefinition const*, std::unique_ptr<ModifierFlow>> m_modifierControlFlow; }; } diff --git a/libsolidity/analysis/StaticAnalyzer.cpp b/libsolidity/analysis/StaticAnalyzer.cpp index 38391841..4d0f3461 100644 --- a/libsolidity/analysis/StaticAnalyzer.cpp +++ b/libsolidity/analysis/StaticAnalyzer.cpp @@ -63,21 +63,21 @@ bool StaticAnalyzer::visit(FunctionDefinition const& _function) void StaticAnalyzer::endVisit(FunctionDefinition const&) { - m_currentFunction = nullptr; - m_constructor = false; - for (auto const& var: m_localVarUseCount) - if (var.second == 0) - { - if (var.first.second->isCallableParameter()) - m_errorReporter.warning( - var.first.second->location(), - "Unused function parameter. Remove or comment out the variable name to silence this warning." - ); - else - m_errorReporter.warning(var.first.second->location(), "Unused local variable."); - } - + if (m_currentFunction && !m_currentFunction->body().statements().empty()) + for (auto const& var: m_localVarUseCount) + if (var.second == 0) + { + if (var.first.second->isCallableParameter()) + m_errorReporter.warning( + var.first.second->location(), + "Unused function parameter. Remove or comment out the variable name to silence this warning." + ); + else + m_errorReporter.warning(var.first.second->location(), "Unused local variable."); + } m_localVarUseCount.clear(); + m_constructor = false; + m_currentFunction = nullptr; } bool StaticAnalyzer::visit(Identifier const& _identifier) diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp index 1112d682..bd3071b3 100644 --- a/libsolidity/analysis/ViewPureChecker.cpp +++ b/libsolidity/analysis/ViewPureChecker.cpp @@ -156,6 +156,7 @@ void ViewPureChecker::endVisit(FunctionDefinition const& _funDef) m_bestMutabilityAndLocation.mutability < _funDef.stateMutability() && _funDef.stateMutability() != StateMutability::Payable && _funDef.isImplemented() && + !_funDef.body().statements().empty() && !_funDef.isConstructor() && !_funDef.isFallback() && !_funDef.annotation().superFunction diff --git a/libsolidity/codegen/ExpressionCompiler.h b/libsolidity/codegen/ExpressionCompiler.h index 2bfaab43..e9345ece 100644 --- a/libsolidity/codegen/ExpressionCompiler.h +++ b/libsolidity/codegen/ExpressionCompiler.h @@ -21,6 +21,8 @@ * Solidity AST to EVM bytecode compiler for expressions. */ +#pragma once + #include <functional> #include <memory> #include <boost/noncopyable.hpp> diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 862b6633..21d213e7 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -27,7 +27,10 @@ #include <libdevcore/JSON.h> #include <libdevcore/Keccak256.h> +#include <algorithm> + #include <boost/algorithm/string.hpp> +#include <boost/optional.hpp> using namespace std; using namespace dev; @@ -225,6 +228,50 @@ Json::Value collectEVMObject(eth::LinkerObject const& _object, string const* _so return output; } +boost::optional<Json::Value> checkKeys(Json::Value const& _input, set<string> const& _keys) +{ + for (auto const& member: _input.getMemberNames()) + if (!_keys.count(member)) + return formatFatalError("JSONError", "Unknown key \"" + member + "\""); + return boost::none; +} + +boost::optional<Json::Value> checkRootKeys(Json::Value const& _input) +{ + static set<string> keys{"auxiliaryInput", "language", "settings", "sources"}; + return checkKeys(_input, keys); +} + +boost::optional<Json::Value> checkSourceKeys(Json::Value const& _input) +{ + static set<string> keys{"content", "keccak256", "urls"}; + return checkKeys(_input, keys); +} + +boost::optional<Json::Value> checkAuxiliaryInputKeys(Json::Value const& _input) +{ + static set<string> keys{"smtlib2responses"}; + return checkKeys(_input, keys); +} + +boost::optional<Json::Value> checkSettingsKeys(Json::Value const& _input) +{ + static set<string> keys{"evmVersion", "libraries", "metadata", "optimizer", "outputSelection", "remappings"}; + return checkKeys(_input, keys); +} + +boost::optional<Json::Value> checkOptimizerKeys(Json::Value const& _input) +{ + static set<string> keys{"enabled", "runs"}; + return checkKeys(_input, keys); +} + +boost::optional<Json::Value> checkMetadataKeys(Json::Value const& _input) +{ + static set<string> keys{"useLiteralContent"}; + return checkKeys(_input, keys); +} + } Json::Value StandardCompiler::compileInternal(Json::Value const& _input) @@ -234,6 +281,9 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) if (!_input.isObject()) return formatFatalError("JSONError", "Input is not a JSON object."); + if (auto result = checkRootKeys(_input)) + return *result; + if (_input["language"] != "Solidity") return formatFatalError("JSONError", "Only \"Solidity\" is supported as a language."); @@ -254,6 +304,9 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) if (!sources[sourceName].isObject()) return formatFatalError("JSONError", "Source input is not a JSON object."); + if (auto result = checkSourceKeys(sources[sourceName])) + return *result; + if (sources[sourceName]["keccak256"].isString()) hash = sources[sourceName]["keccak256"].asString(); @@ -319,6 +372,10 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) } Json::Value const& auxInputs = _input["auxiliaryInput"]; + + if (auto result = checkAuxiliaryInputKeys(auxInputs)) + return *result; + if (!!auxInputs) { Json::Value const& smtlib2Responses = auxInputs["smtlib2responses"]; @@ -341,6 +398,9 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) Json::Value const& settings = _input.get("settings", Json::Value()); + if (auto result = checkSettingsKeys(settings)) + return *result; + if (settings.isMember("evmVersion")) { if (!settings["evmVersion"].isString()) @@ -366,6 +426,10 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) if (settings.isMember("optimizer")) { Json::Value optimizerSettings = settings["optimizer"]; + + if (auto result = checkOptimizerKeys(optimizerSettings)) + return *result; + if (optimizerSettings.isMember("enabled")) { if (!optimizerSettings["enabled"].isBool()) @@ -427,6 +491,10 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) m_compilerStack.setLibraries(libraries); Json::Value metadataSettings = settings.get("metadata", Json::Value()); + + if (auto result = checkMetadataKeys(metadataSettings)) + return *result; + m_compilerStack.useMetadataLiteralSources(metadataSettings.get("useLiteralContent", Json::Value(false)).asBool()); Json::Value outputSelection = settings.get("outputSelection", Json::Value()); diff --git a/libyul/AsmPrinter.cpp b/libyul/AsmPrinter.cpp index eaaba9f3..a5b14953 100644 --- a/libyul/AsmPrinter.cpp +++ b/libyul/AsmPrinter.cpp @@ -40,14 +40,14 @@ using namespace dev::solidity; //@TODO source locations -string AsmPrinter::operator()(yul::Instruction const& _instruction) +string AsmPrinter::operator()(yul::Instruction const& _instruction) const { solAssert(!m_yul, ""); solAssert(isValidInstruction(_instruction.instruction), "Invalid instruction"); return boost::to_lower_copy(instructionInfo(_instruction.instruction).name); } -string AsmPrinter::operator()(Literal const& _literal) +string AsmPrinter::operator()(Literal const& _literal) const { switch (_literal.kind) { @@ -90,13 +90,13 @@ string AsmPrinter::operator()(Literal const& _literal) return "\"" + out + "\"" + appendTypeName(_literal.type); } -string AsmPrinter::operator()(Identifier const& _identifier) +string AsmPrinter::operator()(Identifier const& _identifier) const { solAssert(!_identifier.name.empty(), "Invalid identifier."); return _identifier.name.str(); } -string AsmPrinter::operator()(FunctionalInstruction const& _functionalInstruction) +string AsmPrinter::operator()(FunctionalInstruction const& _functionalInstruction) const { solAssert(!m_yul, ""); solAssert(isValidInstruction(_functionalInstruction.instruction), "Invalid instruction"); @@ -109,26 +109,26 @@ string AsmPrinter::operator()(FunctionalInstruction const& _functionalInstructio ")"; } -string AsmPrinter::operator()(ExpressionStatement const& _statement) +string AsmPrinter::operator()(ExpressionStatement const& _statement) const { return boost::apply_visitor(*this, _statement.expression); } -string AsmPrinter::operator()(Label const& _label) +string AsmPrinter::operator()(Label const& _label) const { solAssert(!m_yul, ""); solAssert(!_label.name.empty(), "Invalid label."); return _label.name.str() + ":"; } -string AsmPrinter::operator()(StackAssignment const& _assignment) +string AsmPrinter::operator()(StackAssignment const& _assignment) const { solAssert(!m_yul, ""); solAssert(!_assignment.variableName.name.empty(), "Invalid variable name."); return "=: " + (*this)(_assignment.variableName); } -string AsmPrinter::operator()(Assignment const& _assignment) +string AsmPrinter::operator()(Assignment const& _assignment) const { solAssert(_assignment.variableNames.size() >= 1, ""); string variables = (*this)(_assignment.variableNames.front()); @@ -137,7 +137,7 @@ string AsmPrinter::operator()(Assignment const& _assignment) return variables + " := " + boost::apply_visitor(*this, *_assignment.value); } -string AsmPrinter::operator()(VariableDeclaration const& _variableDeclaration) +string AsmPrinter::operator()(VariableDeclaration const& _variableDeclaration) const { string out = "let "; out += boost::algorithm::join( @@ -154,7 +154,7 @@ string AsmPrinter::operator()(VariableDeclaration const& _variableDeclaration) return out; } -string AsmPrinter::operator()(FunctionDefinition const& _functionDefinition) +string AsmPrinter::operator()(FunctionDefinition const& _functionDefinition) const { solAssert(!_functionDefinition.name.empty(), "Invalid function name."); string out = "function " + _functionDefinition.name.str() + "("; @@ -179,7 +179,7 @@ string AsmPrinter::operator()(FunctionDefinition const& _functionDefinition) return out + "\n" + (*this)(_functionDefinition.body); } -string AsmPrinter::operator()(FunctionCall const& _functionCall) +string AsmPrinter::operator()(FunctionCall const& _functionCall) const { return (*this)(_functionCall.functionName) + "(" + @@ -189,13 +189,13 @@ string AsmPrinter::operator()(FunctionCall const& _functionCall) ")"; } -string AsmPrinter::operator()(If const& _if) +string AsmPrinter::operator()(If const& _if) const { solAssert(_if.condition, "Invalid if condition."); return "if " + boost::apply_visitor(*this, *_if.condition) + "\n" + (*this)(_if.body); } -string AsmPrinter::operator()(Switch const& _switch) +string AsmPrinter::operator()(Switch const& _switch) const { solAssert(_switch.expression, "Invalid expression pointer."); string out = "switch " + boost::apply_visitor(*this, *_switch.expression); @@ -210,7 +210,7 @@ string AsmPrinter::operator()(Switch const& _switch) return out; } -string AsmPrinter::operator()(ForLoop const& _forLoop) +string AsmPrinter::operator()(ForLoop const& _forLoop) const { solAssert(_forLoop.condition, "Invalid for loop condition."); string out = "for "; @@ -224,7 +224,7 @@ string AsmPrinter::operator()(ForLoop const& _forLoop) return out; } -string AsmPrinter::operator()(Block const& _block) +string AsmPrinter::operator()(Block const& _block) const { if (_block.statements.empty()) return "{\n}"; diff --git a/libyul/AsmPrinter.h b/libyul/AsmPrinter.h index 61dfc18c..a1b9d6cd 100644 --- a/libyul/AsmPrinter.h +++ b/libyul/AsmPrinter.h @@ -36,21 +36,21 @@ class AsmPrinter: public boost::static_visitor<std::string> public: explicit AsmPrinter(bool _yul = false): m_yul(_yul) {} - std::string operator()(Instruction const& _instruction); - std::string operator()(Literal const& _literal); - std::string operator()(Identifier const& _identifier); - std::string operator()(FunctionalInstruction const& _functionalInstruction); - std::string operator()(ExpressionStatement const& _expr); - std::string operator()(Label const& _label); - std::string operator()(StackAssignment const& _assignment); - std::string operator()(Assignment const& _assignment); - std::string operator()(VariableDeclaration const& _variableDeclaration); - std::string operator()(FunctionDefinition const& _functionDefinition); - std::string operator()(FunctionCall const& _functionCall); - std::string operator()(If const& _if); - std::string operator()(Switch const& _switch); - std::string operator()(ForLoop const& _forLoop); - std::string operator()(Block const& _block); + std::string operator()(Instruction const& _instruction) const; + std::string operator()(Literal const& _literal) const; + std::string operator()(Identifier const& _identifier) const; + std::string operator()(FunctionalInstruction const& _functionalInstruction) const; + std::string operator()(ExpressionStatement const& _expr) const; + std::string operator()(Label const& _label) const; + std::string operator()(StackAssignment const& _assignment) const; + std::string operator()(Assignment const& _assignment) const; + std::string operator()(VariableDeclaration const& _variableDeclaration) const; + std::string operator()(FunctionDefinition const& _functionDefinition) const; + std::string operator()(FunctionCall const& _functionCall) const; + std::string operator()(If const& _if) const; + std::string operator()(Switch const& _switch) const; + std::string operator()(ForLoop const& _forLoop) const; + std::string operator()(Block const& _block) const; private: std::string formatTypedName(TypedName _variable) const; diff --git a/libyul/backends/evm/EVMCodeTransform.h b/libyul/backends/evm/EVMCodeTransform.h index 28ef4e45..7be6f892 100644 --- a/libyul/backends/evm/EVMCodeTransform.h +++ b/libyul/backends/evm/EVMCodeTransform.h @@ -18,6 +18,8 @@ * Common code generator for translating Yul / inline assembly to EVM and EVM1.5. */ +#pragma once + #include <libyul/backends/evm/EVMAssembly.h> #include <libyul/backends/evm/EVMDialect.h> diff --git a/libyul/backends/evm/EVMObjectCompiler.h b/libyul/backends/evm/EVMObjectCompiler.h index 057521a8..9325e072 100644 --- a/libyul/backends/evm/EVMObjectCompiler.h +++ b/libyul/backends/evm/EVMObjectCompiler.h @@ -18,6 +18,7 @@ * Compiler that transforms Yul Objects to EVM bytecode objects. */ +#pragma once namespace yul { diff --git a/libyul/optimiser/DataFlowAnalyzer.cpp b/libyul/optimiser/DataFlowAnalyzer.cpp index 64c67b38..7bff2c89 100644 --- a/libyul/optimiser/DataFlowAnalyzer.cpp +++ b/libyul/optimiser/DataFlowAnalyzer.cpp @@ -136,17 +136,22 @@ void DataFlowAnalyzer::operator()(Block& _block) void DataFlowAnalyzer::handleAssignment(set<YulString> const& _variables, Expression* _value) { + static Expression const zero{Literal{{}, LiteralKind::Number, YulString{"0"}, {}}}; clearValues(_variables); MovableChecker movableChecker; if (_value) movableChecker.visit(*_value); - if (_variables.size() == 1) + else + for (auto const& var: _variables) + m_value[var] = &zero; + + if (_value && _variables.size() == 1) { YulString name = *_variables.begin(); // Expression has to be movable and cannot contain a reference // to the variable that will be assigned to. - if (_value && movableChecker.movable() && !movableChecker.referencedVariables().count(name)) + if (movableChecker.movable() && !movableChecker.referencedVariables().count(name)) m_value[name] = _value; } diff --git a/libyul/optimiser/DataFlowAnalyzer.h b/libyul/optimiser/DataFlowAnalyzer.h index cd134d48..4f12ff6a 100644 --- a/libyul/optimiser/DataFlowAnalyzer.h +++ b/libyul/optimiser/DataFlowAnalyzer.h @@ -36,6 +36,8 @@ namespace yul * Tracks assignments and is used as base class for both Rematerialiser and * Common Subexpression Eliminator. * + * A special zero constant expression is used for the default value of variables. + * * Prerequisite: Disambiguator */ class DataFlowAnalyzer: public ASTModifier diff --git a/libyul/optimiser/SSAValueTracker.cpp b/libyul/optimiser/SSAValueTracker.cpp index ef96c379..a0e44b2b 100644 --- a/libyul/optimiser/SSAValueTracker.cpp +++ b/libyul/optimiser/SSAValueTracker.cpp @@ -35,11 +35,12 @@ void SSAValueTracker::operator()(Assignment const& _assignment) void SSAValueTracker::operator()(VariableDeclaration const& _varDecl) { - if (_varDecl.variables.size() == 1) - setValue(_varDecl.variables.front().name, _varDecl.value.get()); - else if (!_varDecl.value) + static Expression const zero{Literal{{}, LiteralKind::Number, YulString{"0"}, {}}}; + if (!_varDecl.value) for (auto const& var: _varDecl.variables) - setValue(var.name, nullptr); + setValue(var.name, &zero); + else if (_varDecl.variables.size() == 1) + setValue(_varDecl.variables.front().name, _varDecl.value.get()); } void SSAValueTracker::setValue(YulString _name, Expression const* _value) diff --git a/libyul/optimiser/SSAValueTracker.h b/libyul/optimiser/SSAValueTracker.h index efec2200..0a6cde80 100644 --- a/libyul/optimiser/SSAValueTracker.h +++ b/libyul/optimiser/SSAValueTracker.h @@ -33,7 +33,7 @@ namespace yul * Class that walks the AST and stores the initial value of each variable * that is never assigned to. * - * Default value is represented as nullptr. + * A special zero constant expression is used for the default value of variables. * * Prerequisite: Disambiguator */ diff --git a/scripts/release_ppa.sh b/scripts/release_ppa.sh index e842bd53..4ba0e644 100755 --- a/scripts/release_ppa.sh +++ b/scripts/release_ppa.sh @@ -28,6 +28,12 @@ ## method = ftp ## incoming = ~ethereum/ethereum ## login = anonymous +## +## [ethereum-static] +## fqdn = ppa.launchpad.net +## method = ftp +## incoming = ~ethereum/ethereum-static +## login = anonymous ## ############################################################################## @@ -41,34 +47,36 @@ else branch=$1 fi -if [ "$branch" = develop ] -then - pparepo=ethereum-dev - ppafilesurl=https://launchpad.net/~ethereum/+archive/ubuntu/ethereum-dev/+files -else - pparepo=ethereum - ppafilesurl=https://launchpad.net/~ethereum/+archive/ubuntu/ethereum/+files -fi - keyid=70D110489D66E2F6 email=builds@ethereum.org packagename=solc -for distribution in trusty xenial bionic cosmic +static_build_distribution=cosmic + +for distribution in xenial bionic cosmic STATIC do cd /tmp/ rm -rf $distribution mkdir $distribution cd $distribution -# Dependency -if [ $distribution = trusty -o $distribution = vivid ] +if [ $distribution = STATIC ] then + pparepo=ethereum-static Z3DEPENDENCY="" + CMAKE_OPTIONS="-DSOLC_LINK_STATIC=On" else + if [ "$branch" = develop ] + then + pparepo=ethereum-dev + else + pparepo=ethereum + fi Z3DEPENDENCY="libz3-dev, " + CMAKE_OPTIONS="" fi +ppafilesurl=https://launchpad.net/~ethereum/+archive/ubuntu/${pparepo}/+files # Fetch source git clone --depth 2 --recursive https://github.com/ethereum/solidity.git -b "$branch" @@ -114,7 +122,7 @@ Priority: extra Maintainer: Christian (Buildserver key) <builds@ethereum.org> Build-Depends: ${Z3DEPENDENCY}debhelper (>= 9.0.0), cmake, - g++-8, + g++, git, libgmp-dev, libboost-all-dev, @@ -168,7 +176,7 @@ override_dh_shlibdeps: dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info override_dh_auto_configure: - dh_auto_configure -- -DINSTALL_LLLC=Off -DCMAKE_C_COMPILER=gcc-8 -DCMAKE_CXX_COMPILER=g++-8 + dh_auto_configure -- -DINSTALL_LLLC=Off -DTESTS=OFF ${CMAKE_OPTIONS} EOF cat <<EOF > debian/copyright Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ @@ -224,7 +232,12 @@ EMAIL="$email" dch -v 1:${debversion}-${versionsuffix} "git build of ${commithas debuild -S -d -sa -us -uc # prepare .changes file for Launchpad -sed -i -e s/UNRELEASED/${distribution}/ -e s/urgency=medium/urgency=low/ ../*.changes +if [ $distribution = STATIC ] +then + sed -i -e s/UNRELEASED/${static_build_distribution}/ -e s/urgency=medium/urgency=low/ ../*.changes +else + sed -i -e s/UNRELEASED/${distribution}/ -e s/urgency=medium/urgency=low/ ../*.changes +fi # check if ubuntu already has the source tarball ( diff --git a/scripts/tests.sh b/scripts/tests.sh index c284c05c..1a8a32cf 100755 --- a/scripts/tests.sh +++ b/scripts/tests.sh @@ -130,21 +130,14 @@ function download_aleth() elif [ -z $CI ]; then ALETH_PATH="aleth" else - # Any time the hash is updated here, the "Running compiler tests" section should also be updated. mkdir -p /tmp/test - if grep -i trusty /etc/lsb-release >/dev/null 2>&1 - then - # built from d661ac4fec0aeffbedcdc195f67f5ded0c798278 at 2018-06-20 - ALETH_BINARY=aleth_2018-06-20_trusty - ALETH_HASH="54b8a5455e45b295e3a962f353ff8f1580ed106c" - else - # built from d661ac4fec0aeffbedcdc195f67f5ded0c798278 at 2018-06-20 - ALETH_BINARY=aleth_2018-06-20_artful - ALETH_HASH="02e6c4b3d98299885e73f7db6c9e3fbe3d66d444" - fi - ALETH_PATH="/tmp/test/aleth" - wget -q -O $ALETH_PATH https://github.com/ethereum/cpp-ethereum/releases/download/solidityTester/$ALETH_BINARY - test "$(shasum $ALETH_PATH)" = "$ALETH_HASH $ALETH_PATH" + # Any time the hash is updated here, the "Running compiler tests" section should also be updated. + ALETH_HASH="8ce2f00539d2fd8b5f093d854c6999424f7494ff" + ALETH_VERSION=1.5.0-alpha.7 + wget -q -O /tmp/test/aleth.tar.gz https://github.com/ethereum/aleth/releases/download/v${ALETH_VERSION}/aleth-${ALETH_VERSION}-linux-x86_64.tar.gz + test "$(shasum /tmp/test/aleth.tar.gz)" = "$ALETH_HASH /tmp/test/aleth.tar.gz" + tar -xf /tmp/test/aleth.tar.gz -C /tmp/test + ALETH_PATH="/tmp/test/bin/aleth" sync chmod +x $ALETH_PATH sync # Otherwise we might get a "text file busy" error diff --git a/test/RPCSession.cpp b/test/RPCSession.cpp index 0aae21a7..60848118 100644 --- a/test/RPCSession.cpp +++ b/test/RPCSession.cpp @@ -296,40 +296,7 @@ void RPCSession::test_mineBlocks(int _number) { u256 startBlock = fromBigEndian<u256>(fromHex(rpcCall("eth_blockNumber").asString())); BOOST_REQUIRE(rpcCall("test_mineBlocks", { to_string(_number) }, true) == true); - - // We auto-calibrate the time it takes to mine the transaction. - // It would be better to go without polling, but that would probably need a change to the test client - - auto startTime = std::chrono::steady_clock::now(); - unsigned sleepTime = m_sleepTime; - size_t tries = 0; - for (; ; ++tries) - { - std::this_thread::sleep_for(chrono::milliseconds(sleepTime)); - auto endTime = std::chrono::steady_clock::now(); - unsigned timeSpent = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count(); - if (timeSpent > m_maxMiningTime) - BOOST_FAIL("Error in test_mineBlocks: block mining timeout!"); - if (fromBigEndian<u256>(fromHex(rpcCall("eth_blockNumber").asString())) >= startBlock + _number) - break; - else - sleepTime *= 2; - } - if (tries > 1) - { - m_successfulMineRuns = 0; - m_sleepTime += 2; - } - else if (tries == 1) - { - m_successfulMineRuns++; - if (m_successfulMineRuns > 5) - { - m_successfulMineRuns = 0; - if (m_sleepTime > 2) - m_sleepTime--; - } - } + BOOST_REQUIRE(fromBigEndian<u256>(fromHex(rpcCall("eth_blockNumber").asString())) == startBlock + _number); } void RPCSession::test_modifyTimestamp(size_t _timestamp) diff --git a/test/RPCSession.h b/test/RPCSession.h index 6e1391b4..92f9da4a 100644 --- a/test/RPCSession.h +++ b/test/RPCSession.h @@ -136,9 +136,6 @@ private: IPCSocket m_ipcSocket; size_t m_rpcSequence = 1; - unsigned m_maxMiningTime = 6000000; // 600 seconds - unsigned m_sleepTime = 10; // 10 milliseconds - unsigned m_successfulMineRuns = 0; bool m_receiptHasStatusField = false; std::vector<std::string> m_accounts; diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index 7b2b528b..bb71e012 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -113,20 +113,30 @@ printTask "Testing unknown options..." test_solc_behaviour() { local filename="${1}" local solc_args="${2}" - local stdout_expected="${3}" - local exit_code_expected="${4}" - local stderr_expected="${5}" + local solc_stdin="${3}" + local stdout_expected="${4}" + local exit_code_expected="${5}" + local stderr_expected="${6}" local stdout_path=`mktemp` local stderr_path=`mktemp` if [[ "$exit_code_expected" = "" ]]; then exit_code_expected="0"; fi set +e - "$SOLC" "${filename}" ${solc_args} 1>$stdout_path 2>$stderr_path + if [[ "$solc_stdin" = "" ]]; then + "$SOLC" "${filename}" ${solc_args} 1>$stdout_path 2>$stderr_path + else + "$SOLC" "${filename}" ${solc_args} <$solc_stdin 1>$stdout_path 2>$stderr_path + fi exitCode=$? set -e - sed -i -e '/^Warning: This is a pre-release compiler version, please do not use it in production./d' "$stderr_path" - sed -i -e 's/ Consider adding "pragma .*$//' "$stderr_path" + if [[ "$solc_args" == *"--standard-json"* ]]; then + sed -i -e 's/{[^{]*Warning: This is a pre-release compiler version[^}]*},\{0,1\}//' "$stdout_path" + sed -i -e 's/,"errors":\[\]//' "$stdout_path" + else + sed -i -e '/^Warning: This is a pre-release compiler version, please do not use it in production./d' "$stderr_path" + sed -i -e 's/ Consider adding "pragma .*$//' "$stderr_path" + fi if [[ $exitCode -ne "$exit_code_expected" ]]; then printError "Incorrect exit code. Expected $exit_code_expected but got $exitCode." @@ -158,14 +168,29 @@ test_solc_behaviour() { } printTask "Testing passing files that are not found..." -test_solc_behaviour "file_not_found.sol" "" "" 1 "\"file_not_found.sol\" is not found." +test_solc_behaviour "file_not_found.sol" "" "" "" 1 "\"file_not_found.sol\" is not found." printTask "Testing passing files that are not files..." -test_solc_behaviour "." "" "" 1 "\".\" is not a valid file." +test_solc_behaviour "." "" "" "" 1 "\".\" is not a valid file." printTask "Testing passing empty remappings..." -test_solc_behaviour "${0}" "=/some/remapping/target" "" 1 "Invalid remapping: \"=/some/remapping/target\"." -test_solc_behaviour "${0}" "ctx:=/some/remapping/target" "" 1 "Invalid remapping: \"ctx:=/some/remapping/target\"." +test_solc_behaviour "${0}" "=/some/remapping/target" "" "" 1 "Invalid remapping: \"=/some/remapping/target\"." +test_solc_behaviour "${0}" "ctx:=/some/remapping/target" "" "" 1 "Invalid remapping: \"ctx:=/some/remapping/target\"." + +printTask "Running standard JSON commandline tests..." +( +cd "$REPO_ROOT"/test/cmdlineTests/ +for file in *.json +do + args="--standard-json" + stdin="$REPO_ROOT/test/cmdlineTests/$file" + stdout=$(cat $file.stdout 2>/dev/null || true) + exitCode=$(cat $file.exit 2>/dev/null || true) + err=$(cat $file.err 2>/dev/null || true) + printTask " - $file" + test_solc_behaviour "" "$args" "$stdin" "$stdout" "$exitCode" "$err" +done +) printTask "Running general commandline tests..." ( @@ -177,7 +202,7 @@ do exitCode=$(cat $file.exit 2>/dev/null || true) err=$(cat $file.err 2>/dev/null || true) printTask " - $file" - test_solc_behaviour "$file" "$args" "$stdout" "$exitCode" "$err" + test_solc_behaviour "$file" "$args" "" "$stdout" "$exitCode" "$err" done ) diff --git a/test/cmdlineTests/standard.json b/test/cmdlineTests/standard.json new file mode 100644 index 00000000..826253b8 --- /dev/null +++ b/test/cmdlineTests/standard.json @@ -0,0 +1,10 @@ +{ + "language": "Solidity", + "sources": + { + "A": + { + "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + } + } +} diff --git a/test/cmdlineTests/standard.json.exit b/test/cmdlineTests/standard.json.exit new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/test/cmdlineTests/standard.json.exit @@ -0,0 +1 @@ +0 diff --git a/test/cmdlineTests/standard.json.stdout b/test/cmdlineTests/standard.json.stdout new file mode 100644 index 00000000..490e1f80 --- /dev/null +++ b/test/cmdlineTests/standard.json.stdout @@ -0,0 +1 @@ +{"contracts":{"A":{"C":{"evm":{}}}},"sources":{"A":{"id":0}}} diff --git a/test/cmdlineTests/standard_wrong_key_auxiliary_input.json b/test/cmdlineTests/standard_wrong_key_auxiliary_input.json new file mode 100644 index 00000000..51dbce41 --- /dev/null +++ b/test/cmdlineTests/standard_wrong_key_auxiliary_input.json @@ -0,0 +1,14 @@ +{ + "language": "Solidity", + "sources": + { + "A": + { + "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + } + }, + "auxiliaryInput": + { + "key1": "test" + } +} diff --git a/test/cmdlineTests/standard_wrong_key_auxiliary_input.json.exit b/test/cmdlineTests/standard_wrong_key_auxiliary_input.json.exit new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/test/cmdlineTests/standard_wrong_key_auxiliary_input.json.exit @@ -0,0 +1 @@ +0 diff --git a/test/cmdlineTests/standard_wrong_key_auxiliary_input.json.stdout b/test/cmdlineTests/standard_wrong_key_auxiliary_input.json.stdout new file mode 100644 index 00000000..077ac47e --- /dev/null +++ b/test/cmdlineTests/standard_wrong_key_auxiliary_input.json.stdout @@ -0,0 +1 @@ +{"errors":[{"component":"general","formattedMessage":"Unknown key \"key1\"","message":"Unknown key \"key1\"","severity":"error","type":"JSONError"}]} diff --git a/test/cmdlineTests/standard_wrong_key_metadata.json b/test/cmdlineTests/standard_wrong_key_metadata.json new file mode 100644 index 00000000..490e489a --- /dev/null +++ b/test/cmdlineTests/standard_wrong_key_metadata.json @@ -0,0 +1,22 @@ +{ + "language": "Solidity", + "sources": + { + "A": + { + "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + } + }, + "settings": + { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "evmVersion": "byzantium", + "metadata": { + "key1": "test", + "useLiteralContent": true + } + } +} diff --git a/test/cmdlineTests/standard_wrong_key_metadata.json.exit b/test/cmdlineTests/standard_wrong_key_metadata.json.exit new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/test/cmdlineTests/standard_wrong_key_metadata.json.exit @@ -0,0 +1 @@ +0 diff --git a/test/cmdlineTests/standard_wrong_key_metadata.json.stdout b/test/cmdlineTests/standard_wrong_key_metadata.json.stdout new file mode 100644 index 00000000..077ac47e --- /dev/null +++ b/test/cmdlineTests/standard_wrong_key_metadata.json.stdout @@ -0,0 +1 @@ +{"errors":[{"component":"general","formattedMessage":"Unknown key \"key1\"","message":"Unknown key \"key1\"","severity":"error","type":"JSONError"}]} diff --git a/test/cmdlineTests/standard_wrong_key_optimizer.json b/test/cmdlineTests/standard_wrong_key_optimizer.json new file mode 100644 index 00000000..c28c3a92 --- /dev/null +++ b/test/cmdlineTests/standard_wrong_key_optimizer.json @@ -0,0 +1,22 @@ +{ + "language": "Solidity", + "sources": + { + "A": + { + "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + } + }, + "settings": + { + "optimizer": { + "key1": "test", + "enabled": true, + "runs": 200 + }, + "evmVersion": "byzantium", + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/test/cmdlineTests/standard_wrong_key_optimizer.json.exit b/test/cmdlineTests/standard_wrong_key_optimizer.json.exit new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/test/cmdlineTests/standard_wrong_key_optimizer.json.exit @@ -0,0 +1 @@ +0 diff --git a/test/cmdlineTests/standard_wrong_key_optimizer.json.stdout b/test/cmdlineTests/standard_wrong_key_optimizer.json.stdout new file mode 100644 index 00000000..077ac47e --- /dev/null +++ b/test/cmdlineTests/standard_wrong_key_optimizer.json.stdout @@ -0,0 +1 @@ +{"errors":[{"component":"general","formattedMessage":"Unknown key \"key1\"","message":"Unknown key \"key1\"","severity":"error","type":"JSONError"}]} diff --git a/test/cmdlineTests/standard_wrong_key_root.json b/test/cmdlineTests/standard_wrong_key_root.json new file mode 100644 index 00000000..4689c50c --- /dev/null +++ b/test/cmdlineTests/standard_wrong_key_root.json @@ -0,0 +1,11 @@ +{ + "language": "Solidity", + "key1": "test", + "sources": + { + "A": + { + "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + } + } +} diff --git a/test/cmdlineTests/standard_wrong_key_root.json.exit b/test/cmdlineTests/standard_wrong_key_root.json.exit new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/test/cmdlineTests/standard_wrong_key_root.json.exit @@ -0,0 +1 @@ +0 diff --git a/test/cmdlineTests/standard_wrong_key_root.json.stdout b/test/cmdlineTests/standard_wrong_key_root.json.stdout new file mode 100644 index 00000000..077ac47e --- /dev/null +++ b/test/cmdlineTests/standard_wrong_key_root.json.stdout @@ -0,0 +1 @@ +{"errors":[{"component":"general","formattedMessage":"Unknown key \"key1\"","message":"Unknown key \"key1\"","severity":"error","type":"JSONError"}]} diff --git a/test/cmdlineTests/standard_wrong_key_settings.json b/test/cmdlineTests/standard_wrong_key_settings.json new file mode 100644 index 00000000..d7809b1c --- /dev/null +++ b/test/cmdlineTests/standard_wrong_key_settings.json @@ -0,0 +1,22 @@ +{ + "language": "Solidity", + "sources": + { + "A": + { + "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + } + }, + "settings": + { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "evmVersion": "byzantium", + "metadata": { + "useLiteralContent": true + }, + "key1": "test" + } +} diff --git a/test/cmdlineTests/standard_wrong_key_settings.json.exit b/test/cmdlineTests/standard_wrong_key_settings.json.exit new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/test/cmdlineTests/standard_wrong_key_settings.json.exit @@ -0,0 +1 @@ +0 diff --git a/test/cmdlineTests/standard_wrong_key_settings.json.stdout b/test/cmdlineTests/standard_wrong_key_settings.json.stdout new file mode 100644 index 00000000..077ac47e --- /dev/null +++ b/test/cmdlineTests/standard_wrong_key_settings.json.stdout @@ -0,0 +1 @@ +{"errors":[{"component":"general","formattedMessage":"Unknown key \"key1\"","message":"Unknown key \"key1\"","severity":"error","type":"JSONError"}]} diff --git a/test/cmdlineTests/standard_wrong_key_source.json b/test/cmdlineTests/standard_wrong_key_source.json new file mode 100644 index 00000000..d8a8aa16 --- /dev/null +++ b/test/cmdlineTests/standard_wrong_key_source.json @@ -0,0 +1,11 @@ +{ + "language": "Solidity", + "sources": + { + "A": + { + "key1": "test", + "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + } + } +} diff --git a/test/cmdlineTests/standard_wrong_key_source.json.exit b/test/cmdlineTests/standard_wrong_key_source.json.exit new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/test/cmdlineTests/standard_wrong_key_source.json.exit @@ -0,0 +1 @@ +0 diff --git a/test/cmdlineTests/standard_wrong_key_source.json.stdout b/test/cmdlineTests/standard_wrong_key_source.json.stdout new file mode 100644 index 00000000..077ac47e --- /dev/null +++ b/test/cmdlineTests/standard_wrong_key_source.json.stdout @@ -0,0 +1 @@ +{"errors":[{"component":"general","formattedMessage":"Unknown key \"key1\"","message":"Unknown key \"key1\"","severity":"error","type":"JSONError"}]} diff --git a/test/libsolidity/GasMeter.cpp b/test/libsolidity/GasMeter.cpp index 5535bd74..12c22604 100644 --- a/test/libsolidity/GasMeter.cpp +++ b/test/libsolidity/GasMeter.cpp @@ -62,7 +62,7 @@ public: ); } - void testCreationTimeGas(string const& _sourceCode) + void testCreationTimeGas(string const& _sourceCode, u256 const& _tolerance = u256(0)) { compileAndRun(_sourceCode); auto state = make_shared<KnownState>(); @@ -75,12 +75,13 @@ public: gas += gasForTransaction(m_compiler.object(m_compiler.lastContractName()).bytecode, true); BOOST_REQUIRE(!gas.isInfinite); - BOOST_CHECK_EQUAL(gas.value, m_gasUsed); + BOOST_CHECK_LE(m_gasUsed, gas.value); + BOOST_CHECK_LE(gas.value - _tolerance, m_gasUsed); } /// Compares the gas computed by PathGasMeter for the given signature (but unknown arguments) /// against the actual gas usage computed by the VM on the given set of argument variants. - void testRunTimeGas(string const& _sig, vector<bytes> _argumentVariants) + void testRunTimeGas(string const& _sig, vector<bytes> _argumentVariants, u256 const& _tolerance = u256(0)) { u256 gasUsed = 0; GasMeter::GasConsumption gas; @@ -98,7 +99,8 @@ public: _sig ); BOOST_REQUIRE(!gas.isInfinite); - BOOST_CHECK_EQUAL(gas.value, m_gasUsed); + BOOST_CHECK_LE(m_gasUsed, gas.value); + BOOST_CHECK_LE(gas.value - _tolerance, m_gasUsed); } static GasMeter::GasConsumption gasForTransaction(bytes const& _data, bool _isCreation) @@ -186,7 +188,7 @@ BOOST_AUTO_TEST_CASE(updating_store) } } )"; - testCreationTimeGas(sourceCode); + testCreationTimeGas(sourceCode, m_evmVersion < EVMVersion::constantinople() ? u256(0) : u256(9600)); } BOOST_AUTO_TEST_CASE(branches) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index dfa60fc5..8d219d16 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -3039,7 +3039,8 @@ BOOST_AUTO_TEST_CASE(gaslimit) } )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(gasLimit())); + auto result = callContractFunction("f()"); + ABI_CHECK(result, encodeArgs(gasLimit())); } BOOST_AUTO_TEST_CASE(gasprice) diff --git a/test/libsolidity/syntaxTests/controlFlow/mappingReturn/named_err.sol b/test/libsolidity/syntaxTests/controlFlow/mappingReturn/named_err.sol index 35420b6d..dbd3db08 100644 --- a/test/libsolidity/syntaxTests/controlFlow/mappingReturn/named_err.sol +++ b/test/libsolidity/syntaxTests/controlFlow/mappingReturn/named_err.sol @@ -2,4 +2,4 @@ contract C { function f() internal pure returns (mapping(uint=>uint) storage r) { } } // ---- -// TypeError: (53-82): This variable is of storage pointer type and might be returned without assignment and could be used uninitialized. Assign the variable (potentially from itself) to fix this error. +// TypeError: (53-82): This variable is of storage pointer type and can be returned without prior assignment. diff --git a/test/libsolidity/syntaxTests/controlFlow/mappingReturn/unnamed_err.sol b/test/libsolidity/syntaxTests/controlFlow/mappingReturn/unnamed_err.sol index 52a8b3d7..476e799b 100644 --- a/test/libsolidity/syntaxTests/controlFlow/mappingReturn/unnamed_err.sol +++ b/test/libsolidity/syntaxTests/controlFlow/mappingReturn/unnamed_err.sol @@ -2,4 +2,4 @@ contract C { function f() internal pure returns (mapping(uint=>uint) storage) {} } // ---- -// TypeError: (53-80): This variable is of storage pointer type and might be returned without assignment and could be used uninitialized. Assign the variable (potentially from itself) to fix this error. +// TypeError: (53-80): This variable is of storage pointer type and can be returned without prior assignment. diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly_err.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly_err.sol index cad9b8e8..a6df889d 100644 --- a/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly_err.sol +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly_err.sol @@ -7,4 +7,4 @@ contract C { } } // ---- -// TypeError: (87-96): This variable is of storage pointer type and might be returned without assignment and could be used uninitialized. Assign the variable (potentially from itself) to fix this error. +// TypeError: (87-96): This variable is of storage pointer type and can be returned without prior assignment. diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly_fine.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly_fine.sol deleted file mode 100644 index 0d3db856..00000000 --- a/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly_fine.sol +++ /dev/null @@ -1,26 +0,0 @@ -contract C { - struct S { bool f; } - S s; - function f() internal returns (S storage c) { - assembly { - sstore(c_slot, sload(s_slot)) - } - } - function g(bool flag) internal returns (S storage c) { - // control flow in assembly will not be analyzed for now, - // so this will not issue an error - assembly { - if flag { - sstore(c_slot, sload(s_slot)) - } - } - } - function h() internal returns (S storage c) { - // any reference from assembly will be sufficient for now, - // so this will not issue an error - assembly { - sstore(s_slot, sload(c_slot)) - } - } -} -// ---- diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/dowhile_err.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/dowhile_err.sol index eb574c96..b868d61d 100644 --- a/test/libsolidity/syntaxTests/controlFlow/storageReturn/dowhile_err.sol +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/dowhile_err.sol @@ -45,8 +45,8 @@ contract C { } } // ---- -// TypeError: (87-98): This variable is of storage pointer type and might be returned without assignment and could be used uninitialized. Assign the variable (potentially from itself) to fix this error. -// TypeError: (223-234): This variable is of storage pointer type and might be returned without assignment and could be used uninitialized. Assign the variable (potentially from itself) to fix this error. -// TypeError: (440-451): This variable is of storage pointer type and might be returned without assignment and could be used uninitialized. Assign the variable (potentially from itself) to fix this error. -// TypeError: (654-665): This variable is of storage pointer type and might be returned without assignment and could be used uninitialized. Assign the variable (potentially from itself) to fix this error. -// TypeError: (871-882): This variable is of storage pointer type and might be returned without assignment and could be used uninitialized. Assign the variable (potentially from itself) to fix this error. +// TypeError: (87-98): This variable is of storage pointer type and can be returned without prior assignment. +// TypeError: (223-234): This variable is of storage pointer type and can be returned without prior assignment. +// TypeError: (440-451): This variable is of storage pointer type and can be returned without prior assignment. +// TypeError: (654-665): This variable is of storage pointer type and can be returned without prior assignment. +// TypeError: (871-882): This variable is of storage pointer type and can be returned without prior assignment. diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/for_err.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/for_err.sol index 9aa580a4..d2dec9c1 100644 --- a/test/libsolidity/syntaxTests/controlFlow/storageReturn/for_err.sol +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/for_err.sol @@ -12,5 +12,5 @@ contract C { } } // ---- -// TypeError: (87-98): This variable is of storage pointer type and might be returned without assignment and could be used uninitialized. Assign the variable (potentially from itself) to fix this error. -// TypeError: (182-193): This variable is of storage pointer type and might be returned without assignment and could be used uninitialized. Assign the variable (potentially from itself) to fix this error. +// TypeError: (87-98): This variable is of storage pointer type and can be returned without prior assignment. +// TypeError: (182-193): This variable is of storage pointer type and can be returned without prior assignment. diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/if_err.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/if_err.sol index f3e55318..12ec31e4 100644 --- a/test/libsolidity/syntaxTests/controlFlow/storageReturn/if_err.sol +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/if_err.sol @@ -14,5 +14,5 @@ contract C { } } // ---- -// TypeError: (96-107): This variable is of storage pointer type and might be returned without assignment and could be used uninitialized. Assign the variable (potentially from itself) to fix this error. -// TypeError: (186-197): This variable is of storage pointer type and might be returned without assignment and could be used uninitialized. Assign the variable (potentially from itself) to fix this error. +// TypeError: (96-107): This variable is of storage pointer type and can be returned without prior assignment. +// TypeError: (186-197): This variable is of storage pointer type and can be returned without prior assignment. diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/modifier_err.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/modifier_err.sol index 42342979..ee1e08fd 100644 --- a/test/libsolidity/syntaxTests/controlFlow/storageReturn/modifier_err.sol +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/modifier_err.sol @@ -18,5 +18,5 @@ contract C { } } // ---- -// TypeError: (249-258): This variable is of storage pointer type and might be returned without assignment and could be used uninitialized. Assign the variable (potentially from itself) to fix this error. -// TypeError: (367-376): This variable is of storage pointer type and might be returned without assignment and could be used uninitialized. Assign the variable (potentially from itself) to fix this error. +// TypeError: (249-258): This variable is of storage pointer type and can be returned without prior assignment. +// TypeError: (367-376): This variable is of storage pointer type and can be returned without prior assignment. diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/short_circuit_err.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/short_circuit_err.sol index d0ad8245..e3579628 100644 --- a/test/libsolidity/syntaxTests/controlFlow/storageReturn/short_circuit_err.sol +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/short_circuit_err.sol @@ -13,6 +13,6 @@ contract C { } } // ---- -// TypeError: (87-98): This variable is of storage pointer type and might be returned without assignment and could be used uninitialized. Assign the variable (potentially from itself) to fix this error. -// TypeError: (176-187): This variable is of storage pointer type and might be returned without assignment and could be used uninitialized. Assign the variable (potentially from itself) to fix this error. -// TypeError: (264-275): This variable is of storage pointer type and might be returned without assignment and could be used uninitialized. Assign the variable (potentially from itself) to fix this error. +// TypeError: (87-98): This variable is of storage pointer type and can be returned without prior assignment. +// TypeError: (176-187): This variable is of storage pointer type and can be returned without prior assignment. +// TypeError: (264-275): This variable is of storage pointer type and can be returned without prior assignment. diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/ternary_err.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/ternary_err.sol index 6d10287b..d5ad73c5 100644 --- a/test/libsolidity/syntaxTests/controlFlow/storageReturn/ternary_err.sol +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/ternary_err.sol @@ -9,5 +9,5 @@ contract C { } } // ---- -// TypeError: (96-107): This variable is of storage pointer type and might be returned without assignment and could be used uninitialized. Assign the variable (potentially from itself) to fix this error. -// TypeError: (200-211): This variable is of storage pointer type and might be returned without assignment and could be used uninitialized. Assign the variable (potentially from itself) to fix this error. +// TypeError: (96-107): This variable is of storage pointer type and can be returned without prior assignment. +// TypeError: (200-211): This variable is of storage pointer type and can be returned without prior assignment. diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/while_err.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/while_err.sol index e7b4fae7..aabb76dd 100644 --- a/test/libsolidity/syntaxTests/controlFlow/storageReturn/while_err.sol +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/while_err.sol @@ -8,4 +8,4 @@ contract C { } } // ---- -// TypeError: (87-98): This variable is of storage pointer type and might be returned without assignment and could be used uninitialized. Assign the variable (potentially from itself) to fix this error. +// TypeError: (87-98): This variable is of storage pointer type and can be returned without prior assignment. diff --git a/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/always_revert.sol b/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/always_revert.sol new file mode 100644 index 00000000..96767402 --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/always_revert.sol @@ -0,0 +1,8 @@ +contract C { + function f() internal view returns(uint[] storage a) + { + uint b = a[0]; + revert(); + b; + } +}
\ No newline at end of file diff --git a/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/assembly.sol b/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/assembly.sol new file mode 100644 index 00000000..bfcbbef5 --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/assembly.sol @@ -0,0 +1,9 @@ +contract C { + uint[] r; + function f() internal view returns (uint[] storage s) { + assembly { pop(s_slot) } + s = r; + } +} +// ---- +// TypeError: (92-126): This variable is of storage pointer type and can be accessed without prior assignment. diff --git a/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/functionType.sol b/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/functionType.sol new file mode 100644 index 00000000..1d683eff --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/functionType.sol @@ -0,0 +1,8 @@ +contract C { + // Make sure function parameters and return values are not considered + // for uninitialized return detection in the control flow analysis. + function f(function(uint[] storage) internal returns (uint[] storage)) internal pure + returns (function(uint[] storage) internal returns (uint[] storage)) + { + } +} diff --git a/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/modifier_order_fail.sol b/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/modifier_order_fail.sol new file mode 100644 index 00000000..90d228fa --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/modifier_order_fail.sol @@ -0,0 +1,8 @@ +contract C { + modifier m1(uint[] storage a) { _; } + modifier m2(uint[] storage a) { _; } + uint[] s; + function f() m1(b) m2(b = s) internal view returns (uint[] storage b) {} +} +// ---- +// TypeError: (129-130): This variable is of storage pointer type and can be accessed without prior assignment. diff --git a/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/modifier_order_fine.sol b/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/modifier_order_fine.sol new file mode 100644 index 00000000..af133929 --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/modifier_order_fine.sol @@ -0,0 +1,6 @@ +contract C { + modifier m1(uint[] storage a) { _; } + modifier m2(uint[] storage a) { _; } + uint[] s; + function f() m1(b = s) m2(b) internal view returns (uint[] storage b) {} +}
\ No newline at end of file diff --git a/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/modifier_post_access.sol b/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/modifier_post_access.sol new file mode 100644 index 00000000..b9f08615 --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/modifier_post_access.sol @@ -0,0 +1,13 @@ +contract C { + uint[] s; + modifier mod(uint[] storage b) { + _; + b[0] = 0; + } + function f() mod(a) internal returns (uint[] storage a) + { + a = s; + } +} +// ---- +// TypeError: (120-121): This variable is of storage pointer type and can be accessed without prior assignment. diff --git a/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/modifier_pre_access.sol b/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/modifier_pre_access.sol new file mode 100644 index 00000000..81618aec --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/modifier_pre_access.sol @@ -0,0 +1,13 @@ +contract C { + uint[] s; + modifier mod(uint[] storage b) { + b[0] = 0; + _; + } + function f() mod(a) internal returns (uint[] storage a) + { + a = s; + } +} +// ---- +// TypeError: (120-121): This variable is of storage pointer type and can be accessed without prior assignment. diff --git a/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/smoke.sol b/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/smoke.sol new file mode 100644 index 00000000..41ced51d --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/smoke.sol @@ -0,0 +1,10 @@ +contract C { + uint[] s; + function f() internal returns (uint[] storage a) + { + a[0] = 0; + a = s; + } +} +// ---- +// TypeError: (94-95): This variable is of storage pointer type and can be accessed without prior assignment. diff --git a/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/struct.sol b/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/struct.sol new file mode 100644 index 00000000..b4f2be5d --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/struct.sol @@ -0,0 +1,11 @@ +contract C { + struct S { uint a; } + S s; + function f() internal returns (S storage r) + { + r.a = 0; + r = s; + } +} +// ---- +// TypeError: (109-110): This variable is of storage pointer type and can be accessed without prior assignment. diff --git a/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/unreachable.sol b/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/unreachable.sol new file mode 100644 index 00000000..b941ad34 --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/uninitializedAccess/unreachable.sol @@ -0,0 +1,10 @@ +contract C { + uint[] s; + function f() internal returns (uint[] storage a) + { + revert(); + a[0] = 0; + a = s; + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/dataLocations/libraries/library_function_with_data_location_fine.sol b/test/libsolidity/syntaxTests/dataLocations/libraries/library_function_with_data_location_fine.sol index 7a276f95..95d4e02a 100644 --- a/test/libsolidity/syntaxTests/dataLocations/libraries/library_function_with_data_location_fine.sol +++ b/test/libsolidity/syntaxTests/dataLocations/libraries/library_function_with_data_location_fine.sol @@ -8,3 +8,9 @@ library L { function i(uint[] calldata, uint[] storage) external pure returns (S storage x) {return x; } } // ---- +// TypeError: (197-198): This variable is of storage pointer type and can be accessed without prior assignment. +// TypeError: (203-204): This variable is of storage pointer type and can be accessed without prior assignment. +// TypeError: (359-360): This variable is of storage pointer type and can be accessed without prior assignment. +// TypeError: (365-366): This variable is of storage pointer type and can be accessed without prior assignment. +// TypeError: (460-461): This variable is of storage pointer type and can be accessed without prior assignment. +// TypeError: (557-558): This variable is of storage pointer type and can be accessed without prior assignment. diff --git a/test/libsolidity/syntaxTests/functionTypes/valid_function_type_variables.sol b/test/libsolidity/syntaxTests/functionTypes/valid_function_type_variables.sol index e7d2c9a9..65198706 100644 --- a/test/libsolidity/syntaxTests/functionTypes/valid_function_type_variables.sol +++ b/test/libsolidity/syntaxTests/functionTypes/valid_function_type_variables.sol @@ -18,9 +18,3 @@ contract test { function(uint) pure internal h = fh; } // ---- -// Warning: (20-47): Function state mutability can be restricted to pure -// Warning: (52-81): Function state mutability can be restricted to pure -// Warning: (86-115): Function state mutability can be restricted to pure -// Warning: (120-149): Function state mutability can be restricted to pure -// Warning: (154-183): Function state mutability can be restricted to pure -// Warning: (188-217): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/004_reference_to_later_declaration.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/004_reference_to_later_declaration.sol index e112e16c..a554d3ab 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/004_reference_to_later_declaration.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/004_reference_to_later_declaration.sol @@ -3,4 +3,3 @@ contract test { function f() public {} } // ---- -// Warning: (53-75): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/009_type_checking_function_call.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/009_type_checking_function_call.sol index abe2beac..3872b1c3 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/009_type_checking_function_call.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/009_type_checking_function_call.sol @@ -3,4 +3,3 @@ contract test { function g(uint256, bool) public returns (uint256) { } } // ---- -// Warning: (88-142): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/049_function_external_call_allowed_conversion.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/049_function_external_call_allowed_conversion.sol index ec72adeb..bda0b946 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/049_function_external_call_allowed_conversion.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/049_function_external_call_allowed_conversion.sol @@ -7,5 +7,3 @@ contract Test { function g (C c) external {} } // ---- -// Warning: (125-128): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (113-141): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/051_function_internal_allowed_conversion.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/051_function_internal_allowed_conversion.sol index aedc7b0b..5a9616ac 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/051_function_internal_allowed_conversion.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/051_function_internal_allowed_conversion.sol @@ -9,5 +9,3 @@ contract Test { } } // ---- -// Warning: (68-71): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (56-82): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/055_inheritance_diamond_basic.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/055_inheritance_diamond_basic.sol index c07e59e2..2e235ee0 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/055_inheritance_diamond_basic.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/055_inheritance_diamond_basic.sol @@ -5,5 +5,3 @@ contract derived is root, inter2, inter1 { function g() public { f(); rootFunction(); } } // ---- -// Warning: (16-49): Function state mutability can be restricted to pure -// Warning: (129-151): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/057_legal_override_direct.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/057_legal_override_direct.sol index 062507ee..bf6459cb 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/057_legal_override_direct.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/057_legal_override_direct.sol @@ -1,6 +1,3 @@ contract B { function f() public {} } contract C is B { function f(uint i) public {} } // ---- -// Warning: (67-73): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (13-35): Function state mutability can be restricted to pure -// Warning: (56-84): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/058_legal_override_indirect.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/058_legal_override_indirect.sol index f59da472..461bbbf2 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/058_legal_override_indirect.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/058_legal_override_indirect.sol @@ -2,6 +2,3 @@ contract A { function f(uint a) public {} } contract B { function f() public {} } contract C is A, B { } // ---- -// Warning: (24-30): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (13-41): Function state mutability can be restricted to pure -// Warning: (57-79): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/060_complex_inheritance.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/060_complex_inheritance.sol index c7e42238..ce3b622b 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/060_complex_inheritance.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/060_complex_inheritance.sol @@ -3,4 +3,3 @@ contract B { function f() public {} function g() public returns (uint8) {} } contract C is A, B { } // ---- // Warning: (35-42): Unused local variable. -// Warning: (95-133): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/061_missing_base_constructor_arguments.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/061_missing_base_constructor_arguments.sol index 8ebb46aa..31be70ca 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/061_missing_base_constructor_arguments.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/061_missing_base_constructor_arguments.sol @@ -1,4 +1,3 @@ contract A { constructor(uint a) public { } } contract B is A { } // ---- -// Warning: (25-31): Unused function parameter. Remove or comment out the variable name to silence this warning. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/062_base_constructor_arguments_override.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/062_base_constructor_arguments_override.sol index 8ebb46aa..31be70ca 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/062_base_constructor_arguments_override.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/062_base_constructor_arguments_override.sol @@ -1,4 +1,3 @@ contract A { constructor(uint a) public { } } contract B is A { } // ---- -// Warning: (25-31): Unused function parameter. Remove or comment out the variable name to silence this warning. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/096_access_to_default_function_visibility.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/096_access_to_default_function_visibility.sol index 9251df73..4f89e69e 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/096_access_to_default_function_visibility.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/096_access_to_default_function_visibility.sol @@ -5,4 +5,3 @@ contract d { function g() public { c(0).f(); } } // ---- -// Warning: (17-39): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/104_empty_name_input_parameter.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/104_empty_name_input_parameter.sol index 824543ef..af392402 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/104_empty_name_input_parameter.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/104_empty_name_input_parameter.sol @@ -2,4 +2,3 @@ contract test { function f(uint) public { } } // ---- -// Warning: (20-47): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/106_empty_name_return_parameter.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/106_empty_name_return_parameter.sol index a2ffc6e1..b524cd97 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/106_empty_name_return_parameter.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/106_empty_name_return_parameter.sol @@ -2,4 +2,3 @@ contract test { function f() public returns (bool) { } } // ---- -// Warning: (20-58): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/216_function_argument_storage_to_mem.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/216_function_argument_storage_to_mem.sol index c5175a41..0f4388d0 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/216_function_argument_storage_to_mem.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/216_function_argument_storage_to_mem.sol @@ -6,5 +6,3 @@ contract C { } } // ---- -// Warning: (91-106): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (80-122): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/256_using_for_overload.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/256_using_for_overload.sol index 155281f5..f033b85b 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/256_using_for_overload.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/256_using_for_overload.sol @@ -11,4 +11,3 @@ contract C { } } // ---- -// Warning: (128-189): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/260_library_memory_struct.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/260_library_memory_struct.sol index 20d8afa5..ee5bcda9 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/260_library_memory_struct.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/260_library_memory_struct.sol @@ -5,4 +5,3 @@ library c { } // ---- // Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments. -// Warning: (75-116): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/288_conditional_with_all_types.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/288_conditional_with_all_types.sol index e9ab08ba..a92c07f3 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/288_conditional_with_all_types.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/288_conditional_with_all_types.sol @@ -85,7 +85,5 @@ contract C { } // ---- // Warning: (1005-1019): This declaration shadows an existing declaration. -// Warning: (90-116): Function state mutability can be restricted to pure -// Warning: (121-147): Function state mutability can be restricted to pure // Warning: (257-642): Function state mutability can be restricted to pure // Warning: (647-1227): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/345_unused_return_value.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/345_unused_return_value.sol index 7f640505..109e8dfb 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/345_unused_return_value.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/345_unused_return_value.sol @@ -5,4 +5,3 @@ contract test { } } // ---- -// Warning: (20-57): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/376_inline_assembly_in_modifier.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/376_inline_assembly_in_modifier.sol index 0032f99e..87a7b28d 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/376_inline_assembly_in_modifier.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/376_inline_assembly_in_modifier.sol @@ -10,4 +10,3 @@ contract test { } } // ---- -// Warning: (122-151): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/403_return_structs.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/403_return_structs.sol index 2575954e..b4088068 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/403_return_structs.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/403_return_structs.sol @@ -7,4 +7,3 @@ contract C { } // ---- // Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments. -// Warning: (112-164): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/437_warn_unused_function_parameter.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/437_warn_unused_function_parameter.sol index 8a36eaad..4227cbb9 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/437_warn_unused_function_parameter.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/437_warn_unused_function_parameter.sol @@ -3,4 +3,3 @@ contract C { } } // ---- -// Warning: (28-34): Unused function parameter. Remove or comment out the variable name to silence this warning. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/439_warn_unused_return_parameter.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/439_warn_unused_return_parameter.sol index b1422c4f..b4c9be35 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/439_warn_unused_return_parameter.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/439_warn_unused_return_parameter.sol @@ -3,4 +3,3 @@ contract C { } } // ---- -// Warning: (51-57): Unused function parameter. Remove or comment out the variable name to silence this warning. diff --git a/test/libsolidity/syntaxTests/parsing/empty_function.sol b/test/libsolidity/syntaxTests/parsing/empty_function.sol index 320a0bcc..3f42e4e3 100644 --- a/test/libsolidity/syntaxTests/parsing/empty_function.sol +++ b/test/libsolidity/syntaxTests/parsing/empty_function.sol @@ -3,7 +3,3 @@ contract test { function functionName(bytes20 arg1, address addr) public view returns (int id) { } } // ---- -// Warning: (58-70): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (72-84): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (107-113): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (36-118): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/parsing/external_function.sol b/test/libsolidity/syntaxTests/parsing/external_function.sol index 3aa3ceec..0315b200 100644 --- a/test/libsolidity/syntaxTests/parsing/external_function.sol +++ b/test/libsolidity/syntaxTests/parsing/external_function.sol @@ -2,4 +2,3 @@ contract c { function x() external {} } // ---- -// Warning: (17-41): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/parsing/function_normal_comments.sol b/test/libsolidity/syntaxTests/parsing/function_normal_comments.sol index 94e1e60a..231be9c2 100644 --- a/test/libsolidity/syntaxTests/parsing/function_normal_comments.sol +++ b/test/libsolidity/syntaxTests/parsing/function_normal_comments.sol @@ -4,6 +4,3 @@ contract test { function functionName(bytes32 input) public returns (bytes32 out) {} } // ---- -// Warning: (97-110): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (128-139): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (75-143): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/parsing/function_type_as_storage_variable_with_assignment.sol b/test/libsolidity/syntaxTests/parsing/function_type_as_storage_variable_with_assignment.sol index 11e77f25..42d8717a 100644 --- a/test/libsolidity/syntaxTests/parsing/function_type_as_storage_variable_with_assignment.sol +++ b/test/libsolidity/syntaxTests/parsing/function_type_as_storage_variable_with_assignment.sol @@ -3,7 +3,3 @@ contract test { function (uint, uint) internal returns (uint) f1 = f; } // ---- -// Warning: (31-37): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (39-45): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (63-69): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (20-73): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/parsing/function_type_in_expression.sol b/test/libsolidity/syntaxTests/parsing/function_type_in_expression.sol index 3defb5ea..000c2011 100644 --- a/test/libsolidity/syntaxTests/parsing/function_type_in_expression.sol +++ b/test/libsolidity/syntaxTests/parsing/function_type_in_expression.sol @@ -5,9 +5,5 @@ contract test { } } // ---- -// Warning: (31-37): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (39-45): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (63-69): Unused function parameter. Remove or comment out the variable name to silence this warning. // Warning: (108-156): Unused local variable. -// Warning: (20-73): Function state mutability can be restricted to pure // Warning: (78-167): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/parsing/library_simple.sol b/test/libsolidity/syntaxTests/parsing/library_simple.sol index 006ff307..c892e3ed 100644 --- a/test/libsolidity/syntaxTests/parsing/library_simple.sol +++ b/test/libsolidity/syntaxTests/parsing/library_simple.sol @@ -2,4 +2,3 @@ library Lib { function f() public { } } // ---- -// Warning: (18-41): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/parsing/modifier_invocation.sol b/test/libsolidity/syntaxTests/parsing/modifier_invocation.sol index cf986efe..6fa007c7 100644 --- a/test/libsolidity/syntaxTests/parsing/modifier_invocation.sol +++ b/test/libsolidity/syntaxTests/parsing/modifier_invocation.sol @@ -4,4 +4,3 @@ contract c { function f() public mod1(7) mod2 { } } // ---- -// Warning: (135-171): Function state mutability can be restricted to view diff --git a/test/libsolidity/syntaxTests/parsing/multiple_functions_natspec_documentation.sol b/test/libsolidity/syntaxTests/parsing/multiple_functions_natspec_documentation.sol index 85d9e6a8..ba090c53 100644 --- a/test/libsolidity/syntaxTests/parsing/multiple_functions_natspec_documentation.sol +++ b/test/libsolidity/syntaxTests/parsing/multiple_functions_natspec_documentation.sol @@ -10,15 +10,3 @@ contract test { function functionName4(bytes32 input) public returns (bytes32 out) {} } // ---- -// Warning: (97-110): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (128-139): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (203-216): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (234-245): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (304-317): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (335-346): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (410-423): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (441-452): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (74-143): Function state mutability can be restricted to pure -// Warning: (180-249): Function state mutability can be restricted to pure -// Warning: (281-350): Function state mutability can be restricted to pure -// Warning: (387-456): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/parsing/no_function_params.sol b/test/libsolidity/syntaxTests/parsing/no_function_params.sol index 5a024bdb..1f7c85a3 100644 --- a/test/libsolidity/syntaxTests/parsing/no_function_params.sol +++ b/test/libsolidity/syntaxTests/parsing/no_function_params.sol @@ -3,4 +3,3 @@ contract test { function functionName() public {} } // ---- -// Warning: (36-69): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/parsing/single_function_param.sol b/test/libsolidity/syntaxTests/parsing/single_function_param.sol index 955f20f0..8dbac272 100644 --- a/test/libsolidity/syntaxTests/parsing/single_function_param.sol +++ b/test/libsolidity/syntaxTests/parsing/single_function_param.sol @@ -3,6 +3,3 @@ contract test { function functionName(bytes32 input) public returns (bytes32 out) {} } // ---- -// Warning: (58-71): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (89-100): Unused function parameter. Remove or comment out the variable name to silence this warning. -// Warning: (36-104): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/parsing/visibility_specifiers.sol b/test/libsolidity/syntaxTests/parsing/visibility_specifiers.sol index db890b37..24071388 100644 --- a/test/libsolidity/syntaxTests/parsing/visibility_specifiers.sol +++ b/test/libsolidity/syntaxTests/parsing/visibility_specifiers.sol @@ -9,6 +9,3 @@ contract c { } // ---- // Warning: (58-71): This declaration shadows an existing declaration. -// Warning: (89-111): Function state mutability can be restricted to pure -// Warning: (116-144): Function state mutability can be restricted to pure -// Warning: (149-182): Function state mutability can be restricted to pure diff --git a/test/libsolidity/syntaxTests/viewPureChecker/suggest_pure.sol b/test/libsolidity/syntaxTests/viewPureChecker/suggest_pure.sol index 87719eb3..5ec6d06f 100644 --- a/test/libsolidity/syntaxTests/viewPureChecker/suggest_pure.sol +++ b/test/libsolidity/syntaxTests/viewPureChecker/suggest_pure.sol @@ -2,4 +2,3 @@ contract C { function g() view public { } } // ---- -// Warning: (17-45): Function state mutability can be restricted to pure diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_variables.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_variables.yul new file mode 100644 index 00000000..a790ca65 --- /dev/null +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_variables.yul @@ -0,0 +1,14 @@ +{ + // This does not replace b by a because there is no + // explicit assignment, even though both hold the same value. + let a + let b + mstore(sub(a, b), 7) +} +// ---- +// commonSubexpressionEliminator +// { +// let a +// let b +// mstore(sub(a, b), 7) +// } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/unassigend_vars_multi.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/unassigend_vars_multi.yul index 8c1ad789..f260db0b 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/unassigend_vars_multi.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/unassigend_vars_multi.yul @@ -1,5 +1,4 @@ -// c & d can't be optimized as expression simplifier doesn't handle default -// values yet +// Unassigned variables are assumed to be zero. { let c, d let y := add(d, add(c, 7)) @@ -8,5 +7,5 @@ // expressionSimplifier // { // let c, d -// let y := add(add(d, c), 7) +// let y := 7 // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/unassigned_vars.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/unassigned_vars.yul index 87391b8c..7b1430f3 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/unassigned_vars.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/unassigned_vars.yul @@ -1,5 +1,4 @@ -// c & d can't be optimized as expression simplifier doesn't handle default -// values yet +// Unassigned variables are assumed to be zero. { let c let d @@ -10,5 +9,5 @@ // { // let c // let d -// let y := add(add(d, c), 7) +// let y := 7 // } diff --git a/test/libyul/yulOptimizerTests/fullInliner/large_function_multi_use.yul b/test/libyul/yulOptimizerTests/fullInliner/large_function_multi_use.yul index 0972ac56..ec44dafb 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/large_function_multi_use.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/large_function_multi_use.yul @@ -13,6 +13,9 @@ let r := f(a) // This should be inlined because it is a constant let t := f(a2) + let a3 + // This should be inlined because it is a constant as well (zero) + let s := f(a3) } // ---- // fullInliner @@ -30,6 +33,16 @@ // let f_y := add(f_a, f_x) // sstore(f_y, 10) // let t := f_b +// let a3 +// let f_a_5 := a3 +// let f_b_6 +// let f_x_7 := mload(f_a_5) +// f_b_6 := sload(f_x_7) +// let f_c_8 := 3 +// mstore(mul(f_a_5, f_b_6), mload(f_x_7)) +// let f_y_11 := add(f_a_5, f_x_7) +// sstore(f_y_11, 10) +// let s := f_b_6 // } // function f(a) -> b // { diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/if_multi_unassigned_condition.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/if_multi_unassigned_condition.yul new file mode 100644 index 00000000..0ece5dbd --- /dev/null +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/if_multi_unassigned_condition.yul @@ -0,0 +1,10 @@ +{ + let x, y + if x { mstore(0, 0) } + if y { mstore(0, 0) } +} +// ---- +// structuralSimplifier +// { +// let x, y +// } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/if_unassigned_condition.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/if_unassigned_condition.yul new file mode 100644 index 00000000..a327a882 --- /dev/null +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/if_unassigned_condition.yul @@ -0,0 +1,9 @@ +{ + let x + if x { mstore(0, 0) } +} +// ---- +// structuralSimplifier +// { +// let x +// } diff --git a/test/solcjsTests.sh b/test/solcjsTests.sh index e0bbc5df..b9224862 100755 --- a/test/solcjsTests.sh +++ b/test/solcjsTests.sh @@ -60,7 +60,7 @@ DIR=$(mktemp -d) # Update version (needed for some tests) echo "Updating package.json to version $VERSION" - npm version --no-git-tag-version $VERSION + npm version --allow-same-version --no-git-tag-version $VERSION echo "Running solc-js tests..." npm run test |