diff --git a/CMakeLists.txt b/CMakeLists.txt index 7aa6647b2233..e7100f141a2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ include(EthPolicy) eth_policy() # project name and version should be set after cmake_policy CMP0048 -set(PROJECT_VERSION "0.6.9") +set(PROJECT_VERSION "0.6.10") # OSX target needed in order to support std::visit set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14") project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX) diff --git a/Changelog.md b/Changelog.md index 62ddd07ea576..e52c63293909 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,22 @@ +### 0.6.10 (2020-06-11) + +Important Bugfixes: + * Fixed a bug related to internal library functions with ``calldata`` parameters called via ``using for``. + + +Compiler Features: + * Commandline Interface: Re-group help screen. + * Output compilation error codes in standard-json and when using ``--error-codes``. + * Yul: Raise warning for switch statements that only have a default and no other cases. + + +Bugfixes: + * SMTChecker: Fix internal error when encoding tuples of tuples. + * SMTChecker: Fix aliasing soundness after pushing to an array pointer. + * Type system: Fix internal compiler error on calling externally a function that returns variables with calldata location. + * Type system: Fix bug where a bound function was not found if ``using for`` is applied to explicit reference types. + + ### 0.6.9 (2020-06-04) Language Features: diff --git a/ReleaseChecklist.md b/ReleaseChecklist.md index b6422654e171..116b3dbe9e39 100644 --- a/ReleaseChecklist.md +++ b/ReleaseChecklist.md @@ -6,9 +6,8 @@ - [ ] Readthedocs account, access to the Solidity project - [ ] Write access to https://github.com/ethereum/homebrew-ethereum -### Pre-release - - [ ] Ensure that a Github project exists for the release. - - [ ] Check that all issues and pull requests from the Github project to be released are merged to ``develop``. +### Blog Post + - [ ] Create a post on https://github.com/ethereum/solidity-blog and explain some of the new features or concepts. ### Changelog - [ ] Sort the changelog entries alphabetically and correct any errors you notice. @@ -33,8 +32,9 @@ - [ ] Wait for the ``~ethereum/ubuntu/ethereum-static`` PPA build to be finished and published for *all platforms*. SERIOUSLY: DO NOT PROCEED EARLIER!!! *After* the static builds are *published*, copy the static package to the ``~ethereum/ubuntu/ethereum`` PPA for the destination series ``Trusty`` and ``Xenial`` 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 v0.x.x``). -### Homebrew +### Homebrew and MacOS - [ ] Update the version and the hash (``sha256sum solidity_x.x.x.tar.gz``) in https://github.com/ethereum/homebrew-ethereum/blob/master/solidity.rb + - [ ] Take the binary from the ``b_osx`` run of the released commit in circle-ci and add it to the release page as ``solc-macos``. ### Documentation - [ ] Build the new version on https://readthedocs.org/projects/solidity/ (select `latest` on the bottom of the page and click `BUILD`) diff --git a/docs/060-breaking-changes.rst b/docs/060-breaking-changes.rst index 1a131a2c83ec..3173bca69da7 100644 --- a/docs/060-breaking-changes.rst +++ b/docs/060-breaking-changes.rst @@ -42,7 +42,8 @@ For most of the topics the compiler will provide suggestions. storage arrays. * The new keyword ``abstract`` can be used to mark contracts as abstract. It has to be used - if a contract does not implement all its functions. + if a contract does not implement all its functions. Abstract contracts cannot be created using the ``new`` operator, + and it is not possible to generate bytecode for them during compilation. * Libraries have to implement all their functions, not only the internal ones. diff --git a/docs/Solidity.g4 b/docs/Solidity.g4 index a415c19f97ff..fdc80822bddd 100644 --- a/docs/Solidity.g4 +++ b/docs/Solidity.g4 @@ -124,7 +124,11 @@ userDefinedTypeName : identifier ( '.' identifier )* ; mapping - : 'mapping' '(' (elementaryTypeName | userDefinedTypeName) '=>' typeName ')' ; + : 'mapping' '(' mappingKey '=>' typeName ')' ; + +mappingKey + : elementaryTypeName + | userDefinedTypeName ; functionTypeName : 'function' parameterList modifierList returnParameters? ; @@ -470,7 +474,7 @@ SingleQuotedStringCharacter : ~['\r\n\\] | ('\\' .) ; VersionLiteral - : [0-9]+ '.' [0-9]+ ('.' [0-9]+)? ; + : [0-9]+ ( '.' [0-9]+ ('.' [0-9]+)? )? ; WS : [ \t\r\n\u000C]+ -> skip ; diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst index 1d3e8efd08c6..ccb76b37cb76 100644 --- a/docs/abi-spec.rst +++ b/docs/abi-spec.rst @@ -24,7 +24,7 @@ Function Selector ================= The first four bytes of the call data for a function call specifies the function to be called. It is the -first (left, high-order in big-endian) four bytes of the Keccak-256 (SHA-3) hash of the signature of +first (left, high-order in big-endian) four bytes of the Keccak-256 hash of the signature of the function. The signature is defined as the canonical expression of the basic prototype without data location specifier, i.e. the function name with the parenthesised list of parameter types. Parameter types are split by a single diff --git a/docs/bugs.json b/docs/bugs.json index 90f211c1f7cc..34325f45b1be 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -1,4 +1,12 @@ [ + { + "name": "UsingForCalldata", + "summary": "Function calls to internal library functions with calldata parameters called via ``using for`` can result in invalid data being read.", + "description": "Function calls to internal library functions using the ``using for`` mechanism copied all calldata parameters to memory first and passed them on like that, regardless of whether it was an internal or an external call. Due to that, the called function would receive a memory pointer that is interpreted as a calldata pointer. Since dynamically sized arrays are passed using two stack slots for calldata, but only one for memory, this can lead to stack corruption. An affected library call will consider the JUMPDEST to which it is supposed to return as part of its arguments and will instead jump out to whatever was on the stack before the call.", + "introduced": "0.6.9", + "fixed": "0.6.10", + "severity": "very low" + }, { "name": "MissingEscapingInFormatting", "summary": "String literals containing double backslash characters passed directly to external or encoding function calls can lead to a different string being used when ABIEncoderV2 is enabled.", diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index 2d81e8783b5d..8472ed5e427a 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -1105,6 +1105,10 @@ ], "released": "2020-01-02" }, + "0.6.10": { + "bugs": [], + "released": "2020-06-11" + }, "0.6.2": { "bugs": [ "MissingEscapingInFormatting", @@ -1165,7 +1169,9 @@ "released": "2020-05-14" }, "0.6.9": { - "bugs": [], + "bugs": [ + "UsingForCalldata" + ], "released": "2020-06-04" } } \ No newline at end of file diff --git a/docs/contracts/inheritance.rst b/docs/contracts/inheritance.rst index 83ccdf773bcc..07bb7463698e 100644 --- a/docs/contracts/inheritance.rst +++ b/docs/contracts/inheritance.rst @@ -194,10 +194,10 @@ not known in the context of the class where it is used, although its type is known. This is similar for ordinary virtual method lookup. -.. _function-overriding: - .. index:: ! overriding;function +.. _function-overriding: + Function Overriding =================== @@ -317,10 +317,10 @@ of the variable: While public state variables can override external functions, they themselves cannot be overridden. -.. _modifier-overriding: - .. index:: ! overriding;modifier +.. _modifier-overriding: + Modifier Overriding =================== diff --git a/docs/types/reference-types.rst b/docs/types/reference-types.rst index 6283eaa0e46d..5bd242f06b99 100644 --- a/docs/types/reference-types.rst +++ b/docs/types/reference-types.rst @@ -430,7 +430,13 @@ Array slices are useful to ABI-decode secondary data passed in function paramete /// Forward call to "setOwner(address)" that is implemented by client /// after doing basic validation on the address argument. function forward(bytes calldata _payload) external { - bytes4 sig = abi.decode(_payload[:4], (bytes4)); + // Since ABI decoding requires padded data, we cannot + // use abi.decode(_payload[:4], (bytes4)). + bytes4 sig = + _payload[0] | + (bytes4(_payload[1]) >> 8) | + (bytes4(_payload[2]) >> 16) | + (bytes4(_payload[3]) >> 24); if (sig == bytes4(keccak256("setOwner(address)"))) { address owner = abi.decode(_payload[4:], (address)); require(owner != address(0), "Address of owner cannot be zero."); diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index 3f0252884d7b..65f3f7acee99 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -374,8 +374,10 @@ Output Description "component": "general", // Mandatory ("error" or "warning") "severity": "error", + // Optional: unique code for the cause of the error + "errorCode": "3141", // Mandatory - "message": "Invalid keyword" + "message": "Invalid keyword", // Optional: the message formatted with source location "formattedMessage": "sourceFile.sol:100: Invalid keyword" } diff --git a/liblangutil/SourceReferenceExtractor.cpp b/liblangutil/SourceReferenceExtractor.cpp index 0a6ff0421ba1..89f84011db71 100644 --- a/liblangutil/SourceReferenceExtractor.cpp +++ b/liblangutil/SourceReferenceExtractor.cpp @@ -38,7 +38,15 @@ SourceReferenceExtractor::Message SourceReferenceExtractor::extract(util::Except for (auto const& info: secondaryLocation->infos) secondary.emplace_back(extract(&info.second, info.first)); - return Message{std::move(primary), _category, std::move(secondary)}; + return Message{std::move(primary), _category, std::move(secondary), nullopt}; +} + +SourceReferenceExtractor::Message SourceReferenceExtractor::extract(Error const& _error) +{ + string category = (_error.type() == Error::Type::Warning) ? "Warning" : "Error"; + Message message = extract(_error, category); + message.errorId = _error.errorId(); + return message; } SourceReference SourceReferenceExtractor::extract(SourceLocation const* _location, std::string message) diff --git a/liblangutil/SourceReferenceExtractor.h b/liblangutil/SourceReferenceExtractor.h index 6aa0ab34a812..b9dababb9671 100644 --- a/liblangutil/SourceReferenceExtractor.h +++ b/liblangutil/SourceReferenceExtractor.h @@ -16,16 +16,14 @@ */ #pragma once +#include + #include +#include #include #include #include -namespace solidity::util -{ -struct Exception; -} - namespace solidity::langutil { @@ -58,8 +56,6 @@ struct SourceReference } }; -struct SourceLocation; - namespace SourceReferenceExtractor { struct Message @@ -67,9 +63,11 @@ namespace SourceReferenceExtractor SourceReference primary; std::string category; // "Error", "Warning", ... std::vector secondary; + std::optional errorId; }; Message extract(util::Exception const& _exception, std::string _category); + Message extract(Error const& _error); SourceReference extract(SourceLocation const* _location, std::string message = ""); } diff --git a/liblangutil/SourceReferenceFormatter.cpp b/liblangutil/SourceReferenceFormatter.cpp index 965755a10cbe..e10f251d5b21 100644 --- a/liblangutil/SourceReferenceFormatter.cpp +++ b/liblangutil/SourceReferenceFormatter.cpp @@ -80,10 +80,7 @@ void SourceReferenceFormatter::printExceptionInformation(util::Exception const& void SourceReferenceFormatter::printErrorInformation(Error const& _error) { - printExceptionInformation( - _error, - (_error.type() == Error::Type::Warning) ? "Warning" : "Error" - ); + printExceptionInformation(SourceReferenceExtractor::extract(_error)); } void SourceReferenceFormatter::printExceptionInformation(SourceReferenceExtractor::Message const& _msg) diff --git a/liblangutil/SourceReferenceFormatterHuman.cpp b/liblangutil/SourceReferenceFormatterHuman.cpp index 3560955c7aa1..998ca7bf59b6 100644 --- a/liblangutil/SourceReferenceFormatterHuman.cpp +++ b/liblangutil/SourceReferenceFormatterHuman.cpp @@ -151,6 +151,8 @@ void SourceReferenceFormatterHuman::printExceptionInformation(SourceReferenceExt { // exception header line errorColored() << _msg.category; + if (m_withErrorIds && _msg.errorId.has_value()) + errorColored() << " (" << _msg.errorId.value().error << ")"; messageColored() << ": " << _msg.primary.message << '\n'; printSourceLocation(_msg.primary); diff --git a/liblangutil/SourceReferenceFormatterHuman.h b/liblangutil/SourceReferenceFormatterHuman.h index 060adc00e362..b468f375651b 100644 --- a/liblangutil/SourceReferenceFormatterHuman.h +++ b/liblangutil/SourceReferenceFormatterHuman.h @@ -29,22 +29,14 @@ #include #include -namespace solidity::util -{ -struct Exception; // forward -} - namespace solidity::langutil { -struct SourceLocation; -struct SourceReference; - class SourceReferenceFormatterHuman: public SourceReferenceFormatter { public: - SourceReferenceFormatterHuman(std::ostream& _stream, bool colored): - SourceReferenceFormatter{_stream}, m_colored{colored} + SourceReferenceFormatterHuman(std::ostream& _stream, bool _colored, bool _withErrorIds): + SourceReferenceFormatter{_stream}, m_colored{_colored}, m_withErrorIds(_withErrorIds) {} void printSourceLocation(SourceReference const& _ref) override; @@ -54,12 +46,13 @@ class SourceReferenceFormatterHuman: public SourceReferenceFormatter static std::string formatExceptionInformation( util::Exception const& _exception, std::string const& _name, - bool colored = false + bool _colored = false, + bool _withErrorIds = false ) { std::ostringstream errorOutput; - SourceReferenceFormatterHuman formatter(errorOutput, colored); + SourceReferenceFormatterHuman formatter(errorOutput, _colored, _withErrorIds); formatter.printExceptionInformation(_exception, _name); return errorOutput.str(); } @@ -75,6 +68,7 @@ class SourceReferenceFormatterHuman: public SourceReferenceFormatter private: bool m_colored; + bool m_withErrorIds; }; } diff --git a/libsolidity/analysis/OverrideChecker.cpp b/libsolidity/analysis/OverrideChecker.cpp index 89f9a6637846..c488fd278a01 100644 --- a/libsolidity/analysis/OverrideChecker.cpp +++ b/libsolidity/analysis/OverrideChecker.cpp @@ -68,7 +68,7 @@ struct OverrideGraph std::map nodes; std::map nodeInv; std::map> edges; - int numNodes = 2; + size_t numNodes = 2; void addEdge(int _a, int _b) { edges[_a].insert(_b); @@ -82,7 +82,7 @@ struct OverrideGraph auto it = nodes.find(_function); if (it != nodes.end()) return it->second; - int currentNode = numNodes++; + int currentNode = static_cast(numNodes++); nodes[_function] = currentNode; nodeInv[currentNode] = _function; if (_function.overrides()) @@ -116,21 +116,24 @@ struct CutVertexFinder std::vector m_parent = std::vector(m_graph.numNodes, -1); std::set m_cutVertices{}; - void run(int _u = 0, int _depth = 0) + void run(size_t _u = 0, size_t _depth = 0) { m_visited.at(_u) = true; - m_depths.at(_u) = m_low.at(_u) = _depth; - for (int v: m_graph.edges.at(_u)) - if (!m_visited.at(v)) + m_depths.at(_u) = m_low.at(_u) = static_cast(_depth); + for (int const v: m_graph.edges.at(static_cast(_u))) + { + auto const vInd = static_cast(v); + if (!m_visited.at(vInd)) { - m_parent[v] = _u; - run(v, _depth + 1); - if (m_low[v] >= m_depths[_u] && m_parent[_u] != -1) - m_cutVertices.insert(m_graph.nodeInv.at(_u)); - m_low[_u] = min(m_low[_u], m_low[v]); + m_parent[vInd] = static_cast(_u); + run(vInd, _depth + 1); + if (m_low[vInd] >= m_depths[_u] && m_parent[_u] != -1) + m_cutVertices.insert(m_graph.nodeInv.at(static_cast(_u))); + m_low[_u] = min(m_low[_u], m_low[vInd]); } else if (v != m_parent[_u]) - m_low[_u] = min(m_low[_u], m_depths[v]); + m_low[_u] = min(m_low[_u], m_depths[vInd]); + } } }; @@ -213,7 +216,7 @@ bool OverrideProxy::CompareBySignature::operator()(OverrideProxy const& _a, Over size_t OverrideProxy::id() const { return std::visit(GenericVisitor{ - [&](auto const* _item) -> size_t { return _item->id(); } + [&](auto const* _item) -> size_t { return static_cast(_item->id()); } }, m_item); } diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 763c34f21b14..c308fadd8efe 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -82,7 +82,7 @@ TypePointer const& TypeChecker::type(VariableDeclaration const& _variable) const bool TypeChecker::visit(ContractDefinition const& _contract) { - m_scope = &_contract; + m_currentContract = &_contract; ASTNode::listAccept(_contract.baseContracts(), *this); @@ -266,7 +266,7 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance) auto base = dynamic_cast(&dereference(_inheritance.name())); solAssert(base, "Base contract not available."); - if (m_scope->isInterface() && !base->isInterface()) + if (m_currentContract->isInterface() && !base->isInterface()) m_errorReporter.typeError(6536_error, _inheritance.location(), "Interfaces can only inherit from other interfaces."); if (base->isLibrary()) @@ -328,8 +328,6 @@ void TypeChecker::endVisit(ModifierDefinition const& _modifier) bool TypeChecker::visit(FunctionDefinition const& _function) { - bool isLibraryFunction = _function.inContractKind() == ContractKind::Library; - if (_function.markedVirtual()) { if (_function.annotation().contract->isInterface()) @@ -340,7 +338,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function) if (_function.isPayable()) { - if (isLibraryFunction) + if (_function.libraryFunction()) m_errorReporter.typeError(7708_error, _function.location(), "Library functions cannot be payable."); if (_function.isOrdinary() && !_function.isPartOfExternalInterface()) m_errorReporter.typeError(5587_error, _function.location(), "Internal functions cannot be payable."); @@ -350,15 +348,13 @@ bool TypeChecker::visit(FunctionDefinition const& _function) { if (var.referenceLocation() != VariableDeclaration::Location::Storage) { - if (!isLibraryFunction && _function.isPublic()) + if (!_function.libraryFunction() && _function.isPublic()) m_errorReporter.typeError(3442_error, var.location(), "Mapping types can only have a data location of \"storage\" and thus only be parameters or return variables for internal or library functions."); else m_errorReporter.typeError(5380_error, var.location(), "Mapping types can only have a data location of \"storage\"." ); } else - { - solAssert(isLibraryFunction || !_function.isPublic(), "Mapping types for parameters or return variables can only be used in internal or library functions."); - } + solAssert(_function.libraryFunction() || !_function.isPublic(), "Mapping types for parameters or return variables can only be used in internal or library functions."); } else { @@ -366,7 +362,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function) m_errorReporter.typeError(3312_error, var.location(), "Type is required to live outside storage."); if (_function.isPublic()) { - auto iType = type(var)->interfaceType(isLibraryFunction); + auto iType = type(var)->interfaceType(_function.libraryFunction()); if (!iType) { @@ -378,7 +374,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function) if ( _function.isPublic() && !_function.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) && - !typeSupportedByOldABIEncoder(*type(var), isLibraryFunction) + !typeSupportedByOldABIEncoder(*type(var), _function.libraryFunction()) ) m_errorReporter.typeError( 4957_error, @@ -417,7 +413,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function) else modifiers.insert(decl); } - if (m_scope->isInterface()) + if (m_currentContract->isInterface()) { if (_function.isImplemented()) m_errorReporter.typeError(4726_error, _function.location(), "Functions in interfaces cannot have an implementation."); @@ -428,14 +424,14 @@ bool TypeChecker::visit(FunctionDefinition const& _function) if (_function.isConstructor()) m_errorReporter.typeError(6482_error, _function.location(), "Constructor cannot be defined in interfaces."); } - else if (m_scope->contractKind() == ContractKind::Library) + else if (m_currentContract->contractKind() == ContractKind::Library) if (_function.isConstructor()) m_errorReporter.typeError(7634_error, _function.location(), "Constructor cannot be defined in libraries."); if (_function.isImplemented()) _function.body().accept(*this); else if (_function.isConstructor()) m_errorReporter.typeError(5700_error, _function.location(), "Constructor must be implemented if declared."); - else if (isLibraryFunction) + else if (_function.libraryFunction()) m_errorReporter.typeError(9231_error, _function.location(), "Library functions must be implemented if declared."); else if (!_function.virtualSemantics()) m_errorReporter.typeError(5424_error, _function.location(), "Functions without implementation must be marked virtual."); @@ -670,7 +666,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) { auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier); if (ref == _inlineAssembly.annotation().externalReferences.end()) - return size_t(-1); + return numeric_limits::max(); Declaration const* declaration = ref->second.declaration; solAssert(!!declaration, ""); bool requiresStorage = ref->second.isSlot || ref->second.isOffset; @@ -680,7 +676,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) if (var->immutable()) { m_errorReporter.typeError(3773_error, _identifier.location, "Assembly access to immutable variables is not supported."); - return size_t(-1); + return numeric_limits::max(); } if (var->isConstant()) { @@ -689,17 +685,17 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) if (var && !var->value()) { m_errorReporter.typeError(3224_error, _identifier.location, "Constant has no value."); - return size_t(-1); + return numeric_limits::max(); } else if (_context == yul::IdentifierContext::LValue) { m_errorReporter.typeError(6252_error, _identifier.location, "Constant variables cannot be assigned to."); - return size_t(-1); + return numeric_limits::max(); } else if (requiresStorage) { m_errorReporter.typeError(6617_error, _identifier.location, "The suffixes _offset and _slot can only be used on non-constant storage variables."); - return size_t(-1); + return numeric_limits::max(); } else if (var && var->value() && !var->value()->annotation().type && !dynamic_cast(var->value().get())) { @@ -727,19 +723,19 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) if (!var->isStateVariable() && !var->type()->dataStoredIn(DataLocation::Storage)) { m_errorReporter.typeError(3622_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables."); - return size_t(-1); + return numeric_limits::max(); } else if (_context == yul::IdentifierContext::LValue) { if (var->isStateVariable()) { m_errorReporter.typeError(4713_error, _identifier.location, "State variables cannot be assigned to - you have to use \"sstore()\"."); - return size_t(-1); + return numeric_limits::max(); } else if (ref->second.isOffset) { m_errorReporter.typeError(9739_error, _identifier.location, "Only _slot can be assigned to."); - return size_t(-1); + return numeric_limits::max(); } else solAssert(ref->second.isSlot, ""); @@ -748,12 +744,12 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) else if (!var->isConstant() && var->isStateVariable()) { m_errorReporter.typeError(1408_error, _identifier.location, "Only local variables are supported. To access storage variables, use the _slot and _offset suffixes."); - return size_t(-1); + return numeric_limits::max(); } else if (var->type()->dataStoredIn(DataLocation::Storage)) { m_errorReporter.typeError(9068_error, _identifier.location, "You have to use the _slot or _offset suffix to access storage reference variables."); - return size_t(-1); + return numeric_limits::max(); } else if (var->type()->sizeOnStack() != 1) { @@ -761,21 +757,21 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) m_errorReporter.typeError(2370_error, _identifier.location, "Call data elements cannot be accessed directly. Copy to a local variable first or use \"calldataload\" or \"calldatacopy\" with manually determined offsets and sizes."); else m_errorReporter.typeError(9857_error, _identifier.location, "Only types that use one stack slot are supported."); - return size_t(-1); + return numeric_limits::max(); } } else if (requiresStorage) { m_errorReporter.typeError(7944_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables."); - return size_t(-1); + return numeric_limits::max(); } else if (_context == yul::IdentifierContext::LValue) { if (dynamic_cast(declaration)) - return size_t(-1); + return numeric_limits::max(); m_errorReporter.typeError(1990_error, _identifier.location, "Only local variables can be assigned to in inline assembly."); - return size_t(-1); + return numeric_limits::max(); } if (_context == yul::IdentifierContext::RValue) @@ -784,7 +780,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) if (dynamic_cast(declaration)) { m_errorReporter.declarationError(2025_error, _identifier.location, "Access to functions is not allowed in inline assembly."); - return size_t(-1); + return numeric_limits::max(); } else if (dynamic_cast(declaration)) { @@ -794,11 +790,11 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) if (!contract->isLibrary()) { m_errorReporter.typeError(4977_error, _identifier.location, "Expected a library."); - return size_t(-1); + return numeric_limits::max(); } } else - return size_t(-1); + return numeric_limits::max(); } ref->second.valueSize = 1; return size_t(1); @@ -1794,7 +1790,7 @@ void TypeChecker::typeCheckFunctionCall( if (_functionType->kind() == FunctionType::Kind::Declaration) { if ( - m_scope->derivesFrom(*_functionType->declaration().annotation().contract) && + m_currentContract->derivesFrom(*_functionType->declaration().annotation().contract) && !dynamic_cast(_functionType->declaration()).isImplemented() ) m_errorReporter.typeError( @@ -1830,7 +1826,7 @@ void TypeChecker::typeCheckFallbackFunction(FunctionDefinition const& _function) { solAssert(_function.isFallback(), ""); - if (_function.inContractKind() == ContractKind::Library) + if (_function.libraryFunction()) m_errorReporter.typeError(5982_error, _function.location(), "Libraries cannot have fallback functions."); if (_function.stateMutability() != StateMutability::NonPayable && _function.stateMutability() != StateMutability::Payable) m_errorReporter.typeError( @@ -1857,7 +1853,7 @@ void TypeChecker::typeCheckReceiveFunction(FunctionDefinition const& _function) { solAssert(_function.isReceive(), ""); - if (_function.inContractKind() == ContractKind::Library) + if (_function.libraryFunction()) m_errorReporter.typeError(4549_error, _function.location(), "Libraries cannot have receive ether functions."); if (_function.stateMutability() != StateMutability::Payable) @@ -1916,7 +1912,7 @@ void TypeChecker::typeCheckABIEncodeFunctions( bool const isPacked = _functionType->kind() == FunctionType::Kind::ABIEncodePacked; solAssert(_functionType->padArguments() != isPacked, "ABI function with unexpected padding"); - bool const abiEncoderV2 = m_scope->sourceUnit().annotation().experimentalFeatures.count( + bool const abiEncoderV2 = m_currentContract->sourceUnit().annotation().experimentalFeatures.count( ExperimentalFeature::ABIEncoderV2 ); @@ -2316,7 +2312,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) case FunctionType::Kind::ABIDecode: { bool const abiEncoderV2 = - m_scope->sourceUnit().annotation().experimentalFeatures.count( + m_currentContract->sourceUnit().annotation().experimentalFeatures.count( ExperimentalFeature::ABIEncoderV2 ); returnTypes = typeCheckABIDecodeAndRetrieveReturnType(_functionCall, abiEncoderV2); @@ -2512,13 +2508,13 @@ void TypeChecker::endVisit(NewExpression const& _newExpression) if (contract->abstract()) m_errorReporter.typeError(4614_error, _newExpression.location(), "Cannot instantiate an abstract contract."); - solAssert(!!m_scope, ""); - m_scope->annotation().contractDependencies.insert(contract); + solAssert(!!m_currentContract, ""); + m_currentContract->annotation().contractDependencies.insert(contract); solAssert( !contract->annotation().linearizedBaseContracts.empty(), "Linearized base contracts not yet available." ); - if (contractDependenciesAreCyclic(*m_scope)) + if (contractDependenciesAreCyclic(*m_currentContract)) m_errorReporter.typeError( 4579_error, _newExpression.location(), @@ -2565,7 +2561,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) // Retrieve the types of the arguments if this is used to call a function. auto const& arguments = _memberAccess.annotation().arguments; - MemberList::MemberMap possibleMembers = exprType->members(m_scope).membersByName(memberName); + MemberList::MemberMap possibleMembers = exprType->members(m_currentContract).membersByName(memberName); size_t const initialMemberCount = possibleMembers.size(); if (initialMemberCount > 1 && arguments) { @@ -2591,7 +2587,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) DataLocation::Storage, exprType ); - if (!storageType->members(m_scope).membersByName(memberName).empty()) + if (!storageType->members(m_currentContract).membersByName(memberName).empty()) m_errorReporter.fatalTypeError( 4994_error, _memberAccess.location(), @@ -2747,7 +2743,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) { annotation.isPure = true; ContractType const& accessedContractType = dynamic_cast(*magicType->typeArgument()); - m_scope->annotation().contractDependencies.insert(&accessedContractType.contractDefinition()); + m_currentContract->annotation().contractDependencies.insert(&accessedContractType.contractDefinition()); if ( memberName == "runtimeCode" && @@ -2759,7 +2755,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) "\"runtimeCode\" is not available for contracts containing immutable variables." ); - if (contractDependenciesAreCyclic(*m_scope)) + if (contractDependenciesAreCyclic(*m_currentContract)) m_errorReporter.typeError( 4224_error, _memberAccess.location(), diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h index 5c327bf2e920..9997c700a630 100644 --- a/libsolidity/analysis/TypeChecker.h +++ b/libsolidity/analysis/TypeChecker.h @@ -165,7 +165,7 @@ class TypeChecker: private ASTConstVisitor /// Runs type checks on @a _expression to infer its type and then checks that it is an LValue. void requireLValue(Expression const& _expression, bool _ordinaryAssignment); - ContractDefinition const* m_scope = nullptr; + ContractDefinition const* m_currentContract = nullptr; langutil::EVMVersion m_evmVersion; diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp index 230e0a8bab56..09c8a34b3c59 100644 --- a/libsolidity/analysis/ViewPureChecker.cpp +++ b/libsolidity/analysis/ViewPureChecker.cpp @@ -276,7 +276,7 @@ void ViewPureChecker::reportMutability( { // We do not warn for library functions because they cannot be payable anyway. // Also internal functions should be allowed to use `msg.value`. - if (m_currentFunction->isPublic() && m_currentFunction->inContractKind() != ContractKind::Library) + if (m_currentFunction->isPublic() && !m_currentFunction->libraryFunction()) { if (_nestedLocation) m_errorReporter.typeError( diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 3edb08476e4a..3492bfc458ee 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -38,7 +38,7 @@ using namespace solidity; using namespace solidity::frontend; ASTNode::ASTNode(int64_t _id, SourceLocation _location): - m_id(_id), + m_id(static_cast(_id)), m_location(std::move(_location)) { } @@ -287,11 +287,11 @@ TypeDeclarationAnnotation& EnumDefinition::annotation() const return initAnnotation(); } -ContractKind FunctionDefinition::inContractKind() const +bool FunctionDefinition::libraryFunction() const { - auto contractDef = dynamic_cast(scope()); - solAssert(contractDef, "Enclosing Scope of FunctionDefinition was not set."); - return contractDef->contractKind(); + if (auto const* contractDef = dynamic_cast(scope())) + return contractDef->isLibrary(); + return false; } FunctionTypePointer FunctionDefinition::functionType(bool _internal) const diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 721e76791f88..c6c560988a0c 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -88,7 +88,7 @@ class ASTNode: private boost::noncopyable virtual ~ASTNode() {} /// @returns an identifier of this AST node that is unique for a single compilation run. - int64_t id() const { return m_id; } + int64_t id() const { return int64_t(m_id); } virtual void accept(ASTVisitor& _visitor) = 0; virtual void accept(ASTConstVisitor& _visitor) const = 0; @@ -799,6 +799,7 @@ class FunctionDefinition: public CallableDeclaration, public StructurallyDocumen void accept(ASTConstVisitor& _visitor) const override; StateMutability stateMutability() const { return m_stateMutability; } + bool libraryFunction() const; bool isOrdinary() const { return m_kind == Token::Function; } bool isConstructor() const { return m_kind == Token::Constructor; } bool isFallback() const { return m_kind == Token::Fallback; } @@ -825,8 +826,6 @@ class FunctionDefinition: public CallableDeclaration, public StructurallyDocumen /// @returns the external identifier of this function (the hash of the signature) as a hex string. std::string externalIdentifierHex() const; - ContractKind inContractKind() const; - TypePointer type() const override; TypePointer typeViaContractName() const override; diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index 8da1dddd719d..219151f89286 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -37,6 +37,7 @@ #include #include #include +#include using namespace std; using namespace solidity::langutil; @@ -134,7 +135,7 @@ size_t ASTJsonConverter::sourceIndexFromLocation(SourceLocation const& _location if (_location.source && m_sourceIndices.count(_location.source->name())) return m_sourceIndices.at(_location.source->name()); else - return size_t(-1); + return numeric_limits::max(); } string ASTJsonConverter::sourceLocationToString(SourceLocation const& _location) const diff --git a/libsolidity/ast/ASTJsonImporter.cpp b/libsolidity/ast/ASTJsonImporter.cpp index 97e3ba964455..65f9fa718e88 100644 --- a/libsolidity/ast/ASTJsonImporter.cpp +++ b/libsolidity/ast/ASTJsonImporter.cpp @@ -92,7 +92,7 @@ SourceLocation const ASTJsonImporter::createSourceLocation(Json::Value const& _n { astAssert(member(_node, "src").isString(), "'src' must be a string"); - return solidity::langutil::parseSourceLocation(_node["src"].asString(), m_currentSourceName, int(m_sourceLocations.size())); + return solidity::langutil::parseSourceLocation(_node["src"].asString(), m_currentSourceName, m_sourceLocations.size()); } template diff --git a/libsolidity/ast/TypeProvider.h b/libsolidity/ast/TypeProvider.h index 38f2642eb8df..a86542d1688a 100644 --- a/libsolidity/ast/TypeProvider.h +++ b/libsolidity/ast/TypeProvider.h @@ -112,14 +112,22 @@ class TypeProvider /// @returns a copy of @a _type having the same location as this (and is not a pointer type) /// if _type is a reference type and an unmodified copy of _type otherwise. /// This function is mostly useful to modify inner types appropriately. - static Type const* withLocationIfReference(DataLocation _location, Type const* _type) + static Type const* withLocationIfReference(DataLocation _location, Type const* _type, bool _isPointer = false) { if (auto refType = dynamic_cast(_type)) - return withLocation(refType, _location, false); + return withLocation(refType, _location, _isPointer); return _type; } + static bool isReferenceWithLocation(Type const* _type, DataLocation _location) + { + if (auto const* refType = dynamic_cast(_type)) + if (refType->location() == _location) + return true; + return false; + } + /// @returns the internally-facing or externally-facing type of a function or the type of a function declaration. static FunctionType const* function(FunctionDefinition const& _function, FunctionType::Kind _kind = FunctionType::Kind::Declaration); diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 66681ea10790..bb202e8755ac 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -356,10 +356,18 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition for (ContractDefinition const* contract: _scope.annotation().linearizedBaseContracts) for (UsingForDirective const* ufd: contract->usingForDirectives()) { - if (ufd->typeName() && _type != *TypeProvider::withLocationIfReference( - typeLocation, - ufd->typeName()->annotation().type - )) + // Convert both types to pointers for comparison to see if the `using for` + // directive applies. + // Further down, we check more detailed for each function if `_type` is + // convertible to the function parameter type. + if (ufd->typeName() && + *TypeProvider::withLocationIfReference(typeLocation, &_type, true) != + *TypeProvider::withLocationIfReference( + typeLocation, + ufd->typeName()->annotation().type, + true + ) + ) continue; auto const& library = dynamic_cast( *ufd->libraryName().annotation().referencedDeclaration @@ -371,7 +379,8 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition seenFunctions.insert(function); if (function->parameters().empty()) continue; - FunctionTypePointer fun = FunctionType(*function, FunctionType::Kind::External).asExternallyCallableFunction(true, true); + FunctionTypePointer fun = + dynamic_cast(*function->typeViaContractName()).asBoundFunction(); if (_type.isImplicitlyConvertibleTo(*fun->selfType())) members.emplace_back(function->name(), fun, function); } @@ -773,7 +782,7 @@ tuple RationalNumberType::parseRational(string const& _value) denominator = bigint(string(fractionalBegin, _value.end())); denominator /= boost::multiprecision::pow( bigint(10), - distance(radixPoint + 1, _value.end()) + static_cast(distance(radixPoint + 1, _value.end())) ); numerator = bigint(string(_value.begin(), radixPoint)); value = numerator + denominator; @@ -1065,7 +1074,7 @@ TypeResult RationalNumberType::binaryOperatorResult(Token _operator, Type const* if (_base == 1) return 1; else if (_base == -1) - return 1 - 2 * int(_exponent & 1); + return 1 - 2 * static_cast(_exponent & 1); else return boost::multiprecision::pow(_base, _exponent); }; @@ -1171,7 +1180,7 @@ string RationalNumberType::bigintToReadableString(bigint const& _num) string str = _num.str(); if (str.size() > 32) { - int omitted = str.size() - 8; + size_t omitted = str.size() - 8; str = str.substr(0, 4) + "...(" + to_string(omitted) + " digits omitted)..." + str.substr(str.size() - 4, 4); } return str; @@ -1201,7 +1210,7 @@ u256 RationalNumberType::literalValue(Literal const*) const { auto fixed = fixedPointType(); solAssert(fixed, "Rational number cannot be represented as fixed point type."); - int fractionalDigits = fixed->fractionalDigits(); + unsigned fractionalDigits = fixed->fractionalDigits(); shiftedValue = m_value.numerator() * boost::multiprecision::pow(bigint(10), fractionalDigits) / m_value.denominator(); } @@ -1291,7 +1300,7 @@ StringLiteralType::StringLiteralType(string _value): BoolResult StringLiteralType::isImplicitlyConvertibleTo(Type const& _convertTo) const { if (auto fixedBytes = dynamic_cast(&_convertTo)) - return size_t(fixedBytes->numBytes()) >= m_value.size(); + return static_cast(fixedBytes->numBytes()) >= m_value.size(); else if (auto arrayType = dynamic_cast(&_convertTo)) return arrayType->isByteArray() && @@ -2457,6 +2466,21 @@ set StructType::membersMissingInMemory() const return missing; } +vector> StructType::makeStackItems() const +{ + switch (m_location) + { + case DataLocation::CallData: + return {std::make_tuple("offset", TypeProvider::uint256())}; + case DataLocation::Memory: + return {std::make_tuple("mpos", TypeProvider::uint256())}; + case DataLocation::Storage: + return {std::make_tuple("slot", TypeProvider::uint256())}; + } + solAssert(false, ""); +} + + TypePointer EnumType::encodingType() const { return TypeProvider::uint(8 * storageBytes()); @@ -3438,34 +3462,61 @@ TypePointer FunctionType::copyAndSetCallOptions(bool _setGas, bool _setValue, bo ); } -FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary, bool _bound) const +FunctionTypePointer FunctionType::asBoundFunction() const { - if (_bound) - solAssert(!m_parameterTypes.empty(), ""); + solAssert(!m_parameterTypes.empty(), ""); + FunctionDefinition const* fun = dynamic_cast(m_declaration); + solAssert(fun && fun->libraryFunction(), ""); + solAssert(!m_gasSet, ""); + solAssert(!m_valueSet, ""); + solAssert(!m_saltSet, ""); + return TypeProvider::function( + m_parameterTypes, + m_returnParameterTypes, + m_parameterNames, + m_returnParameterNames, + m_kind, + m_arbitraryParameters, + m_stateMutability, + m_declaration, + m_gasSet, + m_valueSet, + m_saltSet, + true + ); +} +FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary) const +{ TypePointers parameterTypes; for (auto const& t: m_parameterTypes) - { - auto refType = dynamic_cast(t); - if (refType && refType->location() == DataLocation::CallData) - parameterTypes.push_back(TypeProvider::withLocation(refType, DataLocation::Memory, true)); + if (TypeProvider::isReferenceWithLocation(t, DataLocation::CallData)) + parameterTypes.push_back( + TypeProvider::withLocationIfReference(DataLocation::Memory, t, true) + ); else parameterTypes.push_back(t); - } + + TypePointers returnParameterTypes; + for (auto const& returnParamType: m_returnParameterTypes) + if (TypeProvider::isReferenceWithLocation(returnParamType, DataLocation::CallData)) + returnParameterTypes.push_back( + TypeProvider::withLocationIfReference(DataLocation::Memory, returnParamType, true) + ); + else + returnParameterTypes.push_back(returnParamType); Kind kind = m_kind; if (_inLibrary) { solAssert(!!m_declaration, "Declaration has to be available."); - if (!m_declaration->isPublic()) - kind = Kind::Internal; // will be inlined - else - kind = Kind::DelegateCall; + solAssert(m_declaration->isPublic(), ""); + kind = Kind::DelegateCall; } return TypeProvider::function( parameterTypes, - m_returnParameterTypes, + returnParameterTypes, m_parameterNames, m_returnParameterNames, kind, @@ -3475,7 +3526,7 @@ FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary, m_gasSet, m_valueSet, m_saltSet, - _bound + m_bound ); } diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 609f2e9edf83..a82700808a55 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -980,6 +980,8 @@ class StructType: public ReferenceType void clearCache() const override; +protected: + std::vector> makeStackItems() const override; private: StructDefinition const& m_struct; // Caches for interfaceType(bool) @@ -1302,13 +1304,16 @@ class FunctionType: public Type /// of the parameters to false. TypePointer copyAndSetCallOptions(bool _setGas, bool _setValue, bool _setSalt) const; + /// @returns a copy of this function type with the `bound` flag set to true. + /// Should only be called on library functions. + FunctionTypePointer asBoundFunction() const; + /// @returns a copy of this function type where the location of reference types is changed /// from CallData to Memory. This is the type that would be used when the function is /// called externally, as opposed to the parameter types that are available inside the function body. /// Also supports variants to be used for library or bound calls. /// @param _inLibrary if true, uses DelegateCall as location. - /// @param _bound if true, the function type is set to be bound. - FunctionTypePointer asExternallyCallableFunction(bool _inLibrary, bool _bound = false) const; + FunctionTypePointer asExternallyCallableFunction(bool _inLibrary) const; protected: std::vector> makeStackItems() const override; diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index 189fba165c8b..9f244fdb15dd 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -725,7 +725,7 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray( size_t itemsPerSlot = 32 / storageBytes; solAssert(itemsPerSlot > 0, ""); // The number of elements we need to handle manually after the loop. - size_t spill = size_t(_from.length() % itemsPerSlot); + size_t spill = static_cast(_from.length() % itemsPerSlot); Whiskers templ( R"( // -> diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp index 732deca6f648..9f12f648f8c6 100644 --- a/libsolidity/codegen/ArrayUtils.cpp +++ b/libsolidity/codegen/ArrayUtils.cpp @@ -56,7 +56,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons bool directCopy = sourceIsStorage && sourceBaseType->isValueType() && *sourceBaseType == *targetBaseType; bool haveByteOffsetSource = !directCopy && sourceIsStorage && sourceBaseType->storageBytes() <= 16; bool haveByteOffsetTarget = !directCopy && targetBaseType->storageBytes() <= 16; - unsigned byteOffsetSize = (haveByteOffsetSource ? 1 : 0) + (haveByteOffsetTarget ? 1 : 0); + unsigned byteOffsetSize = (haveByteOffsetSource ? 1u : 0u) + (haveByteOffsetTarget ? 1u : 0u); // stack: source_ref [source_length] target_ref // store target_ref diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 9e2c0663bdd6..fea449f7fd5a 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -133,7 +133,7 @@ void CompilerContext::callLowLevelFunction( *this << lowLevelFunctionTag(_name, _inArgs, _outArgs, _generator); appendJump(evmasm::AssemblyItem::JumpType::IntoFunction); - adjustStackOffset(int(_outArgs) - 1 - _inArgs); + adjustStackOffset(static_cast(_outArgs) - 1 - static_cast(_inArgs)); *this << retTag.tag(); } @@ -147,7 +147,7 @@ void CompilerContext::callYulFunction( auto const retTag = pushNewTag(); CompilerUtils(*this).moveIntoStack(_inArgs); appendJumpTo(namedTag(_name)); - adjustStackOffset(int(_outArgs) - 1 - _inArgs); + adjustStackOffset(static_cast(_outArgs) - 1 - static_cast(_inArgs)); *this << retTag.tag(); } @@ -181,7 +181,7 @@ void CompilerContext::appendMissingLowLevelFunctions() tie(name, inArgs, outArgs, generator) = m_lowLevelFunctionGenerationQueue.front(); m_lowLevelFunctionGenerationQueue.pop(); - setStackOffset(inArgs + 1); + setStackOffset(static_cast(inArgs) + 1); *this << m_lowLevelFunctions.at(name).tag(); generator(*this); CompilerUtils(*this).moveToStackTop(outArgs); @@ -298,12 +298,12 @@ unsigned CompilerContext::baseStackOffsetOfVariable(Declaration const& _declarat unsigned CompilerContext::baseToCurrentStackOffset(unsigned _baseOffset) const { - return m_asm->deposit() - _baseOffset - 1; + return static_cast(m_asm->deposit()) - _baseOffset - 1; } unsigned CompilerContext::currentToBaseStackOffset(unsigned _offset) const { - return m_asm->deposit() - _offset - 1; + return static_cast(m_asm->deposit()) - _offset - 1; } pair CompilerContext::storageLocationOfVariable(Declaration const& _declaration) const @@ -371,7 +371,7 @@ void CompilerContext::appendInlineAssembly( OptimiserSettings const& _optimiserSettings ) { - int startStackHeight = stackHeight(); + unsigned startStackHeight = stackHeight(); set externallyUsedIdentifiers; for (auto const& fun: _externallyUsedFunctions) @@ -387,9 +387,9 @@ void CompilerContext::appendInlineAssembly( ) -> size_t { if (_insideFunction) - return size_t(-1); + return numeric_limits::max(); auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str()); - return it == _localVariables.end() ? size_t(-1) : 1; + return it == _localVariables.end() ? numeric_limits::max() : 1; }; identifierAccess.generateCode = [&]( yul::Identifier const& _identifier, @@ -399,8 +399,8 @@ void CompilerContext::appendInlineAssembly( { auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str()); solAssert(it != _localVariables.end(), ""); - int stackDepth = _localVariables.end() - it; - int stackDiff = _assembly.stackHeight() - startStackHeight + stackDepth; + auto stackDepth = static_cast(distance(it, _localVariables.end())); + size_t stackDiff = static_cast(_assembly.stackHeight()) - startStackHeight + stackDepth; if (_context == yul::IdentifierContext::LValue) stackDiff -= 1; if (stackDiff < 1 || stackDiff > 16) diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index 51d3afe1c1b5..c32b5140627f 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -377,7 +377,7 @@ class CompilerContext /// The runtime context if in Creation mode, this is used for generating tags that would be stored into the storage and then used at runtime. CompilerContext *m_runtimeContext; /// The index of the runtime subroutine. - size_t m_runtimeSub = -1; + size_t m_runtimeSub = std::numeric_limits::max(); /// An index of low-level function labels by name. std::map m_lowLevelFunctions; /// Collector for yul functions. diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 2735c2fce9ed..c3e81d13a860 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -1351,7 +1351,7 @@ void CompilerUtils::popAndJump(unsigned _toHeight, evmasm::AssemblyItem const& _ unsigned amount = m_context.stackHeight() - _toHeight; popStackSlots(amount); m_context.appendJumpTo(_jumpTo); - m_context.adjustStackOffset(amount); + m_context.adjustStackOffset(static_cast(amount)); } unsigned CompilerUtils::sizeOnStack(vector const& _variableTypes) @@ -1436,7 +1436,7 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda { bool leftAligned = _type.category() == Type::Category::FixedBytes; // add leading or trailing zeros by dividing/multiplying depending on alignment - int shiftFactor = (32 - numBytes) * 8; + unsigned shiftFactor = (32 - numBytes) * 8; rightShiftNumberOnStack(shiftFactor); if (leftAligned) { diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 269d9a5bf3e0..6f8603a51230 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -185,7 +185,7 @@ size_t ContractCompiler::packIntoContractCreator(ContractDefinition const& _cont CompilerContext::LocationSetter locationSetter(m_context, _contract); m_context << deployRoutine; - solAssert(m_context.runtimeSub() != size_t(-1), "Runtime sub not registered"); + solAssert(m_context.runtimeSub() != numeric_limits::max(), "Runtime sub not registered"); ContractType contractType(_contract); auto const& immutables = contractType.immutableVariables(); @@ -221,7 +221,7 @@ size_t ContractCompiler::deployLibrary(ContractDefinition const& _contract) CompilerContext::LocationSetter locationSetter(m_context, _contract); - solAssert(m_context.runtimeSub() != size_t(-1), "Runtime sub not registered"); + solAssert(m_context.runtimeSub() != numeric_limits::max(), "Runtime sub not registered"); m_context.pushSubroutineSize(m_context.runtimeSub()); m_context.pushSubroutineOffset(m_context.runtimeSub()); // This code replaces the address added by appendDeployTimeAddress(). @@ -349,11 +349,11 @@ void ContractCompiler::appendInternalSelector( m_context << dupInstruction(1) << u256(FixedHash<4>::Arith(pivot)) << Instruction::GT; evmasm::AssemblyItem lessTag{m_context.appendConditionalJump()}; // Here, we have funid >= pivot - vector> larger{_ids.begin() + pivotIndex, _ids.end()}; + vector> larger{_ids.begin() + static_cast(pivotIndex), _ids.end()}; appendInternalSelector(_entryPoints, larger, _notFoundTag, _runs); m_context << lessTag; // Here, we have funid < pivot - vector> smaller{_ids.begin(), _ids.begin() + pivotIndex}; + vector> smaller{_ids.begin(), _ids.begin() + static_cast(pivotIndex)}; appendInternalSelector(_entryPoints, smaller, _notFoundTag, _runs); } else @@ -512,8 +512,8 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac m_context << returnTag; // Return tag and input parameters get consumed. m_context.adjustStackOffset( - CompilerUtils(m_context).sizeOnStack(functionType->returnParameterTypes()) - - CompilerUtils(m_context).sizeOnStack(functionType->parameterTypes()) - + static_cast(CompilerUtils::sizeOnStack(functionType->returnParameterTypes())) - + static_cast(CompilerUtils::sizeOnStack(functionType->parameterTypes())) - 1 ); // Consumes the return parameters. @@ -589,7 +589,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) unsigned parametersSize = CompilerUtils::sizeOnStack(_function.parameters()); if (!_function.isConstructor()) // adding 1 for return address. - m_context.adjustStackOffset(parametersSize + 1); + m_context.adjustStackOffset(static_cast(parametersSize) + 1); for (ASTPointer const& variable: _function.parameters()) { m_context.addVariable(*variable, parametersSize); @@ -609,7 +609,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) m_breakTags.clear(); m_continueTags.clear(); m_currentFunction = &_function; - m_modifierDepth = -1; + m_modifierDepth = numeric_limits::max(); m_scopeStackHeight.clear(); m_context.setModifierDepth(0); @@ -627,10 +627,10 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) unsigned const c_returnValuesSize = CompilerUtils::sizeOnStack(_function.returnParameters()); vector stackLayout; - stackLayout.push_back(c_returnValuesSize); // target of return address + stackLayout.push_back(static_cast(c_returnValuesSize)); // target of return address stackLayout += vector(c_argumentsSize, -1); // discard all arguments - for (unsigned i = 0; i < c_returnValuesSize; ++i) - stackLayout.push_back(i); + for (size_t i = 0; i < c_returnValuesSize; ++i) + stackLayout.push_back(static_cast(i)); if (stackLayout.size() > 17) BOOST_THROW_EXCEPTION( @@ -638,7 +638,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) errinfo_sourceLocation(_function.location()) << errinfo_comment("Stack too deep, try removing local variables.") ); - while (stackLayout.back() != int(stackLayout.size() - 1)) + while (stackLayout.back() != static_cast(stackLayout.size() - 1)) if (stackLayout.back() < 0) { m_context << Instruction::POP; @@ -646,11 +646,11 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) } else { - m_context << swapInstruction(stackLayout.size() - stackLayout.back() - 1); - swap(stackLayout[stackLayout.back()], stackLayout.back()); + m_context << swapInstruction(stackLayout.size() - static_cast(stackLayout.back()) - 1); + swap(stackLayout[static_cast(stackLayout.back())], stackLayout.back()); } - for (int i = 0; i < int(stackLayout.size()); ++i) - if (stackLayout[i] != i) + for (size_t i = 0; i < stackLayout.size(); ++i) + if (stackLayout[i] != static_cast(i)) solAssert(false, "Invalid stack layout on cleanup."); for (ASTPointer const& variable: _function.parameters() + _function.returnParameters()) @@ -677,7 +677,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) { auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier); if (ref == _inlineAssembly.annotation().externalReferences.end()) - return size_t(-1); + return numeric_limits::max(); return ref->second.valueSize; }; identifierAccess.generateCode = [&](yul::Identifier const& _identifier, yul::IdentifierContext _context, yul::AbstractAssembly& _assembly) @@ -696,7 +696,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) functionDef = &functionDef->resolveVirtual(m_context.mostDerivedContract()); auto functionEntryLabel = m_context.functionEntryLabel(*functionDef).pushTag(); solAssert(functionEntryLabel.data() <= std::numeric_limits::max(), ""); - _assembly.appendLabelReference(size_t(functionEntryLabel.data())); + _assembly.appendLabelReference(static_cast(functionEntryLabel.data())); // If there is a runtime context, we have to merge both labels into the same // stack slot in case we store it in storage. if (CompilerContext* rtc = m_context.runtimeContext()) @@ -705,7 +705,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) _assembly.appendInstruction(Instruction::MUL); auto runtimeEntryLabel = rtc->functionEntryLabel(*functionDef).toSubAssemblyTag(m_context.runtimeSub()); solAssert(runtimeEntryLabel.data() <= std::numeric_limits::max(), ""); - _assembly.appendLabelReference(size_t(runtimeEntryLabel.data())); + _assembly.appendLabelReference(static_cast(runtimeEntryLabel.data())); _assembly.appendInstruction(Instruction::OR); } } @@ -772,7 +772,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) } else if (m_context.isLocalVariable(decl)) { - int stackDiff = _assembly.stackHeight() - m_context.baseStackOffsetOfVariable(*variable); + unsigned stackDiff = static_cast(_assembly.stackHeight()) - m_context.baseStackOffsetOfVariable(*variable); if (ref->second.isSlot || ref->second.isOffset) { solAssert(variable->type()->dataStoredIn(DataLocation::Storage), ""); @@ -816,7 +816,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) } else solAssert(false, "Invalid declaration type."); - solAssert(_assembly.stackHeight() - depositBefore == int(ref->second.valueSize), ""); + solAssert(_assembly.stackHeight() - depositBefore == static_cast(ref->second.valueSize), ""); } else { @@ -828,7 +828,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) "Can only assign to stack variables in inline assembly." ); solAssert(variable->type()->sizeOnStack() == 1, ""); - int stackDiff = _assembly.stackHeight() - m_context.baseStackOffsetOfVariable(*variable) - 1; + unsigned stackDiff = static_cast(_assembly.stackHeight()) - m_context.baseStackOffsetOfVariable(*variable) - 1; if (stackDiff > 16 || stackDiff < 1) BOOST_THROW_EXCEPTION( CompilerError() << @@ -875,7 +875,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) false, m_optimiserSettings.optimizeStackAllocation ); - m_context.setStackOffset(startStackHeight); + m_context.setStackOffset(static_cast(startStackHeight)); return false; } @@ -914,7 +914,7 @@ bool ContractCompiler::visit(TryStatement const& _tryStatement) solAssert(params[i] && exprTypes[i] && *params[i]->annotation().type == *exprTypes[i], ""); } else - CompilerUtils(m_context).popStackSlots(returnSize); + CompilerUtils(m_context).popStackSlots(static_cast(returnSize)); _tryStatement.clauses().front()->accept(*this); } @@ -937,7 +937,7 @@ void ContractCompiler::handleCatch(vector> const& _ca else solAssert(false, ""); - solAssert(_catchClauses.size() == size_t(1 + (structured ? 1 : 0) + (fallback ? 1 : 0)), ""); + solAssert(_catchClauses.size() == 1ul + (structured ? 1 : 0) + (fallback ? 1 : 0), ""); evmasm::AssemblyItem endTag = m_context.newTag(); evmasm::AssemblyItem fallbackTag = m_context.newTag(); diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 6397c7492de6..a020551f36ac 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -100,7 +100,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& if (_varDecl.immutable()) solAssert(paramTypes.empty(), ""); - m_context.adjustStackOffset(1 + CompilerUtils::sizeOnStack(paramTypes)); + m_context.adjustStackOffset(static_cast(1 + CompilerUtils::sizeOnStack(paramTypes))); if (!_varDecl.immutable()) { @@ -242,7 +242,7 @@ bool ExpressionCompiler::visit(Conditional const& _condition) acceptAndConvert(_condition.falseExpression(), *_condition.annotation().type); evmasm::AssemblyItem endTag = m_context.appendJumpToNew(); m_context << trueTag; - int offset = _condition.annotation().type->sizeOnStack(); + int offset = static_cast(_condition.annotation().type->sizeOnStack()); m_context.adjustStackOffset(-offset); acceptAndConvert(_condition.trueExpression(), *_condition.annotation().type); m_context << endTag; @@ -619,7 +619,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) unsigned returnParametersSize = CompilerUtils::sizeOnStack(function.returnParameterTypes()); // callee adds return parameters, but removes arguments and return label - m_context.adjustStackOffset(returnParametersSize - parameterSize - 1); + m_context.adjustStackOffset(static_cast(returnParametersSize - parameterSize) - 1); break; } case FunctionType::Kind::BareCall: @@ -705,7 +705,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) acceptAndConvert(*arguments.front(), *TypeProvider::uint256(), true); // Note that function is not the original function, but the ".gas" function. // Its values of gasSet and valueSet is equal to the original function's though. - unsigned stackDepth = (function.gasSet() ? 1 : 0) + (function.valueSet() ? 1 : 0); + unsigned stackDepth = (function.gasSet() ? 1u : 0u) + (function.valueSet() ? 1u : 0u); if (stackDepth > 0) m_context << swapInstruction(stackDepth); if (function.gasSet()) @@ -814,7 +814,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) case FunctionType::Kind::Log3: case FunctionType::Kind::Log4: { - unsigned logNumber = int(function.kind()) - int(FunctionType::Kind::Log0); + unsigned logNumber = static_cast(function.kind()) - static_cast(FunctionType::Kind::Log0); for (unsigned arg = logNumber; arg > 0; --arg) acceptAndConvert(*arguments[arg], *function.parameterTypes()[arg], true); arguments.front()->accept(*this); @@ -1088,7 +1088,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) { utils().revertWithStringData(*arguments.at(1)->annotation().type); // Here, the argument is consumed, but in the other branch, it is still there. - m_context.adjustStackOffset(arguments.at(1)->annotation().type->sizeOnStack()); + m_context.adjustStackOffset(static_cast(arguments.at(1)->annotation().type->sizeOnStack())); } else m_context.appendRevert(); @@ -1271,9 +1271,9 @@ bool ExpressionCompiler::visit(FunctionCallOptions const& _functionCallOptions) acceptAndConvert(*_functionCallOptions.options()[i], *requiredType); solAssert(!contains(presentOptions, newOption), ""); - size_t insertPos = presentOptions.end() - lower_bound(presentOptions.begin(), presentOptions.end(), newOption); + ptrdiff_t insertPos = presentOptions.end() - lower_bound(presentOptions.begin(), presentOptions.end(), newOption); - utils().moveIntoStack(insertPos, 1); + utils().moveIntoStack(static_cast(insertPos), 1); presentOptions.insert(presentOptions.end() - insertPos, newOption); } @@ -2190,7 +2190,7 @@ void ExpressionCompiler::appendExternalFunctionCall( // contract address unsigned selfSize = _functionType.bound() ? _functionType.selfType()->sizeOnStack() : 0; - unsigned gasValueSize = (_functionType.gasSet() ? 1 : 0) + (_functionType.valueSet() ? 1 : 0); + unsigned gasValueSize = (_functionType.gasSet() ? 1u : 0u) + (_functionType.valueSet() ? 1u : 0u); unsigned contractStackPos = m_context.currentToBaseStackOffset(1 + gasValueSize + selfSize + (_functionType.isBareCall() ? 0 : 1)); unsigned gasStackPos = m_context.currentToBaseStackOffset(gasValueSize); unsigned valueStackPos = m_context.currentToBaseStackOffset(1); @@ -2361,7 +2361,7 @@ void ExpressionCompiler::appendExternalFunctionCall( m_context << Instruction::CALL; unsigned remainsSize = - 2 + // contract address, input_memory_end + 2u + // contract address, input_memory_end (_functionType.valueSet() ? 1 : 0) + (_functionType.gasSet() ? 1 : 0) + (!_functionType.isBareCall() ? 1 : 0); diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 87142099e1d0..f7d9711a260b 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -1652,8 +1652,7 @@ string YulUtilFunctions::allocateAndInitializeMemoryStructFunction(StructType co return m_functionCollector.createFunction(functionName, [&]() { Whiskers templ(R"( function () -> memPtr { - let allocSize := () - memPtr := (allocSize) + memPtr := () let offset := memPtr <#member> mstore(offset, ()) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 075cad1f32a8..3ec89a23315e 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -636,7 +636,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) }); solAssert(it != callArgumentNames.cend(), ""); - arguments.push_back(callArguments[std::distance(callArgumentNames.begin(), it)]); + arguments.push_back(callArguments[static_cast(std::distance(callArgumentNames.begin(), it))]); } auto memberAccess = dynamic_cast(&_functionCall.expression()); @@ -1092,7 +1092,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) case FunctionType::Kind::Log3: case FunctionType::Kind::Log4: { - unsigned logNumber = int(functionType->kind()) - int(FunctionType::Kind::Log0); + unsigned logNumber = static_cast(functionType->kind()) - static_cast(FunctionType::Kind::Log0); solAssert(arguments.size() == logNumber + 1, ""); ABIFunctions abi(m_context.evmVersion(), m_context.revertStrings(), m_context.functionCollector()); string indexedArgs; @@ -1477,7 +1477,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) pair const& offsets = structType.storageOffsetsOfMember(member); string slot = m_context.newYulVariable(); m_code << "let " << slot << " := " << - ("add(" + expression.name() + ", " + offsets.first.str() + ")\n"); + ("add(" + expression.part("slot").name() + ", " + offsets.first.str() + ")\n"); setLValue(_memberAccess, IRLValue{ type(_memberAccess), IRLValue::Storage{slot, offsets.second} @@ -1497,7 +1497,25 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) } case DataLocation::CallData: { - solUnimplementedAssert(false, ""); + string baseRef = expression.part("offset").name(); + string offset = m_context.newYulVariable(); + m_code << "let " << offset << " := " << "add(" << baseRef << ", " << to_string(structType.calldataOffsetOfMember(member)) << ")\n"; + if (_memberAccess.annotation().type->isDynamicallyEncoded()) + define(_memberAccess) << + m_utils.accessCalldataTailFunction(*_memberAccess.annotation().type) << + "(" << + baseRef << + ", " << + offset << + ")" << + std::endl; + else + define(_memberAccess) << + m_utils.readFromCalldata(*_memberAccess.annotation().type) << + "(" << + offset << + ")" << + std::endl; break; } default: @@ -1730,7 +1748,7 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess) setLValue(_indexAccess, IRLValue{ *arrayType.baseType(), - IRLValue::Memory{memAddress} + IRLValue::Memory{memAddress, arrayType.isByteArray()} }); break; } @@ -1763,7 +1781,23 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess) } } else if (baseType.category() == Type::Category::FixedBytes) - solUnimplementedAssert(false, ""); + { + auto const& fixedBytesType = dynamic_cast(baseType); + solAssert(_indexAccess.indexExpression(), "Index expression expected."); + + IRVariable index{m_context.newYulVariable(), *TypeProvider::uint256()}; + define(index, *_indexAccess.indexExpression()); + m_code << Whiskers(R"( + if iszero(lt(, )) { invalid() } + let := (byte(, )) + )") + ("index", index.name()) + ("length", to_string(fixedBytesType.numBytes())) + ("array", IRVariable(_indexAccess.baseExpression()).name()) + ("shl248", m_utils.shiftLeftFunction(256 - 8)) + ("result", IRVariable(_indexAccess).name()) + .render(); + } else if (baseType.category() == Type::Category::TypeType) { solAssert(baseType.sizeOnStack() == 0, ""); diff --git a/libsolidity/formal/BMC.cpp b/libsolidity/formal/BMC.cpp index 8ec6b3564b6e..8f74dbb3e8b3 100644 --- a/libsolidity/formal/BMC.cpp +++ b/libsolidity/formal/BMC.cpp @@ -604,7 +604,11 @@ void BMC::checkUnderflow(BMCVerificationTarget& _target, smtutil::Expression con _target.type == VerificationTarget::Type::UnderOverflow, "" ); - auto intType = dynamic_cast(_target.expression->annotation().type); + IntegerType const* intType = nullptr; + if (auto const* type = dynamic_cast(_target.expression->annotation().type)) + intType = type; + else + intType = TypeProvider::uint256(); solAssert(intType, ""); checkCondition( _target.constraints && _constraints && _target.value < smt::minValue(*intType), @@ -626,7 +630,12 @@ void BMC::checkOverflow(BMCVerificationTarget& _target, smtutil::Expression cons _target.type == VerificationTarget::Type::UnderOverflow, "" ); - auto intType = dynamic_cast(_target.expression->annotation().type); + IntegerType const* intType = nullptr; + if (auto const* type = dynamic_cast(_target.expression->annotation().type)) + intType = type; + else + intType = TypeProvider::uint256(); + solAssert(intType, ""); checkCondition( _target.constraints && _constraints && _target.value > smt::maxValue(*intType), diff --git a/libsolidity/formal/CHC.cpp b/libsolidity/formal/CHC.cpp index f0ba6d0de096..791a4f41d2b8 100644 --- a/libsolidity/formal/CHC.cpp +++ b/libsolidity/formal/CHC.cpp @@ -104,7 +104,7 @@ void CHC::analyze(SourceUnit const& _source) for (auto const* assertion: assertions) { createErrorBlock(); - connectBlocks(target.value, error(), target.constraints && (target.errorId == assertion->id())); + connectBlocks(target.value, error(), target.constraints && (target.errorId == static_cast(assertion->id()))); auto [result, model] = query(error(), assertion->location()); // This should be fine but it's a bug in the old compiler (void)model; @@ -116,7 +116,7 @@ void CHC::analyze(SourceUnit const& _source) { solAssert(dynamic_cast(scope), ""); createErrorBlock(); - connectBlocks(target.value, error(), target.constraints && (target.errorId == scope->id())); + connectBlocks(target.value, error(), target.constraints && (target.errorId == static_cast(scope->id()))); auto [result, model] = query(error(), scope->location()); // This should be fine but it's a bug in the old compiler (void)model; @@ -533,7 +533,9 @@ void CHC::visitAssert(FunctionCall const& _funCall) connectBlocks( m_currentBlock, m_currentFunction->isConstructor() ? summary(*m_currentContract) : summary(*m_currentFunction), - currentPathConditions() && !m_context.expression(*args.front())->currentValue() && (m_error.currentValue() == _funCall.id()) + currentPathConditions() && !m_context.expression(*args.front())->currentValue() && ( + m_error.currentValue() == static_cast(_funCall.id()) + ) ); m_context.addAssertion(m_error.currentValue() == previousError); @@ -601,7 +603,7 @@ void CHC::makeArrayPopVerificationTarget(FunctionCall const& _arrayPop) connectBlocks( m_currentBlock, m_currentFunction->isConstructor() ? summary(*m_currentContract) : summary(*m_currentFunction), - currentPathConditions() && symbArray->length() <= 0 && m_error.currentValue() == _arrayPop.id() + currentPathConditions() && symbArray->length() <= 0 && m_error.currentValue() == static_cast(_arrayPop.id()) ); m_context.addAssertion(m_error.currentValue() == previousError); @@ -891,13 +893,13 @@ vector CHC::initialStateVariables() return stateVariablesAtIndex(0); } -vector CHC::stateVariablesAtIndex(int _index) +vector CHC::stateVariablesAtIndex(unsigned _index) { solAssert(m_currentContract, ""); return applyMap(m_stateVariables, [&](auto _var) { return valueAtIndex(*_var, _index); }); } -vector CHC::stateVariablesAtIndex(int _index, ContractDefinition const& _contract) +vector CHC::stateVariablesAtIndex(unsigned _index, ContractDefinition const& _contract) { return applyMap( stateVariablesIncludingInheritedAndPrivate(_contract), diff --git a/libsolidity/formal/CHC.h b/libsolidity/formal/CHC.h index b1235a188cfe..b52ce6667382 100644 --- a/libsolidity/formal/CHC.h +++ b/libsolidity/formal/CHC.h @@ -149,8 +149,8 @@ class CHC: public SMTEncoder /// @returns the symbolic values of the state variables at the beginning /// of the current transaction. std::vector initialStateVariables(); - std::vector stateVariablesAtIndex(int _index); - std::vector stateVariablesAtIndex(int _index, ContractDefinition const& _contract); + std::vector stateVariablesAtIndex(unsigned _index); + std::vector stateVariablesAtIndex(unsigned _index, ContractDefinition const& _contract); /// @returns the current symbolic values of the current state variables. std::vector currentStateVariables(); diff --git a/libsolidity/formal/SMTEncoder.cpp b/libsolidity/formal/SMTEncoder.cpp index b06abbe6e95a..82cd7557874c 100644 --- a/libsolidity/formal/SMTEncoder.cpp +++ b/libsolidity/formal/SMTEncoder.cpp @@ -154,15 +154,16 @@ void SMTEncoder::visitFunctionOrModifier() ++m_modifierDepthStack.back(); FunctionDefinition const& function = dynamic_cast(*m_callStack.back().first); - if (m_modifierDepthStack.back() == int(function.modifiers().size())) + if (m_modifierDepthStack.back() == static_cast(function.modifiers().size())) { if (function.isImplemented()) function.body().accept(*this); } else { - solAssert(m_modifierDepthStack.back() < int(function.modifiers().size()), ""); - ASTPointer const& modifierInvocation = function.modifiers()[m_modifierDepthStack.back()]; + solAssert(m_modifierDepthStack.back() < static_cast(function.modifiers().size()), ""); + ASTPointer const& modifierInvocation = + function.modifiers()[static_cast(m_modifierDepthStack.back())]; solAssert(modifierInvocation, ""); auto refDecl = modifierInvocation->name()->annotation().referencedDeclaration; if (dynamic_cast(refDecl)) @@ -385,44 +386,22 @@ void SMTEncoder::endVisit(Assignment const& _assignment) } else { - auto const& type = _assignment.annotation().type; - vector rightArguments; - if (auto const* tupleTypeRight = dynamic_cast(_assignment.rightHandSide().annotation().type)) - { - auto symbTupleLeft = dynamic_pointer_cast(m_context.expression(_assignment.leftHandSide())); - solAssert(symbTupleLeft, ""); - auto symbTupleRight = dynamic_pointer_cast(m_context.expression(_assignment.rightHandSide())); - solAssert(symbTupleRight, ""); - - auto const& leftComponents = symbTupleLeft->components(); - auto const& rightComponents = symbTupleRight->components(); - solAssert(leftComponents.size() == rightComponents.size(), ""); - - auto tupleTypeLeft = dynamic_cast(_assignment.leftHandSide().annotation().type); - solAssert(tupleTypeLeft, ""); - solAssert(tupleTypeLeft->components().size() == leftComponents.size(), ""); - auto const& typesLeft = tupleTypeLeft->components(); - - solAssert(tupleTypeRight->components().size() == rightComponents.size(), ""); - auto const& typesRight = tupleTypeRight->components(); - - for (unsigned i = 0; i < rightComponents.size(); ++i) - rightArguments.push_back(symbTupleRight->component(i, typesRight.at(i), typesLeft.at(i))); - } + if (dynamic_cast(_assignment.rightHandSide().annotation().type)) + tupleAssignment(_assignment.leftHandSide(), _assignment.rightHandSide()); else { + auto const& type = _assignment.annotation().type; auto rightHandSide = compoundOps.count(op) ? compoundAssignment(_assignment) : expr(_assignment.rightHandSide(), type); defineExpr(_assignment, rightHandSide); - rightArguments.push_back(expr(_assignment, type)); + assignment( + _assignment.leftHandSide(), + expr(_assignment, type), + type, + _assignment.location() + ); } - assignment( - _assignment.leftHandSide(), - rightArguments, - type, - _assignment.location() - ); } } @@ -1023,38 +1002,7 @@ void SMTEncoder::arrayIndexAssignment(Expression const& _expr, smtutil::Expressi solAssert(varDecl, ""); if (varDecl->hasReferenceOrMappingType()) - m_context.resetVariables([&](VariableDeclaration const& _var) { - if (_var == *varDecl) - return false; - - // If both are state variables no need to clear knowledge. - if (_var.isStateVariable() && varDecl->isStateVariable()) - return false; - - TypePointer prefix = _var.type(); - TypePointer originalType = typeWithoutPointer(varDecl->type()); - while ( - prefix->category() == Type::Category::Mapping || - prefix->category() == Type::Category::Array - ) - { - if (*originalType == *typeWithoutPointer(prefix)) - return true; - if (prefix->category() == Type::Category::Mapping) - { - auto mapPrefix = dynamic_cast(prefix); - solAssert(mapPrefix, ""); - prefix = mapPrefix->valueType(); - } - else - { - auto arrayPrefix = dynamic_cast(prefix); - solAssert(arrayPrefix, ""); - prefix = arrayPrefix->baseType(); - } - } - return false; - }); + resetReferences(*varDecl); auto symbArray = dynamic_pointer_cast(m_context.variable(*varDecl)); smtutil::Expression store = smtutil::Expression::store( @@ -1160,6 +1108,8 @@ void SMTEncoder::arrayPushPopAssign(Expression const& _expr, smtutil::Expression { auto varDecl = identifierToVariable(*id); solAssert(varDecl, ""); + if (varDecl->hasReferenceOrMappingType()) + resetReferences(*varDecl); m_context.addAssertion(m_context.newValue(*varDecl) == _array); } else if (auto const* indexAccess = dynamic_cast(&_expr)) @@ -1213,7 +1163,7 @@ void SMTEncoder::arithmeticOperation(BinaryOperation const& _op) { auto type = _op.annotation().commonType; solAssert(type, ""); - if (type->category() == Type::Category::Integer) + if (type->category() == Type::Category::Integer || type->category() == Type::Category::FixedPoint) { switch (_op.getOperator()) { @@ -1266,13 +1216,21 @@ pair SMTEncoder::arithmeticOperation( }; solAssert(validOperators.count(_op), ""); solAssert(_commonType, ""); - solAssert(_commonType->category() == Type::Category::Integer, ""); + solAssert( + _commonType->category() == Type::Category::Integer || _commonType->category() == Type::Category::FixedPoint, + "" + ); + + IntegerType const* intType = nullptr; + if (auto type = dynamic_cast(_commonType)) + intType = type; + else + intType = TypeProvider::uint256(); - auto const& intType = dynamic_cast(*_commonType); smtutil::Expression valueNoMod( _op == Token::Add ? _left + _right : _op == Token::Sub ? _left - _right : - _op == Token::Div ? division(_left, _right, intType) : + _op == Token::Div ? division(_left, _right, *intType) : _op == Token::Mul ? _left * _right : /*_op == Token::Mod*/ _left % _right ); @@ -1280,20 +1238,23 @@ pair SMTEncoder::arithmeticOperation( if (_op == Token::Div || _op == Token::Mod) m_context.addAssertion(_right != 0); - smtutil::Expression intValueRange = (0 - smt::minValue(intType)) + smt::maxValue(intType) + 1; + auto symbMin = smt::minValue(*intType); + auto symbMax = smt::maxValue(*intType); + + smtutil::Expression intValueRange = (0 - symbMin) + symbMax + 1; auto value = smtutil::Expression::ite( - valueNoMod > smt::maxValue(intType), + valueNoMod > symbMax, valueNoMod % intValueRange, smtutil::Expression::ite( - valueNoMod < smt::minValue(intType), + valueNoMod < symbMin, valueNoMod % intValueRange, valueNoMod ) ); - if (intType.isSigned()) + if (intType->isSigned()) value = smtutil::Expression::ite( - value > smt::maxValue(intType), + value > symbMax, value - intValueRange, value ); @@ -1422,11 +1383,16 @@ smtutil::Expression SMTEncoder::division(smtutil::Expression _left, smtutil::Exp void SMTEncoder::assignment( Expression const& _left, - vector const& _right, + smtutil::Expression const& _right, TypePointer const& _type, langutil::SourceLocation const& _location ) { + solAssert( + _left.annotation().type->category() != Type::Category::Tuple, + "Tuple assignments should be handled by tupleAssignment." + ); + if (!smt::isSupportedType(_type->category())) { // Give it a new index anyway to keep the SSA scheme sound. @@ -1440,26 +1406,9 @@ void SMTEncoder::assignment( ); } else if (auto varDecl = identifierToVariable(_left)) - { - solAssert(_right.size() == 1, ""); - assignment(*varDecl, _right.front()); - } + assignment(*varDecl, _right); else if (dynamic_cast(&_left)) - { - solAssert(_right.size() == 1, ""); - arrayIndexAssignment(_left, _right.front()); - } - else if (auto tuple = dynamic_cast(&_left)) - { - auto const& components = tuple->components(); - if (!_right.empty()) - { - solAssert(_right.size() == components.size(), ""); - for (unsigned i = 0; i < _right.size(); ++i) - if (auto component = components.at(i)) - assignment(*component, {_right.at(i)}, component->annotation().type, component->location()); - } - } + arrayIndexAssignment(_left, _right); else m_errorReporter.warning( 8182_error, @@ -1468,6 +1417,52 @@ void SMTEncoder::assignment( ); } +void SMTEncoder::tupleAssignment(Expression const& _left, Expression const& _right) +{ + auto lTuple = dynamic_cast(&_left); + solAssert(lTuple, ""); + + auto const& lComponents = lTuple->components(); + + // If both sides are tuple expressions, we individually and potentially + // recursively assign each pair of components. + // This is because of potential type conversion. + if (auto rTuple = dynamic_cast(&_right)) + { + auto const& rComponents = rTuple->components(); + solAssert(lComponents.size() == rComponents.size(), ""); + for (unsigned i = 0; i < lComponents.size(); ++i) + { + if (!lComponents.at(i) || !rComponents.at(i)) + continue; + auto const& lExpr = *lComponents.at(i); + auto const& rExpr = *rComponents.at(i); + if (lExpr.annotation().type->category() == Type::Category::Tuple) + tupleAssignment(lExpr, rExpr); + else + { + auto type = lExpr.annotation().type; + assignment(lExpr, expr(rExpr, type), type, lExpr.location()); + } + } + } + else + { + auto rType = dynamic_cast(_right.annotation().type); + solAssert(rType, ""); + + auto const& rComponents = rType->components(); + solAssert(lComponents.size() == rComponents.size(), ""); + + auto symbRight = expr(_right); + solAssert(symbRight.sort->kind == smtutil::Kind::Tuple, ""); + + for (unsigned i = 0; i < lComponents.size(); ++i) + if (auto component = lComponents.at(i); component && rComponents.at(i)) + assignment(*component, smtutil::Expression::tuple_get(symbRight, i), component->annotation().type, component->location()); + } +} + smtutil::Expression SMTEncoder::compoundAssignment(Assignment const& _assignment) { static map const compoundToArithmetic{ @@ -1618,6 +1613,42 @@ void SMTEncoder::resetStateVariables() m_context.resetVariables([&](VariableDeclaration const& _variable) { return _variable.isStateVariable(); }); } +void SMTEncoder::resetReferences(VariableDeclaration const& _varDecl) +{ + m_context.resetVariables([&](VariableDeclaration const& _var) { + if (_var == _varDecl) + return false; + + // If both are state variables no need to clear knowledge. + if (_var.isStateVariable() && _varDecl.isStateVariable()) + return false; + + TypePointer prefix = _var.type(); + TypePointer originalType = typeWithoutPointer(_varDecl.type()); + while ( + prefix->category() == Type::Category::Mapping || + prefix->category() == Type::Category::Array + ) + { + if (*originalType == *typeWithoutPointer(prefix)) + return true; + if (prefix->category() == Type::Category::Mapping) + { + auto mapPrefix = dynamic_cast(prefix); + solAssert(mapPrefix, ""); + prefix = mapPrefix->valueType(); + } + else + { + auto arrayPrefix = dynamic_cast(prefix); + solAssert(arrayPrefix, ""); + prefix = arrayPrefix->baseType(); + } + } + return false; + }); +} + TypePointer SMTEncoder::typeWithoutPointer(TypePointer const& _type) { if (auto refType = dynamic_cast(_type)) @@ -1649,8 +1680,8 @@ void SMTEncoder::mergeVariables(set const& _variable for (auto const* decl: sortedVars) { solAssert(_indicesEndTrue.count(decl) && _indicesEndFalse.count(decl), ""); - int trueIndex = _indicesEndTrue.at(decl); - int falseIndex = _indicesEndFalse.at(decl); + auto trueIndex = static_cast(_indicesEndTrue.at(decl)); + auto falseIndex = static_cast(_indicesEndFalse.at(decl)); solAssert(trueIndex != falseIndex, ""); m_context.addAssertion(m_context.newValue(*decl) == smtutil::Expression::ite( _condition, @@ -1666,7 +1697,7 @@ smtutil::Expression SMTEncoder::currentValue(VariableDeclaration const& _decl) return m_context.variable(_decl)->currentValue(); } -smtutil::Expression SMTEncoder::valueAtIndex(VariableDeclaration const& _decl, int _index) +smtutil::Expression SMTEncoder::valueAtIndex(VariableDeclaration const& _decl, unsigned _index) { solAssert(m_context.knownVariable(_decl), ""); return m_context.variable(_decl)->valueAtIndex(_index); @@ -1789,7 +1820,7 @@ SMTEncoder::VariableIndices SMTEncoder::copyVariableIndices() void SMTEncoder::resetVariableIndices(VariableIndices const& _indices) { for (auto const& var: _indices) - m_context.variable(*var.first)->setIndex(var.second); + m_context.variable(*var.first)->setIndex(static_cast(var.second)); } void SMTEncoder::clearIndices(ContractDefinition const* _contract, FunctionDefinition const* _function) diff --git a/libsolidity/formal/SMTEncoder.h b/libsolidity/formal/SMTEncoder.h index 0e4c170fc78f..86ed21ef97d8 100644 --- a/libsolidity/formal/SMTEncoder.h +++ b/libsolidity/formal/SMTEncoder.h @@ -157,10 +157,12 @@ class SMTEncoder: public ASTConstVisitor /// Will also be used for assignments of tuple components. void assignment( Expression const& _left, - std::vector const& _right, + smtutil::Expression const& _right, TypePointer const& _type, langutil::SourceLocation const& _location ); + /// Handle assignments between tuples. + void tupleAssignment(Expression const& _left, Expression const& _right); /// Computes the right hand side of a compound assignment. smtutil::Expression compoundAssignment(Assignment const& _assignment); @@ -181,6 +183,9 @@ class SMTEncoder: public ASTConstVisitor void initializeLocalVariables(FunctionDefinition const& _function); void initializeFunctionCallParameters(CallableDeclaration const& _function, std::vector const& _callArgs); void resetStateVariables(); + /// Resets all references/pointers that have the same type or have + /// a subexpression of the same type as _varDecl. + void resetReferences(VariableDeclaration const& _varDecl); /// @returns the type without storage pointer information if it has it. TypePointer typeWithoutPointer(TypePointer const& _type); @@ -196,7 +201,7 @@ class SMTEncoder: public ASTConstVisitor smtutil::Expression currentValue(VariableDeclaration const& _decl); /// @returns an expression denoting the value of the variable declared in @a _decl /// at the given index. Does not ensure that this index exists. - smtutil::Expression valueAtIndex(VariableDeclaration const& _decl, int _index); + smtutil::Expression valueAtIndex(VariableDeclaration const& _decl, unsigned _index); /// Returns the expression corresponding to the AST node. /// If _targetType is not null apply conversion. /// Throws if the expression does not exist. diff --git a/libsolidity/formal/SymbolicVariables.cpp b/libsolidity/formal/SymbolicVariables.cpp index 002df600214f..3f86b48d901c 100644 --- a/libsolidity/formal/SymbolicVariables.cpp +++ b/libsolidity/formal/SymbolicVariables.cpp @@ -66,12 +66,12 @@ string SymbolicVariable::currentName() const return uniqueSymbol(m_ssa->index()); } -smtutil::Expression SymbolicVariable::valueAtIndex(int _index) const +smtutil::Expression SymbolicVariable::valueAtIndex(unsigned _index) const { return m_context.newVariable(uniqueSymbol(_index), m_sort); } -string SymbolicVariable::nameAtIndex(int _index) const +string SymbolicVariable::nameAtIndex(unsigned _index) const { return uniqueSymbol(_index); } @@ -170,12 +170,12 @@ smtutil::Expression SymbolicFunctionVariable::currentFunctionValue() const return m_declaration; } -smtutil::Expression SymbolicFunctionVariable::valueAtIndex(int _index) const +smtutil::Expression SymbolicFunctionVariable::valueAtIndex(unsigned _index) const { return m_abstract.valueAtIndex(_index); } -smtutil::Expression SymbolicFunctionVariable::functionValueAtIndex(int _index) const +smtutil::Expression SymbolicFunctionVariable::functionValueAtIndex(unsigned _index) const { return SymbolicVariable::valueAtIndex(_index); } @@ -304,7 +304,7 @@ smtutil::Expression SymbolicArrayVariable::currentValue(frontend::TypePointer co return m_pair.currentValue(); } -smtutil::Expression SymbolicArrayVariable::valueAtIndex(int _index) const +smtutil::Expression SymbolicArrayVariable::valueAtIndex(unsigned _index) const { return m_pair.valueAtIndex(_index); } diff --git a/libsolidity/formal/SymbolicVariables.h b/libsolidity/formal/SymbolicVariables.h index a7c0bd1702fc..65dce43f02f8 100644 --- a/libsolidity/formal/SymbolicVariables.h +++ b/libsolidity/formal/SymbolicVariables.h @@ -54,8 +54,8 @@ class SymbolicVariable virtual smtutil::Expression currentValue(frontend::TypePointer const& _targetType = TypePointer{}) const; std::string currentName() const; - virtual smtutil::Expression valueAtIndex(int _index) const; - virtual std::string nameAtIndex(int _index) const; + virtual smtutil::Expression valueAtIndex(unsigned _index) const; + virtual std::string nameAtIndex(unsigned _index) const; virtual smtutil::Expression resetIndex(); virtual smtutil::Expression setIndex(unsigned _index); virtual smtutil::Expression increaseIndex(); @@ -165,10 +165,10 @@ class SymbolicFunctionVariable: public SymbolicVariable // Explicit request the function declaration. smtutil::Expression currentFunctionValue() const; - smtutil::Expression valueAtIndex(int _index) const override; + smtutil::Expression valueAtIndex(unsigned _index) const override; // Explicit request the function declaration. - smtutil::Expression functionValueAtIndex(int _index) const; + smtutil::Expression functionValueAtIndex(unsigned _index) const; smtutil::Expression resetIndex() override; smtutil::Expression setIndex(unsigned _index) override; @@ -251,7 +251,7 @@ class SymbolicArrayVariable: public SymbolicVariable SymbolicArrayVariable(SymbolicArrayVariable&&) = default; smtutil::Expression currentValue(frontend::TypePointer const& _targetType = TypePointer{}) const override; - smtutil::Expression valueAtIndex(int _index) const override; + smtutil::Expression valueAtIndex(unsigned _index) const override; smtutil::Expression resetIndex() override { SymbolicVariable::resetIndex(); return m_pair.resetIndex(); } smtutil::Expression setIndex(unsigned _index) override { SymbolicVariable::setIndex(_index); return m_pair.setIndex(_index); } smtutil::Expression increaseIndex() override { SymbolicVariable::increaseIndex(); return m_pair.increaseIndex(); } diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index f662d361e70b..a8efdfb0b95e 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -982,7 +982,7 @@ string CompilerStack::applyRemapping(string const& _path, string const& _context bestMatchTarget = util::sanitizePath(redir.target); } string path = bestMatchTarget; - path.append(_path.begin() + longestPrefix, _path.end()); + path.append(_path.begin() + static_cast(longestPrefix), _path.end()); return path; } diff --git a/libsolidity/interface/GasEstimator.cpp b/libsolidity/interface/GasEstimator.cpp index 7282b15986b6..1a86f36ceef3 100644 --- a/libsolidity/interface/GasEstimator.cpp +++ b/libsolidity/interface/GasEstimator.cpp @@ -54,8 +54,8 @@ GasEstimator::ASTGasConsumptionSelfAccumulated GasEstimator::structuralEstimatio { solAssert(!!block.startState, ""); GasMeter meter(block.startState->copy(), m_evmVersion); - auto const end = _items.begin() + block.end; - for (auto iter = _items.begin() + block.begin; iter != end; ++iter) + auto const end = _items.begin() + static_cast(block.end); + for (auto iter = _items.begin() + static_cast(block.begin); iter != end; ++iter) particularCosts[iter->location()] += meter.estimateMax(*iter); } diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index e04b0b2f17a6..7293f94bc8fb 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -111,7 +111,8 @@ Json::Value formatErrorWithException( bool const& _warning, string const& _type, string const& _component, - string const& _message + string const& _message, + optional _errorId = nullopt ) { string message; @@ -122,7 +123,7 @@ Json::Value formatErrorWithException( else message = _message; - return formatError( + Json::Value error = formatError( _warning, _type, _component, @@ -131,6 +132,11 @@ Json::Value formatErrorWithException( formatSourceLocation(boost::get_error_info(_exception)), formatSecondarySourceLocation(boost::get_error_info(_exception)) ); + + if (_errorId) + error["errorCode"] = to_string(_errorId.value().error); + + return error; } map> requestedContractNames(Json::Value const& _outputSelection) @@ -857,7 +863,8 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting err.type() == Error::Type::Warning, err.typeName(), "general", - "" + "", + err.errorId() )); } } diff --git a/libsolidity/interface/StorageLayout.cpp b/libsolidity/interface/StorageLayout.cpp index 8e6915085dd2..806652cfe1b8 100644 --- a/libsolidity/interface/StorageLayout.cpp +++ b/libsolidity/interface/StorageLayout.cpp @@ -50,7 +50,7 @@ Json::Value StorageLayout::generate(VariableDeclaration const& _var, u256 const& TypePointer varType = _var.type(); varEntry["label"] = _var.name(); - varEntry["astId"] = int(_var.id()); + varEntry["astId"] = static_cast(_var.id()); varEntry["contract"] = m_contract->fullyQualifiedName(); varEntry["slot"] = _slot.str(); varEntry["offset"] = _offset; diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index 256d2ac387d2..eee3beacbb1c 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -359,6 +359,13 @@ void AsmAnalyzer::operator()(Switch const& _switch) { yulAssert(_switch.expression, ""); + if (_switch.cases.size() == 1 && !_switch.cases[0].value) + m_errorReporter.warning( + 9592_error, + _switch.location, + "\"switch\" statement with only a default case." + ); + YulString valueType = expectExpression(*_switch.expression); set cases; diff --git a/libyul/backends/wasm/BinaryTransform.cpp b/libyul/backends/wasm/BinaryTransform.cpp index 84e3650162e2..b305b9c550aa 100644 --- a/libyul/backends/wasm/BinaryTransform.cpp +++ b/libyul/backends/wasm/BinaryTransform.cpp @@ -22,8 +22,11 @@ #include #include +#include #include +#include +#include using namespace std; using namespace solidity; @@ -81,6 +84,16 @@ bytes toBytes(ValueType _vt) return toBytes(uint8_t(_vt)); } +ValueType toValueType(wasm::Type _type) +{ + if (_type == wasm::Type::i32) + return ValueType::I32; + else if (_type == wasm::Type::i64) + return ValueType::I64; + else + yulAssert(false, "Invalid wasm variable type"); +} + enum class Export: uint8_t { Function = 0x0, @@ -130,7 +143,17 @@ bytes toBytes(Opcode _o) return toBytes(uint8_t(_o)); } -static std::map const builtins = { +Opcode constOpcodeFor(ValueType _type) +{ + if (_type == ValueType::I32) + return Opcode::I32Const; + else if (_type == ValueType::I64) + return Opcode::I64Const; + else + yulAssert(false, "Values of this type cannot be used with const opcode"); +} + +static map const builtins = { {"i32.load", 0x28}, {"i64.load", 0x29}, {"i32.load8_s", 0x2c}, @@ -240,53 +263,94 @@ bytes lebEncodeSigned(int64_t _n) bytes prefixSize(bytes _data) { size_t size = _data.size(); - return lebEncode(size) + std::move(_data); + return lebEncode(size) + move(_data); } bytes makeSection(Section _section, bytes _data) { - return toBytes(_section) + prefixSize(std::move(_data)); + return toBytes(_section) + prefixSize(move(_data)); +} + +/// This is a kind of run-length-encoding of local types. +vector> groupLocalVariables(vector _localVariables) +{ + vector> localEntries; + + size_t entrySize = 0; + ValueType entryType = ValueType::I32; // Any type would work here + for (VariableDeclaration const& localVariable: _localVariables) + { + ValueType variableType = toValueType(localVariable.type); + + if (variableType != entryType) + { + if (entrySize > 0) + localEntries.emplace_back(entrySize, entryType); + + entryType = variableType; + entrySize = 0; + } + + ++entrySize; + } + if (entrySize > 0) + localEntries.emplace_back(entrySize, entryType); + + return localEntries; } } bytes BinaryTransform::run(Module const& _module) { - BinaryTransform bt; + map> const types = typeToFunctionMap(_module.imports, _module.functions); - for (size_t i = 0; i < _module.globals.size(); ++i) - bt.m_globals[_module.globals[i].variableName] = i; + map const globalIDs = enumerateGlobals(_module); + map const functionIDs = enumerateFunctions(_module); + map const functionTypes = enumerateFunctionTypes(types); - size_t funID = 0; - for (FunctionImport const& fun: _module.imports) - bt.m_functions[fun.internalName] = funID++; - for (FunctionDefinition const& fun: _module.functions) - bt.m_functions[fun.name] = funID++; + yulAssert(globalIDs.size() == _module.globals.size(), ""); + yulAssert(functionIDs.size() == _module.imports.size() + _module.functions.size(), ""); + yulAssert(functionTypes.size() == functionIDs.size(), ""); + yulAssert(functionTypes.size() >= types.size(), ""); bytes ret{0, 'a', 's', 'm'}; // version ret += bytes{1, 0, 0, 0}; - ret += bt.typeSection(_module.imports, _module.functions); - ret += bt.importSection(_module.imports); - ret += bt.functionSection(_module.functions); - ret += bt.memorySection(); - ret += bt.globalSection(); - ret += bt.exportSection(); + ret += typeSection(types); + ret += importSection(_module.imports, functionTypes); + ret += functionSection(_module.functions, functionTypes); + ret += memorySection(); + ret += globalSection(_module.globals); + ret += exportSection(functionIDs); + + map> subModulePosAndSize; for (auto const& sub: _module.subModules) { // TODO should we prefix and / or shorten the name? bytes data = BinaryTransform::run(sub.second); size_t length = data.size(); - ret += bt.customSection(sub.first, std::move(data)); - bt.m_subModulePosAndSize[sub.first] = {ret.size() - length, length}; + ret += customSection(sub.first, move(data)); + subModulePosAndSize[sub.first] = {ret.size() - length, length}; } + + BinaryTransform bt( + move(globalIDs), + move(functionIDs), + move(functionTypes), + move(subModulePosAndSize) + ); + ret += bt.codeSection(_module.functions); return ret; } bytes BinaryTransform::operator()(Literal const& _literal) { - return toBytes(Opcode::I64Const) + lebEncodeSigned(_literal.value); + return std::visit(GenericVisitor{ + [&](uint32_t _value) -> bytes { return toBytes(Opcode::I32Const) + lebEncodeSigned(static_cast(_value)); }, + [&](uint64_t _value) -> bytes { return toBytes(Opcode::I64Const) + lebEncodeSigned(static_cast(_value)); }, + }, _literal.value); } bytes BinaryTransform::operator()(StringLiteral const&) @@ -302,7 +366,7 @@ bytes BinaryTransform::operator()(LocalVariable const& _variable) bytes BinaryTransform::operator()(GlobalVariable const& _variable) { - return toBytes(Opcode::GlobalGet) + lebEncode(m_globals.at(_variable.name)); + return toBytes(Opcode::GlobalGet) + lebEncode(m_globalIDs.at(_variable.name)); } bytes BinaryTransform::operator()(BuiltinCall const& _call) @@ -311,12 +375,12 @@ bytes BinaryTransform::operator()(BuiltinCall const& _call) // they are references to object names that should not end up in the code. if (_call.functionName == "dataoffset") { - string name = std::get(_call.arguments.at(0)).value; + string name = get(_call.arguments.at(0)).value; return toBytes(Opcode::I64Const) + lebEncodeSigned(m_subModulePosAndSize.at(name).first); } else if (_call.functionName == "datasize") { - string name = std::get(_call.arguments.at(0)).value; + string name = get(_call.arguments.at(0)).value; return toBytes(Opcode::I64Const) + lebEncodeSigned(m_subModulePosAndSize.at(name).second); } @@ -331,20 +395,24 @@ bytes BinaryTransform::operator()(BuiltinCall const& _call) else { yulAssert(builtins.count(_call.functionName), "Builtin " + _call.functionName + " not found"); - bytes ret = std::move(args) + toBytes(builtins.at(_call.functionName)); + bytes ret = move(args) + toBytes(builtins.at(_call.functionName)); if ( _call.functionName.find(".load") != string::npos || _call.functionName.find(".store") != string::npos ) - // alignment and offset - ret += bytes{{3, 0}}; + // Alignment hint and offset. Interpreters ignore the alignment. JITs/AOTs can take it + // into account to generate more efficient code but if the hint is invalid it could + // actually be more expensive. It's best to hint at 1-byte alignment if we don't plan + // to control the memory layout accordingly. + ret += bytes{{0, 0}}; // 2^0 == 1-byte alignment + return ret; } } bytes BinaryTransform::operator()(FunctionCall const& _call) { - return visit(_call.arguments) + toBytes(Opcode::Call) + lebEncode(m_functions.at(_call.functionName)); + return visit(_call.arguments) + toBytes(Opcode::Call) + lebEncode(m_functionIDs.at(_call.functionName)); } bytes BinaryTransform::operator()(LocalAssignment const& _assignment) @@ -360,7 +428,7 @@ bytes BinaryTransform::operator()(GlobalAssignment const& _assignment) return std::visit(*this, *_assignment.value) + toBytes(Opcode::GlobalSet) + - lebEncode(m_globals.at(_assignment.variableName)); + lebEncode(m_globalIDs.at(_assignment.variableName)); } bytes BinaryTransform::operator()(If const& _if) @@ -428,16 +496,18 @@ bytes BinaryTransform::operator()(FunctionDefinition const& _function) { bytes ret; - // This is a kind of run-length-encoding of local types. Has to be adapted once - // we have locals of different types. - ret += lebEncode(1); // number of locals groups - ret += lebEncode(_function.locals.size()); - ret += toBytes(ValueType::I64); + vector> localEntries = groupLocalVariables(_function.locals); + ret += lebEncode(localEntries.size()); + for (pair const& entry: localEntries) + { + ret += lebEncode(entry.first); + ret += toBytes(entry.second); + } m_locals.clear(); size_t varIdx = 0; - for (size_t i = 0; i < _function.parameterNames.size(); ++i) - m_locals[_function.parameterNames[i]] = varIdx++; + for (size_t i = 0; i < _function.parameters.size(); ++i) + m_locals[_function.parameters[i].name] = varIdx++; for (size_t i = 0; i < _function.locals.size(); ++i) m_locals[_function.locals[i].variableName] = varIdx++; @@ -448,48 +518,49 @@ bytes BinaryTransform::operator()(FunctionDefinition const& _function) yulAssert(m_labels.empty(), "Stray labels."); - return prefixSize(std::move(ret)); + return prefixSize(move(ret)); } BinaryTransform::Type BinaryTransform::typeOf(FunctionImport const& _import) { return { encodeTypes(_import.paramTypes), - encodeTypes(_import.returnType ? vector(1, *_import.returnType) : vector()) + encodeTypes(_import.returnType ? vector(1, *_import.returnType) : vector()) }; } BinaryTransform::Type BinaryTransform::typeOf(FunctionDefinition const& _funDef) { - return { - encodeTypes(vector(_funDef.parameterNames.size(), "i64")), - encodeTypes(vector(_funDef.returns ? 1 : 0, "i64")) + encodeTypes(_funDef.parameters), + encodeTypes(_funDef.returnType ? vector(1, *_funDef.returnType) : vector()) }; } -uint8_t BinaryTransform::encodeType(string const& _typeName) +uint8_t BinaryTransform::encodeType(wasm::Type _type) { - if (_typeName == "i32") - return uint8_t(ValueType::I32); - else if (_typeName == "i64") - return uint8_t(ValueType::I64); - else - yulAssert(false, ""); - return 0; + return uint8_t(toValueType(_type)); } -vector BinaryTransform::encodeTypes(vector const& _typeNames) +vector BinaryTransform::encodeTypes(vector const& _types) { vector result; - for (auto const& t: _typeNames) + for (wasm::Type t: _types) result.emplace_back(encodeType(t)); return result; } -bytes BinaryTransform::typeSection( - vector const& _imports, - vector const& _functions +vector BinaryTransform::encodeTypes(wasm::TypedNameList const& _typedNameList) +{ + vector result; + for (TypedName const& typedName: _typedNameList) + result.emplace_back(encodeType(typedName.type)); + return result; +} + +map> BinaryTransform::typeToFunctionMap( + vector const& _imports, + vector const& _functions ) { map> types; @@ -498,12 +569,50 @@ bytes BinaryTransform::typeSection( for (auto const& fun: _functions) types[typeOf(fun)].emplace_back(fun.name); + return types; +} + +map BinaryTransform::enumerateGlobals(Module const& _module) +{ + map globals; + for (size_t i = 0; i < _module.globals.size(); ++i) + globals[_module.globals[i].variableName] = i; + + return globals; +} + +map BinaryTransform::enumerateFunctions(Module const& _module) +{ + map functions; + size_t funID = 0; + for (FunctionImport const& fun: _module.imports) + functions[fun.internalName] = funID++; + for (FunctionDefinition const& fun: _module.functions) + functions[fun.name] = funID++; + + return functions; +} + +map BinaryTransform::enumerateFunctionTypes(map> const& _typeToFunctionMap) +{ + map functionTypes; + size_t typeID = 0; + for (vector const& funNames: _typeToFunctionMap | boost::adaptors::map_values) + { + for (string const& name: funNames) + functionTypes[name] = typeID; + ++typeID; + } + + return functionTypes; +} + +bytes BinaryTransform::typeSection(map> const& _typeToFunctionMap) +{ bytes result; size_t index = 0; - for (auto const& [type, funNames]: types) + for (Type const& type: _typeToFunctionMap | boost::adaptors::map_keys) { - for (string const& name: funNames) - m_functionTypes[name] = index; result += toBytes(ValueType::Function); result += lebEncode(type.first.size()) + type.first; result += lebEncode(type.second.size()) + type.second; @@ -511,11 +620,12 @@ bytes BinaryTransform::typeSection( index++; } - return makeSection(Section::TYPE, lebEncode(index) + std::move(result)); + return makeSection(Section::TYPE, lebEncode(index) + move(result)); } bytes BinaryTransform::importSection( - vector const& _imports + vector const& _imports, + map const& _functionTypes ) { bytes result = lebEncode(_imports.size()); @@ -526,17 +636,20 @@ bytes BinaryTransform::importSection( encodeName(import.module) + encodeName(import.externalName) + toBytes(importKind) + - lebEncode(m_functionTypes[import.internalName]); + lebEncode(_functionTypes.at(import.internalName)); } - return makeSection(Section::IMPORT, std::move(result)); + return makeSection(Section::IMPORT, move(result)); } -bytes BinaryTransform::functionSection(vector const& _functions) +bytes BinaryTransform::functionSection( + vector const& _functions, + map const& _functionTypes +) { bytes result = lebEncode(_functions.size()); for (auto const& fun: _functions) - result += lebEncode(m_functionTypes.at(fun.name)); - return makeSection(Section::FUNCTION, std::move(result)); + result += lebEncode(_functionTypes.at(fun.name)); + return makeSection(Section::FUNCTION, move(result)); } bytes BinaryTransform::memorySection() @@ -544,35 +657,38 @@ bytes BinaryTransform::memorySection() bytes result = lebEncode(1); result.push_back(static_cast(LimitsKind::Min)); result.push_back(1); // initial length - return makeSection(Section::MEMORY, std::move(result)); + return makeSection(Section::MEMORY, move(result)); } -bytes BinaryTransform::globalSection() +bytes BinaryTransform::globalSection(vector const& _globals) { - bytes result = lebEncode(m_globals.size()); - for (size_t i = 0; i < m_globals.size(); ++i) + bytes result = lebEncode(_globals.size()); + for (wasm::GlobalVariableDeclaration const& global: _globals) + { + ValueType globalType = toValueType(global.type); result += - toBytes(ValueType::I64) + + toBytes(globalType) + lebEncode(static_cast(Mutability::Var)) + - toBytes(Opcode::I64Const) + + toBytes(constOpcodeFor(globalType)) + lebEncodeSigned(0) + toBytes(Opcode::End); + } - return makeSection(Section::GLOBAL, std::move(result)); + return makeSection(Section::GLOBAL, move(result)); } -bytes BinaryTransform::exportSection() +bytes BinaryTransform::exportSection(map const& _functionIDs) { bytes result = lebEncode(2); result += encodeName("memory") + toBytes(Export::Memory) + lebEncode(0); - result += encodeName("main") + toBytes(Export::Function) + lebEncode(m_functions.at("main")); - return makeSection(Section::EXPORT, std::move(result)); + result += encodeName("main") + toBytes(Export::Function) + lebEncode(_functionIDs.at("main")); + return makeSection(Section::EXPORT, move(result)); } bytes BinaryTransform::customSection(string const& _name, bytes _data) { - bytes result = encodeName(_name) + std::move(_data); - return makeSection(Section::CUSTOM, std::move(result)); + bytes result = encodeName(_name) + move(_data); + return makeSection(Section::CUSTOM, move(result)); } bytes BinaryTransform::codeSection(vector const& _functions) @@ -580,7 +696,7 @@ bytes BinaryTransform::codeSection(vector const& _func bytes result = lebEncode(_functions.size()); for (FunctionDefinition const& fun: _functions) result += (*this)(fun); - return makeSection(Section::CODE, std::move(result)); + return makeSection(Section::CODE, move(result)); } bytes BinaryTransform::visit(vector const& _expressions) @@ -611,7 +727,7 @@ bytes BinaryTransform::encodeLabelIdx(string const& _label) const yulAssert(false, "Label not found."); } -bytes BinaryTransform::encodeName(std::string const& _name) +bytes BinaryTransform::encodeName(string const& _name) { // UTF-8 is allowed here by the Wasm spec, but since all names here should stem from // Solidity or Yul identifiers or similar, non-ascii characters ending up here diff --git a/libyul/backends/wasm/BinaryTransform.h b/libyul/backends/wasm/BinaryTransform.h index c1c924dccb64..c505fe2dc1b5 100644 --- a/libyul/backends/wasm/BinaryTransform.h +++ b/libyul/backends/wasm/BinaryTransform.h @@ -55,23 +55,50 @@ class BinaryTransform bytes operator()(wasm::FunctionDefinition const& _function); private: + BinaryTransform( + std::map _globalIDs, + std::map _functionIDs, + std::map _functionTypes, + std::map> _subModulePosAndSize + ): + m_globalIDs(std::move(_globalIDs)), + m_functionIDs(std::move(_functionIDs)), + m_functionTypes(std::move(_functionTypes)), + m_subModulePosAndSize(std::move(_subModulePosAndSize)) + {} + using Type = std::pair, std::vector>; static Type typeOf(wasm::FunctionImport const& _import); static Type typeOf(wasm::FunctionDefinition const& _funDef); - static uint8_t encodeType(std::string const& _typeName); - static std::vector encodeTypes(std::vector const& _typeNames); - bytes typeSection( + static uint8_t encodeType(wasm::Type _type); + static std::vector encodeTypes(std::vector const& _types); + static std::vector encodeTypes(wasm::TypedNameList const& _typedNameList); + + static std::map> typeToFunctionMap( std::vector const& _imports, std::vector const& _functions ); - bytes importSection(std::vector const& _imports); - bytes functionSection(std::vector const& _functions); - bytes memorySection(); - bytes globalSection(); - bytes exportSection(); - bytes customSection(std::string const& _name, bytes _data); + static std::map enumerateGlobals(Module const& _module); + static std::map enumerateFunctions(Module const& _module); + static std::map enumerateFunctionTypes( + std::map> const& _typeToFunctionMap + ); + + static bytes typeSection(std::map> const& _typeToFunctionMap); + static bytes importSection( + std::vector const& _imports, + std::map const& _functionTypes + ); + static bytes functionSection( + std::vector const& _functions, + std::map const& _functionTypes + ); + static bytes memorySection(); + static bytes globalSection(std::vector const& _globals); + static bytes exportSection(std::map const& _functionIDs); + static bytes customSection(std::string const& _name, bytes _data); bytes codeSection(std::vector const& _functions); bytes visit(std::vector const& _expressions); @@ -81,12 +108,13 @@ class BinaryTransform static bytes encodeName(std::string const& _name); + std::map const m_globalIDs; + std::map const m_functionIDs; + std::map const m_functionTypes; + std::map> const m_subModulePosAndSize; + std::map m_locals; - std::map m_globals; - std::map m_functions; - std::map m_functionTypes; std::vector m_labels; - std::map> m_subModulePosAndSize; }; } diff --git a/libyul/backends/wasm/TextTransform.cpp b/libyul/backends/wasm/TextTransform.cpp index fd8eaf746772..b7f1e81ea512 100644 --- a/libyul/backends/wasm/TextTransform.cpp +++ b/libyul/backends/wasm/TextTransform.cpp @@ -20,7 +20,10 @@ #include +#include + #include +#include #include #include @@ -44,9 +47,9 @@ string TextTransform::run(wasm::Module const& _module) { ret += " (import \"" + imp.module + "\" \"" + imp.externalName + "\" (func $" + imp.internalName; if (!imp.paramTypes.empty()) - ret += " (param" + joinHumanReadablePrefixed(imp.paramTypes, " ", " ") + ")"; + ret += " (param" + joinHumanReadablePrefixed(imp.paramTypes | boost::adaptors::transformed(encodeType), " ", " ") + ")"; if (imp.returnType) - ret += " (result " + *imp.returnType + ")"; + ret += " (result " + encodeType(*imp.returnType) + ")"; ret += "))\n"; } @@ -56,7 +59,7 @@ string TextTransform::run(wasm::Module const& _module) ret += " (export \"main\" (func $main))\n"; for (auto const& g: _module.globals) - ret += " (global $" + g.variableName + " (mut i64) (i64.const 0))\n"; + ret += " (global $" + g.variableName + " (mut " + encodeType(g.type) + ") (" + encodeType(g.type) + ".const 0))\n"; ret += "\n"; for (auto const& f: _module.functions) ret += transform(f) + "\n"; @@ -65,7 +68,10 @@ string TextTransform::run(wasm::Module const& _module) string TextTransform::operator()(wasm::Literal const& _literal) { - return "(i64.const " + to_string(_literal.value) + ")"; + return std::visit(GenericVisitor{ + [&](uint32_t _value) -> string { return "(i32.const " + to_string(_value) + ")"; }, + [&](uint64_t _value) -> string { return "(i64.const " + to_string(_value) + ")"; }, + }, _literal.value); } string TextTransform::operator()(wasm::StringLiteral const& _literal) @@ -162,12 +168,12 @@ string TextTransform::indented(string const& _in) string TextTransform::transform(wasm::FunctionDefinition const& _function) { string ret = "(func $" + _function.name + "\n"; - for (auto const& param: _function.parameterNames) - ret += " (param $" + param + " i64)\n"; - if (_function.returns) - ret += " (result i64)\n"; + for (auto const& param: _function.parameters) + ret += " (param $" + param.name + " " + encodeType(param.type) + ")\n"; + if (_function.returnType.has_value()) + ret += " (result " + encodeType(_function.returnType.value()) + ")\n"; for (auto const& local: _function.locals) - ret += " (local $" + local.variableName + " i64)\n"; + ret += " (local $" + local.variableName + " " + encodeType(local.type) + ")\n"; ret += indented(joinTransformed(_function.body, '\n')); if (ret.back() != '\n') ret += '\n'; @@ -193,3 +199,13 @@ string TextTransform::joinTransformed(vector const& _expressio } return ret; } + +string TextTransform::encodeType(wasm::Type _type) +{ + if (_type == wasm::Type::i32) + return "i32"; + else if (_type == wasm::Type::i64) + return "i64"; + else + yulAssert(false, "Invalid wasm type"); +} diff --git a/libyul/backends/wasm/TextTransform.h b/libyul/backends/wasm/TextTransform.h index ebbca4e9e7e6..b8b21f7f2e6d 100644 --- a/libyul/backends/wasm/TextTransform.h +++ b/libyul/backends/wasm/TextTransform.h @@ -63,6 +63,8 @@ class TextTransform std::vector const& _expressions, char _separator = ' ' ); + + static std::string encodeType(wasm::Type _type); }; } diff --git a/libyul/backends/wasm/WasmAST.h b/libyul/backends/wasm/WasmAST.h index 7ba7066cbca2..b22b0db84430 100644 --- a/libyul/backends/wasm/WasmAST.h +++ b/libyul/backends/wasm/WasmAST.h @@ -30,6 +30,15 @@ namespace solidity::yul::wasm { +enum class Type +{ + i32, + i64, +}; + +struct TypedName { std::string name; Type type; }; +using TypedNameList = std::vector; + struct Literal; struct StringLiteral; struct LocalVariable; @@ -50,7 +59,7 @@ using Expression = std::variant< Block, If, Loop, Branch, BranchIf, Return >; -struct Literal { uint64_t value; }; +struct Literal { std::variant value; }; struct StringLiteral { std::string value; }; struct LocalVariable { std::string name; }; struct GlobalVariable { std::string name; }; @@ -70,21 +79,21 @@ struct Branch { Label label; }; struct Return {}; struct BranchIf { Label label; std::unique_ptr condition; }; -struct VariableDeclaration { std::string variableName; }; -struct GlobalVariableDeclaration { std::string variableName; }; +struct VariableDeclaration { std::string variableName; Type type; }; +struct GlobalVariableDeclaration { std::string variableName; Type type; }; struct FunctionImport { std::string module; std::string externalName; std::string internalName; - std::vector paramTypes; - std::optional returnType; + std::vector paramTypes; + std::optional returnType; }; struct FunctionDefinition { std::string name; - std::vector parameterNames; - bool returns; + std::vector parameters; + std::optional returnType; std::vector locals; std::vector body; }; diff --git a/libyul/backends/wasm/WasmCodeTransform.cpp b/libyul/backends/wasm/WasmCodeTransform.cpp index f23f51eee92f..8f987824c3d1 100644 --- a/libyul/backends/wasm/WasmCodeTransform.cpp +++ b/libyul/backends/wasm/WasmCodeTransform.cpp @@ -88,7 +88,7 @@ wasm::Expression WasmCodeTransform::operator()(VariableDeclaration const& _varDe for (auto const& var: _varDecl.variables) { variableNames.emplace_back(var.name.str()); - m_localVariables.emplace_back(wasm::VariableDeclaration{variableNames.back()}); + m_localVariables.emplace_back(wasm::VariableDeclaration{variableNames.back(), wasm::Type::i64}); } if (_varDecl.value) @@ -127,10 +127,10 @@ wasm::Expression WasmCodeTransform::operator()(FunctionCall const& _call) builtin->name.str().substr(4), builtin->name.str(), {}, - builtin->returns.empty() ? nullopt : make_optional(builtin->returns.front().str()) + builtin->returns.empty() ? nullopt : make_optional(translatedType(builtin->returns.front())) }; for (auto const& param: builtin->parameters) - imp.paramTypes.emplace_back(param.str()); + imp.paramTypes.emplace_back(translatedType(param)); m_functionsToImport[builtin->name] = std::move(imp); } typeConversionNeeded = true; @@ -184,7 +184,7 @@ wasm::Expression WasmCodeTransform::operator()(Literal const& _literal) { u256 value = valueOfLiteral(_literal); yulAssert(value <= numeric_limits::max(), "Literal too large: " + value.str()); - return wasm::Literal{uint64_t(value)}; + return wasm::Literal{static_cast(value)}; } wasm::Expression WasmCodeTransform::operator()(If const& _if) @@ -193,7 +193,7 @@ wasm::Expression WasmCodeTransform::operator()(If const& _if) vector args; args.emplace_back(visitReturnByValue(*_if.condition)); - args.emplace_back(wasm::Literal{0}); + args.emplace_back(wasm::Literal{static_cast(0)}); return wasm::If{ make_unique(wasm::BuiltinCall{"i64.ne", std::move(args)}), visit(_if.body.statements), @@ -205,7 +205,7 @@ wasm::Expression WasmCodeTransform::operator()(Switch const& _switch) { wasm::Block block; string condition = m_nameDispenser.newName("condition"_yulstring).str(); - m_localVariables.emplace_back(wasm::VariableDeclaration{condition}); + m_localVariables.emplace_back(wasm::VariableDeclaration{condition, wasm::Type::i64}); block.statements.emplace_back(wasm::LocalAssignment{condition, visit(*_switch.expression)}); vector* currentBlock = &block.statements; @@ -325,10 +325,11 @@ wasm::FunctionDefinition WasmCodeTransform::translateFunction(yul::FunctionDefin wasm::FunctionDefinition fun; fun.name = _fun.name.str(); for (auto const& param: _fun.parameters) - fun.parameterNames.emplace_back(param.name.str()); + fun.parameters.push_back({param.name.str(), wasm::Type::i64}); for (auto const& retParam: _fun.returnVariables) - fun.locals.emplace_back(wasm::VariableDeclaration{retParam.name.str()}); - fun.returns = !_fun.returnVariables.empty(); + fun.locals.emplace_back(wasm::VariableDeclaration{retParam.name.str(), wasm::Type::i64}); + if (!_fun.returnVariables.empty()) + fun.returnType = wasm::Type::i64; yulAssert(m_localVariables.empty(), ""); yulAssert(m_functionBodyLabel.empty(), ""); @@ -361,14 +362,14 @@ wasm::Expression WasmCodeTransform::injectTypeConversionIfNeeded(wasm::FunctionC { wasm::FunctionImport const& import = m_functionsToImport.at(YulString{_call.functionName}); for (size_t i = 0; i < _call.arguments.size(); ++i) - if (import.paramTypes.at(i) == "i32") + if (import.paramTypes.at(i) == wasm::Type::i32) _call.arguments[i] = wasm::BuiltinCall{"i32.wrap_i64", make_vector(std::move(_call.arguments[i]))}; else - yulAssert(import.paramTypes.at(i) == "i64", "Unknown type " + import.paramTypes.at(i)); + yulAssert(import.paramTypes.at(i) == wasm::Type::i64, "Invalid Wasm type"); - if (import.returnType && *import.returnType != "i64") + if (import.returnType && *import.returnType != wasm::Type::i64) { - yulAssert(*import.returnType == "i32", "Invalid type " + *import.returnType); + yulAssert(*import.returnType == wasm::Type::i32, "Invalid Wasm type"); return wasm::BuiltinCall{"i64.extend_i32_u", make_vector(std::move(_call))}; } return {std::move(_call)}; @@ -400,6 +401,17 @@ void WasmCodeTransform::allocateGlobals(size_t _amount) { while (m_globalVariables.size() < _amount) m_globalVariables.emplace_back(wasm::GlobalVariableDeclaration{ - m_nameDispenser.newName("global_"_yulstring).str() + m_nameDispenser.newName("global_"_yulstring).str(), + wasm::Type::i64 }); } + +wasm::Type WasmCodeTransform::translatedType(yul::Type _yulType) +{ + if (_yulType == "i32"_yulstring) + return wasm::Type::i32; + else if (_yulType == "i64"_yulstring) + return wasm::Type::i64; + else + yulAssert(false, "This Yul type does not have a corresponding type in Wasm."); +} diff --git a/libyul/backends/wasm/WasmCodeTransform.h b/libyul/backends/wasm/WasmCodeTransform.h index 26000e3852ab..5680269f4c54 100644 --- a/libyul/backends/wasm/WasmCodeTransform.h +++ b/libyul/backends/wasm/WasmCodeTransform.h @@ -89,6 +89,8 @@ class WasmCodeTransform /// Makes sure that there are at least @a _amount global variables. void allocateGlobals(size_t _amount); + static wasm::Type translatedType(yul::Type _yulType); + Dialect const& m_dialect; NameDispenser m_nameDispenser; diff --git a/libyul/optimiser/VarNameCleaner.cpp b/libyul/optimiser/VarNameCleaner.cpp index 2d7cae6c6619..f9b9e7899048 100644 --- a/libyul/optimiser/VarNameCleaner.cpp +++ b/libyul/optimiser/VarNameCleaner.cpp @@ -33,16 +33,16 @@ using namespace solidity::yul; VarNameCleaner::VarNameCleaner( Block const& _ast, Dialect const& _dialect, - set _blacklist + set _namesToKeep ): m_dialect{_dialect}, - m_blacklist{std::move(_blacklist)}, + m_namesToKeep{std::move(_namesToKeep)}, m_translatedNames{} { for (auto const& statement: _ast.statements) if (holds_alternative(statement)) - m_blacklist.insert(std::get(statement).name); - m_usedNames = m_blacklist; + m_namesToKeep.insert(std::get(statement).name); + m_usedNames = m_namesToKeep; } void VarNameCleaner::operator()(FunctionDefinition& _funDef) @@ -51,7 +51,7 @@ void VarNameCleaner::operator()(FunctionDefinition& _funDef) m_insideFunction = true; set globalUsedNames = std::move(m_usedNames); - m_usedNames = m_blacklist; + m_usedNames = m_namesToKeep; map globalTranslatedNames; swap(globalTranslatedNames, m_translatedNames); diff --git a/libyul/optimiser/VarNameCleaner.h b/libyul/optimiser/VarNameCleaner.h index 4bd4ca100e0a..911f67ca66e4 100644 --- a/libyul/optimiser/VarNameCleaner.h +++ b/libyul/optimiser/VarNameCleaner.h @@ -63,7 +63,7 @@ class VarNameCleaner: public ASTModifier VarNameCleaner( Block const& _ast, Dialect const& _dialect, - std::set _blacklist = {} + std::set _namesToKeep = {} ); /// Tries to rename a list of variables. @@ -77,11 +77,13 @@ class VarNameCleaner: public ASTModifier YulString findCleanName(YulString const& name) const; /// Tests whether a given name was already used within this pass - /// or is on the blacklist. + /// or was set to be kept. bool isUsedName(YulString const& _name) const; Dialect const& m_dialect; - std::set m_blacklist; + + /// These names will not be modified. + std::set m_namesToKeep; /// Set of names that are in use. std::set m_usedNames; diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 44be43539325..8b6117a2d38a 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -177,6 +177,7 @@ static string const g_strVersion = "version"; static string const g_strIgnoreMissingFiles = "ignore-missing"; static string const g_strColor = "color"; static string const g_strNoColor = "no-color"; +static string const g_strErrorIds = "error-codes"; static string const g_strOldReporter = "old-reporter"; static string const g_argAbi = g_strAbi; @@ -222,6 +223,7 @@ static string const g_stdinFileName = g_stdinFileNameStr; static string const g_argIgnoreMissingFiles = g_strIgnoreMissingFiles; static string const g_argColor = g_strColor; static string const g_argNoColor = g_strNoColor; +static string const g_argErrorIds = g_strErrorIds; static string const g_argOldReporter = g_strOldReporter; /// Possible arguments to for --combined-json @@ -738,7 +740,7 @@ remap paths using the context:prefix=path syntax. Example: solc --)" + g_argBinary + R"( -o /tmp/solcoutput dapp-bin=/usr/local/lib/dapp-bin contract.sol -Allowed options)").c_str(), +General Information)").c_str(), po::options_description::m_default_line_length, po::options_description::m_default_line_length - 23 ); @@ -746,47 +748,67 @@ Allowed options)").c_str(), (g_argHelp.c_str(), "Show help message and exit.") (g_argVersion.c_str(), "Show version and exit.") (g_strLicense.c_str(), "Show licensing information and exit.") + ; + + po::options_description inputOptions("Input Options"); + inputOptions.add_options() ( - g_strEVMVersion.c_str(), - po::value()->value_name("version"), - "Select desired EVM version. Either homestead, tangerineWhistle, spuriousDragon, " - "byzantium, constantinople, petersburg, istanbul (default) or berlin." + g_argBasePath.c_str(), + po::value()->value_name("path"), + "Use the given path as the root of the source tree instead of the root of the filesystem." ) - (g_argPrettyJson.c_str(), "Output JSON in pretty format. Currently it only works with the combined JSON output.") ( - g_argLibraries.c_str(), - po::value>()->value_name("libs"), - "Direct string or file containing library addresses. Syntax: " - ":
[, or whitespace] ...\n" - "Address is interpreted as a hex string optionally prefixed by 0x." + g_argAllowPaths.c_str(), + po::value()->value_name("path(s)"), + "Allow a given path for imports. A list of paths can be supplied by separating them with a comma." ) ( - g_strRevertStrings.c_str(), - po::value()->value_name(boost::join(g_revertStringsArgs, ",")), - "Strip revert (and require) reason strings or add additional debugging information." + g_argIgnoreMissingFiles.c_str(), + "Ignore missing files." + ) + ( + g_argErrorRecovery.c_str(), + "Enables additional parser error recovery." ) + ; + desc.add(inputOptions); + + po::options_description outputOptions("Output Options"); + outputOptions.add_options() ( (g_argOutputDir + ",o").c_str(), po::value()->value_name("path"), "If given, creates one file per component and contract/file at the specified directory." ) - (g_strOverwrite.c_str(), "Overwrite existing files (used together with -o).") ( - g_argCombinedJson.c_str(), - po::value()->value_name(boost::join(g_combinedJsonArgs, ",")), - "Output a single json document containing the specified information." + g_strOverwrite.c_str(), + "Overwrite existing files (used together with -o)." + ) + ( + g_strEVMVersion.c_str(), + po::value()->value_name("version"), + "Select desired EVM version. Either homestead, tangerineWhistle, spuriousDragon, " + "byzantium, constantinople, petersburg, istanbul (default) or berlin." ) - (g_argGas.c_str(), "Print an estimate of the maximal gas usage for each function.") + ( + g_strRevertStrings.c_str(), + po::value()->value_name(boost::join(g_revertStringsArgs, ",")), + "Strip revert (and require) reason strings or add additional debugging information." + ) + ; + desc.add(outputOptions); + + po::options_description alternativeInputModes("Alternative Input Modes"); + alternativeInputModes.add_options() ( g_argStandardJSON.c_str(), "Switch to Standard JSON input / output mode, ignoring all options. " "It reads from standard input, if no input file was given, otherwise it reads from the provided input file. The result will be written to standard output." ) ( - g_argImportAst.c_str(), - ("Import ASTs to be compiled, assumes input holds the AST in compact JSON format. " - "Supported Inputs is the output of the --" + g_argStandardJSON + " or the one produced by " - "--" + g_argCombinedJson + " " + g_strAst + "," + g_strCompactJSON).c_str() + g_argLink.c_str(), + ("Switch to linker mode, ignoring all options apart from --" + g_argLibraries + " " + "and modify binaries in place.").c_str() ) ( g_argAssemble.c_str(), @@ -807,58 +829,66 @@ Allowed options)").c_str(), "and assumes input is strict assembly.").c_str() ) ( - g_strYulDialect.c_str(), - po::value()->value_name(boost::join(g_yulDialectArgs, ",")), - "Input dialect to use in assembly or yul mode." + g_argImportAst.c_str(), + ("Import ASTs to be compiled, assumes input holds the AST in compact JSON format. " + "Supported Inputs is the output of the --" + g_argStandardJSON + " or the one produced by " + "--" + g_argCombinedJson + " " + g_strAst + "," + g_strCompactJSON).c_str() ) + ; + desc.add(alternativeInputModes); + + po::options_description assemblyModeOptions("Assembly Mode Options"); + assemblyModeOptions.add_options() ( g_argMachine.c_str(), po::value()->value_name(boost::join(g_machineArgs, ",")), "Target machine in assembly or Yul mode." ) ( - g_argLink.c_str(), - ("Switch to linker mode, ignoring all options apart from --" + g_argLibraries + " " - "and modify binaries in place.").c_str() + g_strYulDialect.c_str(), + po::value()->value_name(boost::join(g_yulDialectArgs, ",")), + "Input dialect to use in assembly or yul mode." ) + ; + desc.add(assemblyModeOptions); + + po::options_description linkerModeOptions("Linker Mode Options"); + linkerModeOptions.add_options() ( - g_argMetadataHash.c_str(), - po::value()->value_name(boost::join(g_metadataHashArgs, ",")), - "Choose hash method for the bytecode metadata or disable it." + g_argLibraries.c_str(), + po::value>()->value_name("libs"), + "Direct string or file containing library addresses. Syntax: " + ":
[, or whitespace] ...\n" + "Address is interpreted as a hex string optionally prefixed by 0x." ) - (g_argMetadataLiteral.c_str(), "Store referenced sources as literal data in the metadata output.") + ; + desc.add(linkerModeOptions); + + po::options_description outputFormatting("Output Formatting"); + outputFormatting.add_options() ( - g_argAllowPaths.c_str(), - po::value()->value_name("path(s)"), - "Allow a given path for imports. A list of paths can be supplied by separating them with a comma." + g_argPrettyJson.c_str(), + "Output JSON in pretty format. Currently it only works with the combined JSON output." ) ( - g_argBasePath.c_str(), - po::value()->value_name("path"), - "Use the given path as the root of the source tree instead of the root of the filesystem." + g_argColor.c_str(), + "Force colored output." ) - (g_argColor.c_str(), "Force colored output.") - (g_argNoColor.c_str(), "Explicitly disable colored output, disabling terminal auto-detection.") - (g_argOldReporter.c_str(), "Enables old diagnostics reporter.") - (g_argErrorRecovery.c_str(), "Enables additional parser error recovery.") - (g_argIgnoreMissingFiles.c_str(), "Ignore missing files."); - po::options_description optimizerOptions("Optimizer options"); - optimizerOptions.add_options() - (g_argOptimize.c_str(), "Enable bytecode optimizer.") ( - g_argOptimizeRuns.c_str(), - po::value()->value_name("n")->default_value(200), - "Set for how many contract runs to optimize. " - "Lower values will optimize more for initial deployment cost, higher values will optimize more for high-frequency usage." + g_argNoColor.c_str(), + "Explicitly disable colored output, disabling terminal auto-detection." ) - (g_strOptimizeYul.c_str(), ("Legacy option, ignored. Use the general --" + g_argOptimize + " to enable Yul optimizer.").c_str()) - (g_strNoOptimizeYul.c_str(), "Disable Yul optimizer in Solidity.") ( - g_strYulOptimizations.c_str(), - po::value()->value_name("steps"), - "Forces yul optimizer to use the specified sequence of optimization steps instead of the built-in one." - ); - desc.add(optimizerOptions); + g_argErrorIds.c_str(), + "Output error codes." + ) + ( + g_argOldReporter.c_str(), + "Enables old diagnostics reporter (legacy option, will be removed)." + ) + ; + desc.add(outputFormatting); + po::options_description outputComponents("Output Components"); outputComponents.add_options() (g_argAstJson.c_str(), "AST of all source files in JSON format.") @@ -876,9 +906,66 @@ Allowed options)").c_str(), (g_argNatspecUser.c_str(), "Natspec user documentation of all contracts.") (g_argNatspecDev.c_str(), "Natspec developer documentation of all contracts.") (g_argMetadata.c_str(), "Combined Metadata JSON whose Swarm hash is stored on-chain.") - (g_argStorageLayout.c_str(), "Slots, offsets and types of the contract's state variables."); + (g_argStorageLayout.c_str(), "Slots, offsets and types of the contract's state variables.") + ; desc.add(outputComponents); + po::options_description extraOutput("Extra Output"); + extraOutput.add_options() + ( + g_argGas.c_str(), + "Print an estimate of the maximal gas usage for each function." + ) + ( + g_argCombinedJson.c_str(), + po::value()->value_name(boost::join(g_combinedJsonArgs, ",")), + "Output a single json document containing the specified information." + ) + ; + desc.add(extraOutput); + + po::options_description metadataOptions("Metadata Options"); + metadataOptions.add_options() + ( + g_argMetadataHash.c_str(), + po::value()->value_name(boost::join(g_metadataHashArgs, ",")), + "Choose hash method for the bytecode metadata or disable it." + ) + ( + g_argMetadataLiteral.c_str(), + "Store referenced sources as literal data in the metadata output." + ) + ; + desc.add(metadataOptions); + + po::options_description optimizerOptions("Optimizer Options"); + optimizerOptions.add_options() + ( + g_argOptimize.c_str(), + "Enable bytecode optimizer." + ) + ( + g_argOptimizeRuns.c_str(), + po::value()->value_name("n")->default_value(200), + "Set for how many contract runs to optimize. " + "Lower values will optimize more for initial deployment cost, higher values will optimize more for high-frequency usage." + ) + ( + g_strOptimizeYul.c_str(), + ("Legacy option, ignored. Use the general --" + g_argOptimize + " to enable Yul optimizer.").c_str() + ) + ( + g_strNoOptimizeYul.c_str(), + "Disable Yul optimizer in Solidity." + ) + ( + g_strYulOptimizations.c_str(), + po::value()->value_name("steps"), + "Forces yul optimizer to use the specified sequence of optimization steps instead of the built-in one." + ) + ; + desc.add(optimizerOptions); + po::options_description allOptions = desc; allOptions.add_options()(g_argInputFile.c_str(), po::value>(), "input file"); @@ -908,6 +995,8 @@ Allowed options)").c_str(), m_coloredOutput = !m_args.count(g_argNoColor) && (isatty(STDERR_FILENO) || m_args.count(g_argColor)); + m_withErrorIds = m_args.count(g_argErrorIds); + if (m_args.count(g_argHelp) || (isatty(fileno(stdin)) && _argc == 1)) { sout() << desc; @@ -1213,7 +1302,7 @@ bool CommandLineInterface::processInput() if (m_args.count(g_argOldReporter)) formatter = make_unique(serr(false)); else - formatter = make_unique(serr(false), m_coloredOutput); + formatter = make_unique(serr(false), m_coloredOutput, m_withErrorIds); try { @@ -1651,7 +1740,7 @@ bool CommandLineInterface::assemble( if (m_args.count(g_argOldReporter)) formatter = make_unique(serr(false)); else - formatter = make_unique(serr(false), m_coloredOutput); + formatter = make_unique(serr(false), m_coloredOutput, m_withErrorIds); for (auto const& error: stack.errors()) { diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index 00b9181ec069..2c871a670e8a 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -131,6 +131,8 @@ class CommandLineInterface CompilerStack::MetadataHash m_metadataHash = CompilerStack::MetadataHash::IPFS; /// Whether or not to colorize diagnostics output. bool m_coloredOutput = true; + /// Whether or not to output error IDs. + bool m_withErrorIds = false; }; } diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index 07e249492c3e..448ba5a6e5ef 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -121,6 +121,7 @@ function test_solc_behaviour() rm "$stdout_path.bak" else sed -i.bak -e '/^Warning: This is a pre-release compiler version, please do not use it in production./d' "$stderr_path" + sed -i.bak -e '/^Warning (3805): This is a pre-release compiler version, please do not use it in production./d' "$stderr_path" sed -i.bak -e 's/\(^[ ]*auxdata: \)0x[0-9a-f]*$/\1AUXDATA REMOVED/' "$stdout_path" sed -i.bak -e 's/ Consider adding "pragma .*$//' "$stderr_path" # Remove trailing empty lines. Needs a line break to make OSX sed happy. diff --git a/test/cmdlineTests/error_codes/args b/test/cmdlineTests/error_codes/args new file mode 100644 index 000000000000..330f811c7ac6 --- /dev/null +++ b/test/cmdlineTests/error_codes/args @@ -0,0 +1 @@ +--error-codes diff --git a/test/cmdlineTests/error_codes/err b/test/cmdlineTests/error_codes/err new file mode 100644 index 000000000000..1d983a7fd19e --- /dev/null +++ b/test/cmdlineTests/error_codes/err @@ -0,0 +1,26 @@ +Error (4937): No visibility specified. Did you intend to add "public"? + --> error_codes/input.sol:4:5: + | +4 | function f() { + | ^ (Relevant source part starts here and spans across multiple lines). + +Warning (3420): Source file does not specify required compiler version! +--> error_codes/input.sol + +Error (4247): Expression has to be an lvalue. + --> error_codes/input.sol:5:9: + | +5 | 2=0; + | ^ + +Error (7407): Type int_const 0 is not implicitly convertible to expected type int_const 2. + --> error_codes/input.sol:5:11: + | +5 | 2=0; + | ^ + +Error (2614): Indexed expression has to be a type, mapping or array (is literal_string "") + --> error_codes/input.sol:6:9: + | +6 | ""[2]; + | ^^ diff --git a/test/cmdlineTests/error_codes/exit b/test/cmdlineTests/error_codes/exit new file mode 100644 index 000000000000..d00491fd7e5b --- /dev/null +++ b/test/cmdlineTests/error_codes/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/error_codes/input.sol b/test/cmdlineTests/error_codes/input.sol new file mode 100644 index 000000000000..78aceb41f1e3 --- /dev/null +++ b/test/cmdlineTests/error_codes/input.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-3.0 + +contract C { + function f() { + 2=0; + ""[2]; + } +} diff --git a/test/cmdlineTests/evm_to_wasm/output b/test/cmdlineTests/evm_to_wasm/output index 31b982d0dba6..7e8bd21cc4b7 100644 --- a/test/cmdlineTests/evm_to_wasm/output +++ b/test/cmdlineTests/evm_to_wasm/output @@ -45,7 +45,7 @@ object "object" { Binary representation: -0061736d0100000001160460000060017e017e60057e7e7e7e7e0060027f7f0002190108657468657265756d0c73746f7261676553746f7265000303060500010101020503010001060100071102066d656d6f72790200046d61696e00010acd01052b01017e0240420021004200200020002000200010054220200020002000420110054200a74220a710000b0b1f01017e024020004208864280fe0383200042088842ff01838421010b20010b1e01027e02402000100242108621022002200042108810028421010b20010b1e01027e02402000100342208621022002200042208810038421010b20010b4101007e02402000a7200110043703002000a74208a76aada7200210043703002000a74210a76aada7200310043703002000a74218a76aada7200410043703000b0b +0061736d0100000001160460000060017e017e60057e7e7e7e7e0060027f7f0002190108657468657265756d0c73746f7261676553746f7265000303060500010101020503010001060100071102066d656d6f72790200046d61696e00010acb01052b01017e0240420021004200200020002000200010054220200020002000420110054200a74220a710000b0b1f01017e024020004208864280fe0383200042088842ff01838421010b20010b1e01027e02402000100242108621022002200042108810028421010b20010b1e01027e02402000100342208621022002200042208810038421010b20010b3f0002402000a7200110043700002000a74208a76aada7200210043700002000a74210a76aada7200310043700002000a74218a76aada7200410043700000b0b Text representation: (module diff --git a/test/cmdlineTests/evm_to_wasm_break/output b/test/cmdlineTests/evm_to_wasm_break/output index 2325fa737083..4d5e10921121 100644 --- a/test/cmdlineTests/evm_to_wasm_break/output +++ b/test/cmdlineTests/evm_to_wasm_break/output @@ -154,7 +154,7 @@ object "object" { Binary representation: -0061736d0100000001480a60000060017e017e60027e7e017e60037e7e7e017e60047e7e7e7e017e60057e7e7e7e7e0060087e7e7e7e7e7e7e7e0060087e7e7e7e7e7e7e7e017e60027f7f0060037f7f7f0002310208657468657265756d0c73746f7261676553746f7265000808657468657265756d0c63616c6c44617461436f70790009030e0d0003070407020704010101050605030100010610037e0142000b7e0142000b7e0142000b071102066d656d6f72790200046d61696e00020aa9090df302011f7e02404200210002402000200020002000100921012300210223012103230221040b2001210520022106200321072004210842012109200020008420002009848450ada745ada745ad210a02400340200aa745ad500d01024002402005200620072008200020002000420a1008210b2300210c2301210d2302210e0b0240200b200c200d200e1005210f2300211023012111230221120b200f20108420112012848450ada745ad42005204400c030b024020052006200720082000200020004202100621132300211423012115230221160b201320148420152016848450ada745ad42005204400c030b0240200520062007200820002000200042041006211723002118230121192302211a0b20172018842019201a848450ada745ad42005204400c010b0b0240200520062007200820002000200020091004211b2300211c2301211d2302211e0b201b2105201c2106201d2107201e21080c000b0b20002000200020002005200620072008100e0b0b2f01037e0240200020017c2105200520027c21032005200054ada72003200554ada772ada7ad21040b2004240020030b72010b7e0240200320077c210c200c42007c210b024020022006200c200354ada7200b200c54ada772ada7ad1003210d2300210e0b200d210a024020012005200e1003210f230021100b200f2109024020002004201010032111230021120b201121080b20092400200a2401200b240220080b2601047e0240200020018420022003848450ada7ad21070b20052400200624012007240220040b4901047e02402000200451ad42005204402001200551ad42005204402002200651ad42005204402003200751ad42005204404201210b0b0b0b0b0b20092400200a2401200b240220080b2d01027e024002402000200154ad21032003420151044042ffffffff0f2102052000200152ad21020b0b0b20020b960101087e02404200210c0240200020041007210d200d42005104400240200120051007210e200e42005104400240200220061007210f200f42005104402003200754ad210c05200f42015104404200210c054201210c0b0b0b05200e42015104404200210c054201210c0b0b0b05200d42015104404200210c054201210c0b0b0b200ca7ad210b0b20092400200a2401200b240220080b8f0101087e02404200200020018420028452ad4200520440000b4200200342208852ad4200520440000b4200a72003a7ada74220a710014200a7290300100c21084200a74208a76aada7290300100c21094200a74210a76aada7290300100c210a4200a74218a76aada7290300100c210b2008210420092105200a2106200b21070b20052400200624012007240220040b1f01017e024020004208864280fe0383200042088842ff01838421010b20010b1e01027e02402000100a421086210220022000421088100a8421010b20010b1e01027e02402000100b422086210220022000422088100b8421010b20010b4101007e02402000a72001100c3703002000a74208a76aada72002100c3703002000a74210a76aada72003100c3703002000a74218a76aada72004100c3703000b0b2701007e024042002000200120022003100d42202004200520062007100d4200a74220a710000b0b +0061736d0100000001480a60000060017e017e60027e7e017e60037e7e7e017e60047e7e7e7e017e60057e7e7e7e7e0060087e7e7e7e7e7e7e7e0060087e7e7e7e7e7e7e7e017e60027f7f0060037f7f7f0002310208657468657265756d0c73746f7261676553746f7265000808657468657265756d0c63616c6c44617461436f70790009030e0d0003070407020704010101050605030100010610037e0142000b7e0142000b7e0142000b071102066d656d6f72790200046d61696e00020aa5090df302011f7e02404200210002402000200020002000100921012300210223012103230221040b2001210520022106200321072004210842012109200020008420002009848450ada745ada745ad210a02400340200aa745ad500d01024002402005200620072008200020002000420a1008210b2300210c2301210d2302210e0b0240200b200c200d200e1005210f2300211023012111230221120b200f20108420112012848450ada745ad42005204400c030b024020052006200720082000200020004202100621132300211423012115230221160b201320148420152016848450ada745ad42005204400c030b0240200520062007200820002000200042041006211723002118230121192302211a0b20172018842019201a848450ada745ad42005204400c010b0b0240200520062007200820002000200020091004211b2300211c2301211d2302211e0b201b2105201c2106201d2107201e21080c000b0b20002000200020002005200620072008100e0b0b2f01037e0240200020017c2105200520027c21032005200054ada72003200554ada772ada7ad21040b2004240020030b72010b7e0240200320077c210c200c42007c210b024020022006200c200354ada7200b200c54ada772ada7ad1003210d2300210e0b200d210a024020012005200e1003210f230021100b200f2109024020002004201010032111230021120b201121080b20092400200a2401200b240220080b2601047e0240200020018420022003848450ada7ad21070b20052400200624012007240220040b4901047e02402000200451ad42005204402001200551ad42005204402002200651ad42005204402003200751ad42005204404201210b0b0b0b0b0b20092400200a2401200b240220080b2d01027e024002402000200154ad21032003420151044042ffffffff0f2102052000200152ad21020b0b0b20020b960101087e02404200210c0240200020041007210d200d42005104400240200120051007210e200e42005104400240200220061007210f200f42005104402003200754ad210c05200f42015104404200210c054201210c0b0b0b05200e42015104404200210c054201210c0b0b0b05200d42015104404200210c054201210c0b0b0b200ca7ad210b0b20092400200a2401200b240220080b8f0101087e02404200200020018420028452ad4200520440000b4200200342208852ad4200520440000b4200a72003a7ada74220a710014200a7290000100c21084200a74208a76aada7290000100c21094200a74210a76aada7290000100c210a4200a74218a76aada7290000100c210b2008210420092105200a2106200b21070b20052400200624012007240220040b1f01017e024020004208864280fe0383200042088842ff01838421010b20010b1e01027e02402000100a421086210220022000421088100a8421010b20010b1e01027e02402000100b422086210220022000422088100b8421010b20010b3f0002402000a72001100c3700002000a74208a76aada72002100c3700002000a74210a76aada72003100c3700002000a74218a76aada72004100c3700000b0b2500024042002000200120022003100d42202004200520062007100d4200a74220a710000b0b Text representation: (module diff --git a/test/cmdlineTests/output_selection_all_A1/output.json b/test/cmdlineTests/output_selection_all_A1/output.json index 074b2062b216..1e4a0b11f85b 100644 --- a/test/cmdlineTests/output_selection_all_A1/output.json +++ b/test/cmdlineTests/output_selection_all_A1/output.json @@ -1,6 +1,6 @@ -{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}},"b.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure +{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}},"b.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"3420","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"2018","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } ^------------------------------------------^ ","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/output_selection_all_A2/output.json b/test/cmdlineTests/output_selection_all_A2/output.json index aa2ca9d0e121..5b0b55bbf6aa 100644 --- a/test/cmdlineTests/output_selection_all_A2/output.json +++ b/test/cmdlineTests/output_selection_all_A2/output.json @@ -1,6 +1,6 @@ -{"contracts":{"a.sol":{"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure +{"contracts":{"a.sol":{"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"3420","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"2018","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } ^------------------------------------------^ ","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/output_selection_all_blank/output.json b/test/cmdlineTests/output_selection_all_blank/output.json index e0872ca8cbdf..32c04bf8ed9c 100644 --- a/test/cmdlineTests/output_selection_all_blank/output.json +++ b/test/cmdlineTests/output_selection_all_blank/output.json @@ -1,6 +1,6 @@ -{"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure +{"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"3420","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"2018","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } ^------------------------------------------^ ","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/output_selection_all_star/output.json b/test/cmdlineTests/output_selection_all_star/output.json index 8997ed8e2dc6..d885876d905e 100644 --- a/test/cmdlineTests/output_selection_all_star/output.json +++ b/test/cmdlineTests/output_selection_all_star/output.json @@ -1,6 +1,6 @@ -{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}},"b.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"B2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure +{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}},"b.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"B2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"3420","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"2018","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } ^------------------------------------------^ ","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/output_selection_single_A1/output.json b/test/cmdlineTests/output_selection_single_A1/output.json index 5bdef1db92be..b32b519ddbb1 100644 --- a/test/cmdlineTests/output_selection_single_A1/output.json +++ b/test/cmdlineTests/output_selection_single_A1/output.json @@ -1,2 +1,2 @@ -{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! +{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/output_selection_single_B1/output.json b/test/cmdlineTests/output_selection_single_B1/output.json index c9c929b971f7..aeb29d7aefb5 100644 --- a/test/cmdlineTests/output_selection_single_B1/output.json +++ b/test/cmdlineTests/output_selection_single_B1/output.json @@ -1,5 +1,5 @@ -{"contracts":{"b.sol":{"B2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure +{"contracts":{"b.sol":{"B2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"2018","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } ^------------------------------------------^ ","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/output_selection_single_all/output.json b/test/cmdlineTests/output_selection_single_all/output.json index f9203fa301e2..07b1a5453d7e 100644 --- a/test/cmdlineTests/output_selection_single_all/output.json +++ b/test/cmdlineTests/output_selection_single_all/output.json @@ -1,2 +1,2 @@ -{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! +{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/recovery_standard_json/output.json b/test/cmdlineTests/recovery_standard_json/output.json index 18a3b97ce2fd..a4113e18679e 100644 --- a/test/cmdlineTests/recovery_standard_json/output.json +++ b/test/cmdlineTests/recovery_standard_json/output.json @@ -1,7 +1,7 @@ -{"errors":[{"component":"general","formattedMessage":"A:2:58: ParserError: Expected type name +{"errors":[{"component":"general","errorCode":"3546","formattedMessage":"A:2:58: ParserError: Expected type name pragma solidity >=0.0; contract Errort6 { using foo for ; /* missing type name */ } ^ -","message":"Expected type name","severity":"error","sourceLocation":{"end":94,"file":"A","start":93},"type":"ParserError"},{"component":"general","formattedMessage":"A:2:84: Warning: Recovered in ContractDefinition at '}'. +","message":"Expected type name","severity":"error","sourceLocation":{"end":94,"file":"A","start":93},"type":"ParserError"},{"component":"general","errorCode":"3796","formattedMessage":"A:2:84: Warning: Recovered in ContractDefinition at '}'. pragma solidity >=0.0; contract Errort6 { using foo for ; /* missing type name */ } ^ ","message":"Recovered in ContractDefinition at '}'.","severity":"warning","sourceLocation":{"end":120,"file":"A","start":119},"type":"Warning"}],"sources":{"A":{"ast":{"absolutePath":"A","exportedSymbols":{"Errort6":[3]},"id":4,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:0"},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","documentation":null,"fullyImplemented":true,"id":3,"linearizedBaseContracts":[3],"name":"Errort6","nodeType":"ContractDefinition","nodes":[],"scope":4,"src":"59:35:0"}],"src":"36:84:0"},"id":0}}} diff --git a/test/cmdlineTests/standard_empty_file_name/output.json b/test/cmdlineTests/standard_empty_file_name/output.json index d1ab4c870f36..04bc54a92a9f 100644 --- a/test/cmdlineTests/standard_empty_file_name/output.json +++ b/test/cmdlineTests/standard_empty_file_name/output.json @@ -1,4 +1,4 @@ -{"errors":[{"component":"general","formattedMessage":":2:24: DeclarationError: Declaration \"A\" not found in \"\" (referenced as \".\"). +{"errors":[{"component":"general","errorCode":"2904","formattedMessage":":2:24: DeclarationError: Declaration \"A\" not found in \"\" (referenced as \".\"). pragma solidity >=0.0; import {A} from \".\"; ^------------------^ ","message":"Declaration \"A\" not found in \"\" (referenced as \".\").","severity":"error","type":"DeclarationError"}],"sources":{}} diff --git a/test/cmdlineTests/standard_immutable_references/output.json b/test/cmdlineTests/standard_immutable_references/output.json index f39a67c07a5d..48376adc5860 100644 --- a/test/cmdlineTests/standard_immutable_references/output.json +++ b/test/cmdlineTests/standard_immutable_references/output.json @@ -1,2 +1,2 @@ -{"contracts":{"a.sol":{"A":{"evm":{"deployedBytecode":{"immutableReferences":{"3":[{"length":32,"start":77}]},"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"36:96:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74:56;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;108:7;126:1;119:8;;74:56;:::o"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! +{"contracts":{"a.sol":{"A":{"evm":{"deployedBytecode":{"immutableReferences":{"3":[{"length":32,"start":77}]},"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"36:96:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74:56;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;108:7;126:1;119:8;;74:56;:::o"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"}],"sources":{"a.sol":{"id":0}}} diff --git a/test/cmdlineTests/standard_secondary_source_location/output.json b/test/cmdlineTests/standard_secondary_source_location/output.json index d9f56b80d688..b32b00028f95 100644 --- a/test/cmdlineTests/standard_secondary_source_location/output.json +++ b/test/cmdlineTests/standard_secondary_source_location/output.json @@ -1,4 +1,4 @@ -{"errors":[{"component":"general","formattedMessage":"A:2:112: DeclarationError: Base constructor arguments given twice. +{"errors":[{"component":"general","errorCode":"3364","formattedMessage":"A:2:112: DeclarationError: Base constructor arguments given twice. pragma solidity >=0.0; contract A { constructor(uint) public {} } contract B is A(2) { } contract C is A(3) {} contract D is B, C {} ^-------------------^ A:2:81: First constructor call is here: diff --git a/test/cmdlineTests/storage_layout_bytes/output.json b/test/cmdlineTests/storage_layout_bytes/output.json index 4414b07d58c2..613189a2a869 100644 --- a/test/cmdlineTests/storage_layout_bytes/output.json +++ b/test/cmdlineTests/storage_layout_bytes/output.json @@ -1,2 +1,2 @@ -{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"s1","offset":0,"slot":"0","type":"t_bytes_storage"},{"astId":5,"contract":"fileA:A","label":"s2","offset":0,"slot":"1","type":"t_bytes_storage"}],"types":{"t_bytes_storage":{"encoding":"bytes","label":"bytes","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"s1","offset":0,"slot":"0","type":"t_bytes_storage"},{"astId":5,"contract":"fileA:A","label":"s2","offset":0,"slot":"1","type":"t_bytes_storage"}],"types":{"t_bytes_storage":{"encoding":"bytes","label":"bytes","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_dyn_array/output.json b/test/cmdlineTests/storage_layout_dyn_array/output.json index 0581b35a1e93..8be650aa54f5 100644 --- a/test/cmdlineTests/storage_layout_dyn_array/output.json +++ b/test/cmdlineTests/storage_layout_dyn_array/output.json @@ -1,2 +1,2 @@ -{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"array1","offset":0,"slot":"0","type":"t_array(t_uint256)dyn_storage"},{"astId":6,"contract":"fileA:A","label":"array2","offset":0,"slot":"1","type":"t_array(t_bool)dyn_storage"}],"types":{"t_array(t_bool)dyn_storage":{"base":"t_bool","encoding":"dynamic_array","label":"bool[]","numberOfBytes":"32"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"array1","offset":0,"slot":"0","type":"t_array(t_uint256)dyn_storage"},{"astId":6,"contract":"fileA:A","label":"array2","offset":0,"slot":"1","type":"t_array(t_bool)dyn_storage"}],"types":{"t_array(t_bool)dyn_storage":{"base":"t_bool","encoding":"dynamic_array","label":"bool[]","numberOfBytes":"32"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_many/output.json b/test/cmdlineTests/storage_layout_many/output.json index 8e14940a9347..a413e1027c1e 100644 --- a/test/cmdlineTests/storage_layout_many/output.json +++ b/test/cmdlineTests/storage_layout_many/output.json @@ -1,2 +1,2 @@ -{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"6","type":"t_address"},{"astId":26,"contract":"fileA:A","label":"map","offset":0,"slot":"7","type":"t_mapping(t_uint256,t_mapping(t_address,t_bool))"},{"astId":29,"contract":"fileA:A","label":"array","offset":0,"slot":"8","type":"t_array(t_uint256)dyn_storage"},{"astId":31,"contract":"fileA:A","label":"s1","offset":0,"slot":"9","type":"t_string_storage"},{"astId":33,"contract":"fileA:A","label":"b1","offset":0,"slot":"10","type":"t_bytes_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_bytes_storage":{"encoding":"bytes","label":"bytes","numberOfBytes":"32"},"t_mapping(t_address,t_bool)":{"encoding":"mapping","key":"t_address","label":"mapping(address => bool)","numberOfBytes":"32","value":"t_bool"},"t_mapping(t_uint256,t_mapping(t_address,t_bool))":{"encoding":"mapping","key":"t_uint256","label":"mapping(uint256 => mapping(address => bool))","numberOfBytes":"32","value":"t_mapping(t_address,t_bool)"},"t_string_storage":{"encoding":"bytes","label":"string","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint128"},{"astId":4,"contract":"fileA:A","label":"b","offset":16,"slot":"0","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"1","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"3","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"128"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"6","type":"t_address"},{"astId":26,"contract":"fileA:A","label":"map","offset":0,"slot":"7","type":"t_mapping(t_uint256,t_mapping(t_address,t_bool))"},{"astId":29,"contract":"fileA:A","label":"array","offset":0,"slot":"8","type":"t_array(t_uint256)dyn_storage"},{"astId":31,"contract":"fileA:A","label":"s1","offset":0,"slot":"9","type":"t_string_storage"},{"astId":33,"contract":"fileA:A","label":"b1","offset":0,"slot":"10","type":"t_bytes_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_bytes_storage":{"encoding":"bytes","label":"bytes","numberOfBytes":"32"},"t_mapping(t_address,t_bool)":{"encoding":"mapping","key":"t_address","label":"mapping(address => bool)","numberOfBytes":"32","value":"t_bool"},"t_mapping(t_uint256,t_mapping(t_address,t_bool))":{"encoding":"mapping","key":"t_uint256","label":"mapping(uint256 => mapping(address => bool))","numberOfBytes":"32","value":"t_mapping(t_address,t_bool)"},"t_string_storage":{"encoding":"bytes","label":"string","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint128"},{"astId":4,"contract":"fileA:A","label":"b","offset":16,"slot":"0","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"1","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"3","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"128"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_mapping/output.json b/test/cmdlineTests/storage_layout_mapping/output.json index c380197cae0e..e3a4944fd2dc 100644 --- a/test/cmdlineTests/storage_layout_mapping/output.json +++ b/test/cmdlineTests/storage_layout_mapping/output.json @@ -1,2 +1,2 @@ -{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":10,"contract":"fileA:A","label":"map","offset":0,"slot":"2","type":"t_mapping(t_uint256,t_mapping(t_address,t_bool))"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_mapping(t_address,t_bool)":{"encoding":"mapping","key":"t_address","label":"mapping(address => bool)","numberOfBytes":"32","value":"t_bool"},"t_mapping(t_uint256,t_mapping(t_address,t_bool))":{"encoding":"mapping","key":"t_uint256","label":"mapping(uint256 => mapping(address => bool))","numberOfBytes":"32","value":"t_mapping(t_address,t_bool)"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":10,"contract":"fileA:A","label":"map","offset":0,"slot":"2","type":"t_mapping(t_uint256,t_mapping(t_address,t_bool))"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_mapping(t_address,t_bool)":{"encoding":"mapping","key":"t_address","label":"mapping(address => bool)","numberOfBytes":"32","value":"t_bool"},"t_mapping(t_uint256,t_mapping(t_address,t_bool))":{"encoding":"mapping","key":"t_uint256","label":"mapping(uint256 => mapping(address => bool))","numberOfBytes":"32","value":"t_mapping(t_address,t_bool)"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_smoke/output.json b/test/cmdlineTests/storage_layout_smoke/output.json index fb8c544c6f6c..c5830bb00678 100644 --- a/test/cmdlineTests/storage_layout_smoke/output.json +++ b/test/cmdlineTests/storage_layout_smoke/output.json @@ -1,2 +1,2 @@ -{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[],"types":null}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[],"types":null}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_smoke_two_contracts/output.json b/test/cmdlineTests/storage_layout_smoke_two_contracts/output.json index abbace7a94eb..8ec54ae260af 100644 --- a/test/cmdlineTests/storage_layout_smoke_two_contracts/output.json +++ b/test/cmdlineTests/storage_layout_smoke_two_contracts/output.json @@ -1,2 +1,2 @@ -{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[],"types":null}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[],"types":null}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0},"fileB":{"id":1}}} diff --git a/test/cmdlineTests/storage_layout_string/output.json b/test/cmdlineTests/storage_layout_string/output.json index 6ce9e236db4c..59312174fa71 100644 --- a/test/cmdlineTests/storage_layout_string/output.json +++ b/test/cmdlineTests/storage_layout_string/output.json @@ -1,2 +1,2 @@ -{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"s1","offset":0,"slot":"0","type":"t_string_storage"},{"astId":5,"contract":"fileA:A","label":"s2","offset":0,"slot":"1","type":"t_string_storage"}],"types":{"t_string_storage":{"encoding":"bytes","label":"string","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"s1","offset":0,"slot":"0","type":"t_string_storage"},{"astId":5,"contract":"fileA:A","label":"s2","offset":0,"slot":"1","type":"t_string_storage"}],"types":{"t_string_storage":{"encoding":"bytes","label":"string","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_struct/output.json b/test/cmdlineTests/storage_layout_struct/output.json index 6437d599ab2f..e8c2d6fdc498 100644 --- a/test/cmdlineTests/storage_layout_struct/output.json +++ b/test/cmdlineTests/storage_layout_struct/output.json @@ -1,2 +1,2 @@ -{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"7","type":"t_address"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"b","offset":0,"slot":"1","type":"t_uint256"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"2","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"4","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"160"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"7","type":"t_address"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"b","offset":0,"slot":"1","type":"t_uint256"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"2","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"4","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"160"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_struct_packed/output.json b/test/cmdlineTests/storage_layout_struct_packed/output.json index 44adfefda243..7ac8c11eb5e8 100644 --- a/test/cmdlineTests/storage_layout_struct_packed/output.json +++ b/test/cmdlineTests/storage_layout_struct_packed/output.json @@ -1,2 +1,2 @@ -{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"6","type":"t_address"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint128"},{"astId":4,"contract":"fileA:A","label":"b","offset":16,"slot":"0","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"1","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"3","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"128"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"6","type":"t_address"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint128"},{"astId":4,"contract":"fileA:A","label":"b","offset":16,"slot":"0","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"1","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"3","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"128"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_value_types/output.json b/test/cmdlineTests/storage_layout_value_types/output.json index 8b9d2437ffbf..2d10422a5a55 100644 --- a/test/cmdlineTests/storage_layout_value_types/output.json +++ b/test/cmdlineTests/storage_layout_value_types/output.json @@ -1,2 +1,2 @@ -{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":6,"contract":"fileA:A","label":"addr","offset":0,"slot":"2","type":"t_address"},{"astId":10,"contract":"fileA:A","label":"array","offset":0,"slot":"3","type":"t_array(t_uint256)2_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":6,"contract":"fileA:A","label":"addr","offset":0,"slot":"2","type":"t_address"},{"astId":10,"contract":"fileA:A","label":"array","offset":0,"slot":"3","type":"t_array(t_uint256)2_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_value_types_packed/output.json b/test/cmdlineTests/storage_layout_value_types_packed/output.json index c7d9563616ee..634cb9305a8d 100644 --- a/test/cmdlineTests/storage_layout_value_types_packed/output.json +++ b/test/cmdlineTests/storage_layout_value_types_packed/output.json @@ -1,2 +1,2 @@ -{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint64"},{"astId":4,"contract":"fileA:A","label":"y","offset":8,"slot":"0","type":"t_uint128"},{"astId":6,"contract":"fileA:A","label":"z","offset":0,"slot":"1","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"addr","offset":0,"slot":"2","type":"t_address"},{"astId":12,"contract":"fileA:A","label":"array","offset":0,"slot":"3","type":"t_array(t_uint256)2_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"},"t_uint64":{"encoding":"inplace","label":"uint64","numberOfBytes":"8"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint64"},{"astId":4,"contract":"fileA:A","label":"y","offset":8,"slot":"0","type":"t_uint128"},{"astId":6,"contract":"fileA:A","label":"z","offset":0,"slot":"1","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"addr","offset":0,"slot":"2","type":"t_address"},{"astId":12,"contract":"fileA:A","label":"array","offset":0,"slot":"3","type":"t_array(t_uint256)2_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"},"t_uint64":{"encoding":"inplace","label":"uint64","numberOfBytes":"8"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/args b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/args new file mode 100644 index 000000000000..04cd5f05ba49 --- /dev/null +++ b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/args @@ -0,0 +1 @@ +--yul --yul-dialect ewasm --machine ewasm diff --git a/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/err b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/err new file mode 100644 index 000000000000..014a1178fa22 --- /dev/null +++ b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/err @@ -0,0 +1 @@ +Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/input.yul b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/input.yul new file mode 100644 index 000000000000..2b1a6d9606c0 --- /dev/null +++ b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/input.yul @@ -0,0 +1,17 @@ +object "object" { + code { + function main() + { + let m:i64, n:i32, p:i32, q:i64 := multireturn(1:i32, 2:i64, 3:i64, 4:i32) + } + + function multireturn(a:i32, b:i64, c:i64, d:i32) -> x:i64, y:i32, z:i32, w:i64 + { + x := b + w := c + + y := a + z := d + } + } +} diff --git a/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/output b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/output new file mode 100644 index 000000000000..a99808601e42 --- /dev/null +++ b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/output @@ -0,0 +1,73 @@ + +======= wasm_to_wasm_function_returning_multiple_values/input.yul (Ewasm) ======= + +Pretty printed source: +object "object" { + code { + function main() + { + let m, n:i32, p:i32, q := multireturn(1:i32, 2, 3, 4:i32) + } + function multireturn(a:i32, b, c, d:i32) -> x, y:i32, z:i32, w + { + x := b + w := c + y := a + z := d + } + } +} + + +Binary representation: +0061736d01000000010c0260000060047e7e7e7e017e020100030302000105030100010610037e0142000b7e0142000b7e0142000b071102066d656d6f72790200046d61696e00000a4a022201047e024002404201420242034204100121002300210123012102230221030b0b0b2501047e0240200121042002210720002105200321060b20052400200624012007240220040b + +Text representation: +(module + (memory $memory (export "memory") 1) + (export "main" (func $main)) + (global $global_ (mut i64) (i64.const 0)) + (global $global__1 (mut i64) (i64.const 0)) + (global $global__2 (mut i64) (i64.const 0)) + +(func $main + (local $m i64) + (local $n i64) + (local $p i64) + (local $q i64) + (block $label_ + (block + (local.set $m (call $multireturn (i64.const 1) (i64.const 2) (i64.const 3) (i64.const 4))) + (local.set $n (global.get $global_)) + (local.set $p (global.get $global__1)) + (local.set $q (global.get $global__2)) + + ) + + ) +) + +(func $multireturn + (param $a i64) + (param $b i64) + (param $c i64) + (param $d i64) + (result i64) + (local $x i64) + (local $y i64) + (local $z i64) + (local $w i64) + (block $label__3 + (local.set $x (local.get $b)) + (local.set $w (local.get $c)) + (local.set $y (local.get $a)) + (local.set $z (local.get $d)) + + ) + (global.set $global_ (local.get $y)) + (global.set $global__1 (local.get $z)) + (global.set $global__2 (local.get $w)) + (local.get $x) +) + +) diff --git a/test/cmdlineTests/wasm_to_wasm_memory_instructions_alignment/args b/test/cmdlineTests/wasm_to_wasm_memory_instructions_alignment/args new file mode 100644 index 000000000000..04cd5f05ba49 --- /dev/null +++ b/test/cmdlineTests/wasm_to_wasm_memory_instructions_alignment/args @@ -0,0 +1 @@ +--yul --yul-dialect ewasm --machine ewasm diff --git a/test/cmdlineTests/wasm_to_wasm_memory_instructions_alignment/err b/test/cmdlineTests/wasm_to_wasm_memory_instructions_alignment/err new file mode 100644 index 000000000000..014a1178fa22 --- /dev/null +++ b/test/cmdlineTests/wasm_to_wasm_memory_instructions_alignment/err @@ -0,0 +1 @@ +Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/wasm_to_wasm_memory_instructions_alignment/input.yul b/test/cmdlineTests/wasm_to_wasm_memory_instructions_alignment/input.yul new file mode 100644 index 000000000000..731e6c9bb21a --- /dev/null +++ b/test/cmdlineTests/wasm_to_wasm_memory_instructions_alignment/input.yul @@ -0,0 +1,8 @@ +object "object" { + code { + function main() + { + i64.store8(0x01:i32, 42:i64) + } + } +} diff --git a/test/cmdlineTests/wasm_to_wasm_memory_instructions_alignment/output b/test/cmdlineTests/wasm_to_wasm_memory_instructions_alignment/output new file mode 100644 index 000000000000..ef0b409fbd77 --- /dev/null +++ b/test/cmdlineTests/wasm_to_wasm_memory_instructions_alignment/output @@ -0,0 +1,27 @@ + +======= wasm_to_wasm_memory_instructions_alignment/input.yul (Ewasm) ======= + +Pretty printed source: +object "object" { + code { + function main() + { i64.store8(0x01:i32, 42) } + } +} + + +Binary representation: +0061736d01000000010401600000020100030201000503010001060100071102066d656d6f72790200046d61696e00000a0f010d0002404201a7422a3c00000b0b + +Text representation: +(module + (memory $memory (export "memory") 1) + (export "main" (func $main)) + +(func $main + (block $label_ + (i64.store8 (i32.wrap_i64 (i64.const 1)) (i64.const 42)) + ) +) + +) diff --git a/test/libsolidity/ABIEncoderTests.cpp b/test/libsolidity/ABIEncoderTests.cpp index b816de6fd211..2e50fe743549 100644 --- a/test/libsolidity/ABIEncoderTests.cpp +++ b/test/libsolidity/ABIEncoderTests.cpp @@ -606,7 +606,7 @@ BOOST_AUTO_TEST_CASE(bytesNN_arrays) BOTH_ENCODERS( for (size_t size = 1; size < 15; size++) { - for (size_t width: {1, 2, 4, 5, 7, 15, 16, 17, 31, 32}) + for (size_t width: {1u, 2u, 4u, 5u, 7u, 15u, 16u, 17u, 31u, 32u}) { string source = boost::algorithm::replace_all_copy(sourceCode, "SIZE", to_string(size)); source = boost::algorithm::replace_all_copy(source, "UINTWIDTH", to_string(width * 8)); @@ -651,7 +651,7 @@ BOOST_AUTO_TEST_CASE(bytesNN_arrays_dyn) BOTH_ENCODERS( for (size_t size = 0; size < 15; size++) { - for (size_t width: {1, 2, 4, 5, 7, 15, 16, 17, 31, 32}) + for (size_t width: {1u, 2u, 4u, 5u, 7u, 15u, 16u, 17u, 31u, 32u}) { string source = boost::algorithm::replace_all_copy(sourceCode, "SIZE", to_string(size)); source = boost::algorithm::replace_all_copy(source, "UINTWIDTH", to_string(width * 8)); diff --git a/test/libsolidity/ASTJSON/assembly/switch_default.json b/test/libsolidity/ASTJSON/assembly/switch_default.json index 2f15a82c5536..3a6c7186477c 100644 --- a/test/libsolidity/ASTJSON/assembly/switch_default.json +++ b/test/libsolidity/ASTJSON/assembly/switch_default.json @@ -33,14 +33,14 @@ { "id": 4, "nodeType": "Block", - "src": "42:48:1", + "src": "42:58:1", "statements": [ { "AST": { "nodeType": "YulBlock", - "src": "61:23:1", + "src": "61:33:1", "statements": [ { @@ -50,11 +50,29 @@ "body": { "nodeType": "YulBlock", - "src": "80:2:1", + "src": "79:2:1", "statements": [] }, "nodeType": "YulCase", - "src": "72:10:1", + "src": "72:9:1", + "value": + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "77:1:1", + "type": "", + "value": "0" + } + }, + { + "body": + { + "nodeType": "YulBlock", + "src": "90:2:1", + "statements": [] + }, + "nodeType": "YulCase", + "src": "82:10:1", "value": "default" } ], @@ -67,7 +85,7 @@ "value": "0" }, "nodeType": "YulSwitch", - "src": "63:19:1" + "src": "63:29:1" } ] }, @@ -75,7 +93,7 @@ "externalReferences": [], "id": 3, "nodeType": "InlineAssembly", - "src": "52:32:1" + "src": "52:42:1" } ] }, @@ -103,15 +121,15 @@ "src": "42:0:1" }, "scope": 6, - "src": "17:73:1", + "src": "17:83:1", "stateMutability": "view", "virtual": false, "visibility": "public" } ], "scope": 7, - "src": "0:92:1" + "src": "0:102:1" } ], - "src": "0:93:1" + "src": "0:103:1" } diff --git a/test/libsolidity/ASTJSON/assembly/switch_default.sol b/test/libsolidity/ASTJSON/assembly/switch_default.sol index 8bfba2c11568..1f61896fe275 100644 --- a/test/libsolidity/ASTJSON/assembly/switch_default.sol +++ b/test/libsolidity/ASTJSON/assembly/switch_default.sol @@ -1,6 +1,6 @@ contract C { function g() view public { - assembly { switch 0 default {} } + assembly { switch 0 case 0 {} default {} } } } diff --git a/test/libsolidity/ASTJSON/assembly/switch_default_legacy.json b/test/libsolidity/ASTJSON/assembly/switch_default_legacy.json index 18e7c860c17d..3b79ccf44182 100644 --- a/test/libsolidity/ASTJSON/assembly/switch_default_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/switch_default_legacy.json @@ -95,30 +95,30 @@ [ null ], - "operations": "{\n switch 0\n default { }\n}" + "operations": "{\n switch 0\n case 0 { }\n default { }\n}" }, "children": [], "id": 3, "name": "InlineAssembly", - "src": "52:32:1" + "src": "52:42:1" } ], "id": 4, "name": "Block", - "src": "42:48:1" + "src": "42:58:1" } ], "id": 5, "name": "FunctionDefinition", - "src": "17:73:1" + "src": "17:83:1" } ], "id": 6, "name": "ContractDefinition", - "src": "0:92:1" + "src": "0:102:1" } ], "id": 7, "name": "SourceUnit", - "src": "0:93:1" + "src": "0:103:1" } diff --git a/test/libsolidity/ASTJSONTest.cpp b/test/libsolidity/ASTJSONTest.cpp index 3cc8b3ab31a7..974e0f4863c9 100644 --- a/test/libsolidity/ASTJSONTest.cpp +++ b/test/libsolidity/ASTJSONTest.cpp @@ -134,7 +134,7 @@ TestCase::TestResult ASTJSONTest::run(ostream& _stream, string const& _linePrefi c.analyze(); else { - SourceReferenceFormatterHuman formatter(_stream, _formatted); + SourceReferenceFormatterHuman formatter(_stream, _formatted, false); for (auto const& error: c.errors()) formatter.printErrorInformation(*error); return TestResult::FatalError; diff --git a/test/libsolidity/GasTest.cpp b/test/libsolidity/GasTest.cpp index 893a20715f2e..d76979c9c7b6 100644 --- a/test/libsolidity/GasTest.cpp +++ b/test/libsolidity/GasTest.cpp @@ -118,7 +118,7 @@ TestCase::TestResult GasTest::run(ostream& _stream, string const& _linePrefix, b if (!compiler().parseAndAnalyze() || !compiler().compile()) { - SourceReferenceFormatterHuman formatter(_stream, _formatted); + SourceReferenceFormatterHuman formatter(_stream, _formatted, false); for (auto const& error: compiler().errors()) formatter.printErrorInformation(*error); return TestResult::FatalError; diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp index 2a1b72e500da..1d61484a9c48 100644 --- a/test/libsolidity/InlineAssembly.cpp +++ b/test/libsolidity/InlineAssembly.cpp @@ -314,9 +314,17 @@ BOOST_AUTO_TEST_CASE(switch_duplicate_case) BOOST_AUTO_TEST_CASE(switch_invalid_expression) { - CHECK_PARSE_ERROR("{ switch {} default {} }", ParserError, "Literal or identifier expected."); - CHECK_PARSE_ERROR("{ switch mload default {} }", ParserError, "Expected '(' but got reserved keyword 'default'"); - CHECK_PARSE_ERROR("{ switch mstore(1, 1) default {} }", TypeError, "Expected expression to evaluate to one value, but got 0 values instead."); + CHECK_PARSE_ERROR("{ switch {} case 1 {} default {} }", ParserError, "Literal or identifier expected."); + CHECK_PARSE_ERROR( + "{ switch mload case 1 {} default {} }", + ParserError, + "Expected '(' but got reserved keyword 'case'" + ); + CHECK_PARSE_ERROR( + "{ switch mstore(1, 1) case 1 {} default {} }", + TypeError, + "Expected expression to evaluate to one value, but got 0 values instead." + ); } BOOST_AUTO_TEST_CASE(switch_default_before_case) diff --git a/test/libsolidity/SMTCheckerJSONTest.cpp b/test/libsolidity/SMTCheckerJSONTest.cpp index 484db13fff0e..396ecb280b27 100644 --- a/test/libsolidity/SMTCheckerJSONTest.cpp +++ b/test/libsolidity/SMTCheckerJSONTest.cpp @@ -116,21 +116,21 @@ TestCase::TestResult SMTCheckerJSONTest::run(ostream& _stream, string const& _li !location["end"].isInt() ) BOOST_THROW_EXCEPTION(runtime_error("Error must have a SourceLocation with start and end.")); - int start = location["start"].asInt(); - int end = location["end"].asInt(); + size_t start = location["start"].asUInt(); + size_t end = location["end"].asUInt(); std::string sourceName; if (location.isMember("source") && location["source"].isString()) sourceName = location["source"].asString(); - if (start >= static_cast(preamble.size())) + if (start >= preamble.size()) start -= preamble.size(); - if (end >= static_cast(preamble.size())) + if (end >= preamble.size()) end -= preamble.size(); m_errorList.emplace_back(SyntaxTestError{ error["type"].asString(), error["message"].asString(), sourceName, - start, - end + static_cast(start), + static_cast(end) }); } } diff --git a/test/libsolidity/SolidityExpressionCompiler.cpp b/test/libsolidity/SolidityExpressionCompiler.cpp index d40e64ebf5fd..41c850b4d90f 100644 --- a/test/libsolidity/SolidityExpressionCompiler.cpp +++ b/test/libsolidity/SolidityExpressionCompiler.cpp @@ -143,8 +143,8 @@ bytes compileFirstExpression( ); context.resetVisitedNodes(contract); context.setMostDerivedContract(*contract); - unsigned parametersSize = _localVariables.size(); // assume they are all one slot on the stack - context.adjustStackOffset(parametersSize); + size_t parametersSize = _localVariables.size(); // assume they are all one slot on the stack + context.adjustStackOffset(static_cast(parametersSize)); for (vector const& variable: _localVariables) context.addVariable( dynamic_cast(resolveDeclaration(*sourceUnit, variable, resolver)), diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp index fec67f0e6a18..4062b1928b2b 100644 --- a/test/libsolidity/SolidityOptimizer.cpp +++ b/test/libsolidity/SolidityOptimizer.cpp @@ -491,7 +491,7 @@ BOOST_AUTO_TEST_CASE(constant_optimization_early_exit) #endif #endif #if __SANITIZE_ADDRESS__ - maxDuration = size_t(-1); + maxDuration = numeric_limits::max(); BOOST_TEST_MESSAGE("Disabled constant optimizer run time check for address sanitizer build."); #endif BOOST_CHECK_MESSAGE(duration <= maxDuration, "Compilation of constants took longer than 20 seconds."); diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp index 12fbc3fcec35..364c0e2d56ac 100644 --- a/test/libsolidity/SolidityParser.cpp +++ b/test/libsolidity/SolidityParser.cpp @@ -675,7 +675,7 @@ BOOST_AUTO_TEST_CASE(inline_asm_end_location) bool visit(InlineAssembly const& _inlineAsm) override { auto loc = _inlineAsm.location(); - auto asmStr = loc.source->source().substr(loc.start, loc.end - loc.start); + auto asmStr = loc.source->source().substr(static_cast(loc.start), static_cast(loc.end - loc.start)); BOOST_CHECK_EQUAL(asmStr, "assembly { a := 0x12345678 }"); visited = true; diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index 3b7b1d1284f8..f8ae1d873cf4 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -466,7 +466,7 @@ BOOST_AUTO_TEST_CASE(compilation_error) { BOOST_CHECK_EQUAL( util::jsonCompactPrint(error), - "{\"component\":\"general\",\"formattedMessage\":\"fileA:1:23: ParserError: Expected identifier but got '}'\\n" + "{\"component\":\"general\",\"errorCode\":\"2314\",\"formattedMessage\":\"fileA:1:23: ParserError: Expected identifier but got '}'\\n" "contract A { function }\\n ^\\n\",\"message\":\"Expected identifier but got '}'\"," "\"severity\":\"error\",\"sourceLocation\":{\"end\":23,\"file\":\"fileA\",\"start\":22},\"type\":\"ParserError\"}" ); diff --git a/test/libsolidity/SyntaxTest.cpp b/test/libsolidity/SyntaxTest.cpp index 55a77ed3090f..47411748e941 100644 --- a/test/libsolidity/SyntaxTest.cpp +++ b/test/libsolidity/SyntaxTest.cpp @@ -98,9 +98,9 @@ void SyntaxTest::filterObtainedErrors() { // ignore the version & license pragma inserted by the testing tool when calculating locations. if (location->start >= static_cast(preamble.size())) - locationStart = location->start - (preamble.size()); + locationStart = location->start - static_cast(preamble.size()); if (location->end >= static_cast(preamble.size())) - locationEnd = location->end - (preamble.size()); + locationEnd = location->end - static_cast(preamble.size()); if (location->source) sourceName = location->source->name(); } diff --git a/test/libsolidity/semanticTests/array/index_access.sol b/test/libsolidity/semanticTests/array/index_access.sol new file mode 100644 index 000000000000..acb33fc46b2f --- /dev/null +++ b/test/libsolidity/semanticTests/array/index_access.sol @@ -0,0 +1,20 @@ +contract C { + function to_little_endian_64(uint64 value) public pure returns (bytes memory ret) { + ret = new bytes(8); + bytes8 bytesValue = bytes8(value); + // Byteswapping during copying to bytes. + ret[0] = bytesValue[7]; + ret[1] = bytesValue[6]; + ret[2] = bytesValue[5]; + ret[3] = bytesValue[4]; + ret[4] = bytesValue[3]; + ret[5] = bytesValue[2]; + ret[6] = bytesValue[1]; + ret[7] = bytesValue[0]; + } +} +// ==== +// compileViaYul: also +// ---- +// to_little_endian_64(uint64): 0 -> 0x20, 8, 0x00 +// to_little_endian_64(uint64): 0x0102030405060708 -> 0x20, 8, 0x0807060504030201000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/calldata/calldata_bytes_external.sol b/test/libsolidity/semanticTests/calldata/calldata_bytes_external.sol new file mode 100644 index 000000000000..9917e736a945 --- /dev/null +++ b/test/libsolidity/semanticTests/calldata/calldata_bytes_external.sol @@ -0,0 +1,12 @@ +contract CalldataTest { + function test(bytes calldata x) public returns (bytes calldata) { + return x; + } + function tester(bytes calldata x) public returns (byte) { + return this.test(x)[2]; + } +} +// ==== +// EVMVersion: >=byzantium +// ---- +// tester(bytes): 0x20, 0x08, "abcdefgh" -> "c" diff --git a/test/libsolidity/semanticTests/getters/array_mapping_struct.sol b/test/libsolidity/semanticTests/getters/array_mapping_struct.sol new file mode 100644 index 000000000000..534dcd8a6970 --- /dev/null +++ b/test/libsolidity/semanticTests/getters/array_mapping_struct.sol @@ -0,0 +1,29 @@ +contract C { + struct Y { + uint a; + uint b; + } + mapping(uint256 => Y)[] public m; + mapping(uint256 => Y)[3] public n; + constructor() public { + m.push(); + m.push(); + m[1][0].a = 1; + m[1][0].b = 2; + m[1][1].a = 3; + m[1][1].b = 4; + n[1][0].a = 7; + n[1][0].b = 8; + n[1][1].a = 9; + n[1][1].b = 10; + } +} +// ---- +// m(uint256,uint256): 0, 0 -> 0x00, 0x00 +// m(uint256,uint256): 1, 0 -> 1, 2 +// m(uint256,uint256): 1, 1 -> 3, 4 +// m(uint256,uint256): 1, 2 -> 0x00, 0x00 +// n(uint256,uint256): 0, 0 -> 0x00, 0x00 +// n(uint256,uint256): 1, 0 -> 7, 8 +// n(uint256,uint256): 1, 1 -> 9, 0x0a +// n(uint256,uint256): 1, 2 -> 0x00, 0x00 diff --git a/test/libsolidity/semanticTests/getters/mapping_array_struct.sol b/test/libsolidity/semanticTests/getters/mapping_array_struct.sol new file mode 100644 index 000000000000..2b237c4df9a0 --- /dev/null +++ b/test/libsolidity/semanticTests/getters/mapping_array_struct.sol @@ -0,0 +1,27 @@ +contract C { + struct Y { + uint a; + uint b; + } + mapping(uint256 => Y[]) public m; + mapping(uint256 => Y[3]) public n; + constructor() public { + m[1].push().a = 1; + m[1][0].b = 2; + m[1].push().a = 3; + m[1][1].b = 4; + n[1][0].a = 7; + n[1][0].b = 8; + n[1][1].a = 9; + n[1][1].b = 10; + } +} +// ---- +// m(uint256,uint256): 0, 0 -> FAILURE +// m(uint256,uint256): 1, 0 -> 1, 2 +// m(uint256,uint256): 1, 1 -> 3, 4 +// m(uint256,uint256): 1, 2 -> FAILURE +// n(uint256,uint256): 0, 0 -> 0x00, 0x00 +// n(uint256,uint256): 1, 0 -> 7, 8 +// n(uint256,uint256): 1, 1 -> 9, 0x0a +// n(uint256,uint256): 1, 2 -> 0x00, 0x00 diff --git a/test/libsolidity/semanticTests/getters/mapping_of_string.sol b/test/libsolidity/semanticTests/getters/mapping_of_string.sol new file mode 100644 index 000000000000..ea0a8b8f8a54 --- /dev/null +++ b/test/libsolidity/semanticTests/getters/mapping_of_string.sol @@ -0,0 +1,18 @@ +contract C { + mapping(string => uint8[3]) public x; + constructor() public { + x["abc"][0] = 1; + x["abc"][2] = 3; + x["abc"][1] = 2; + x["def"][1] = 9; + } +} +// ==== +// compileViaYul: also +// ---- +// x(string,uint256): 0x40, 0, 3, "abc" -> 1 +// x(string,uint256): 0x40, 1, 3, "abc" -> 2 +// x(string,uint256): 0x40, 2, 3, "abc" -> 3 +// x(string,uint256): 0x40, 0, 3, "def" -> 0x00 +// x(string,uint256): 0x40, 1, 3, "def" -> 9 +// x(string,uint256): 0x40, 2, 3, "def" -> 0x00 diff --git a/test/libsolidity/semanticTests/getters/struct_with_bytes.sol b/test/libsolidity/semanticTests/getters/struct_with_bytes.sol new file mode 100644 index 000000000000..2bbd7e8b823e --- /dev/null +++ b/test/libsolidity/semanticTests/getters/struct_with_bytes.sol @@ -0,0 +1,18 @@ +contract C { + struct S { + uint a; + bytes b; + mapping(uint => uint) c; + uint[] d; + } + uint shifter; + S public s; + constructor() public { + s.a = 7; + s.b = "abc"; + s.c[0] = 9; + s.d.push(10); + } +} +// ---- +// s() -> 7, 0x40, 3, 0x6162630000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/getters/struct_with_bytes_simple.sol b/test/libsolidity/semanticTests/getters/struct_with_bytes_simple.sol new file mode 100644 index 000000000000..974ca9e809c7 --- /dev/null +++ b/test/libsolidity/semanticTests/getters/struct_with_bytes_simple.sol @@ -0,0 +1,17 @@ +contract C { + struct S { + uint a; + bytes b; + mapping(uint => uint) c; + uint[] d; + } + uint shifter; + S public s; + constructor() public { + s.a = 7; + s.b = "abc"; + s.c[0] = 9; + } +} +// ---- +// s() -> 0x07, 0x40, 0x03, 0x6162630000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/libraries/bound_returning_calldata.sol b/test/libsolidity/semanticTests/libraries/bound_returning_calldata.sol new file mode 100644 index 000000000000..7451e9dc486d --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/bound_returning_calldata.sol @@ -0,0 +1,17 @@ +library D { + function f(bytes calldata _x) internal pure returns (bytes calldata) { + return _x; + } + function g(bytes calldata _x) internal pure returns (bytes memory) { + return _x; + } +} + +contract C { + using D for bytes; + function f(bytes calldata _x) public pure returns (byte, byte) { + return (_x.f()[0], _x.g()[0]); + } +} +// ---- +// f(bytes): 0x20, 4, "abcd" -> 0x6100000000000000000000000000000000000000000000000000000000000000, 0x6100000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/libraries/bound_returning_calldata_external.sol b/test/libsolidity/semanticTests/libraries/bound_returning_calldata_external.sol new file mode 100644 index 000000000000..3114f851071a --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/bound_returning_calldata_external.sol @@ -0,0 +1,20 @@ +library D { + function f(bytes calldata _x) public pure returns (bytes calldata) { + return _x; + } + function g(bytes calldata _x) public pure returns (bytes memory) { + return _x; + } +} + +contract C { + using D for bytes; + function f(bytes calldata _x) public pure returns (byte, byte) { + return (_x.f()[0], _x.g()[0]); + } +} +// ==== +// EVMVersion: >homestead +// ---- +// library: D +// f(bytes): 0x20, 4, "abcd" -> 0x6100000000000000000000000000000000000000000000000000000000000000, 0x6100000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/libraries/bound_to_calldata.sol b/test/libsolidity/semanticTests/libraries/bound_to_calldata.sol new file mode 100644 index 000000000000..0e9bb811b3ac --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/bound_to_calldata.sol @@ -0,0 +1,17 @@ +library D { + function f(bytes calldata _x) internal pure returns (byte) { + return _x[0]; + } + function g(bytes memory _x) internal pure returns (byte) { + return _x[0]; + } +} + +contract C { + using D for bytes; + function f(bytes calldata _x) public pure returns (byte, byte) { + return (_x.f(), _x.g()); + } +} +// ---- +// f(bytes): 0x20, 4, "abcd" -> 0x6100000000000000000000000000000000000000000000000000000000000000, 0x6100000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/libraries/bound_to_calldata_external.sol b/test/libsolidity/semanticTests/libraries/bound_to_calldata_external.sol new file mode 100644 index 000000000000..2f8c7c7f3937 --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/bound_to_calldata_external.sol @@ -0,0 +1,20 @@ +library D { + function f(bytes calldata _x) public pure returns (byte) { + return _x[0]; + } + function g(bytes memory _x) public pure returns (byte) { + return _x[0]; + } +} + +contract C { + using D for bytes; + function f(bytes calldata _x) public pure returns (byte, byte) { + return (_x.f(), _x.g()); + } +} +// ==== +// EVMVersion: >homestead +// ---- +// library: D +// f(bytes): 0x20, 4, "abcd" -> 0x6100000000000000000000000000000000000000000000000000000000000000, 0x6100000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/libraries/using_for_storage_structs.sol b/test/libsolidity/semanticTests/libraries/using_for_storage_structs.sol new file mode 100644 index 000000000000..cd45726b676b --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/using_for_storage_structs.sol @@ -0,0 +1,25 @@ +struct Struct { uint x; } + +library L { + function f(Struct storage _x) internal view returns (uint256) { + return _x.x; + } +} + +contract C { + using L for Struct; + + Struct s; + + function h(Struct storage _s) internal view returns (uint) { + // _s is pointer + return _s.f(); + } + function g() public returns (uint, uint) { + s.x = 7; + // s is reference + return (s.f(), h(s)); + } +} +// ---- +// g() -> 7, 7 diff --git a/test/libsolidity/semanticTests/viaYul/memory_struct_allow.sol b/test/libsolidity/semanticTests/viaYul/memory_struct_allow.sol new file mode 100644 index 000000000000..b1af4fab8563 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/memory_struct_allow.sol @@ -0,0 +1,21 @@ +contract C { + struct S { + uint256 a; + uint256 b; + } + + function f() public pure returns (uint256 a, uint256 b){ + assembly { + // Make free memory dirty to check that the struct allocation cleans it up again. + let freeMem := mload(0x40) + mstore(freeMem, 42) + mstore(add(freeMem, 32), 42) + } + S memory s; + return (s.a, s.b); + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> 0, 0 diff --git a/test/libsolidity/semanticTests/viaYul/struct_member_access.sol b/test/libsolidity/semanticTests/viaYul/struct_member_access.sol new file mode 100644 index 000000000000..60733d414033 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/struct_member_access.sol @@ -0,0 +1,39 @@ +pragma experimental ABIEncoderV2; + +contract C { + struct S { + uint a; + uint[] b; + uint c; + } + + S s; + constructor() public { + s.a = 42; + s.b.push(1); + s.b.push(2); + s.b.push(3); + s.c = 21; + } + + function f(S memory m) public pure returns (uint, uint[] memory, uint) { + return (m.a, m.b, m.c); + } + function g(S calldata c) external pure returns (uint, uint, uint, uint, uint, uint) { + return (c.a, c.b.length, c.c, c.b[0], c.b[1], c.b[2]); + } + function g2(S calldata c1, S calldata c2) external pure returns (uint, uint, uint, uint, uint, uint) { + return (c1.a, c1.c, c2.a, c2.b.length, c2.c, c2.b[0]); + } + function h() external view returns (uint, uint, uint, uint, uint, uint) { + return (s.a, s.b.length, s.c, s.b[0], s.b[1], s.b[2]); + } +} +// ==== +// EVMVersion: >homestead +// compileViaYul: also +// ---- +// f((uint256,uint256[],uint256)): 0x20, 42, 0x60, 21, 3, 1, 2, 3 -> 42, 0x60, 21, 3, 1, 2, 3 +// g((uint256,uint256[],uint256)): 0x20, 42, 0x60, 21, 3, 1, 2, 3 -> 42, 3, 21, 1, 2, 3 +// g2((uint256,uint256[],uint256),(uint256,uint256[],uint256)): 0x40, 0x0120, 42, 0x60, 21, 2, 1, 2, 3, 7, 0x80, 9, 0, 1, 17 -> 42, 21, 7, 1, 9, 17 +// h() -> 42, 3, 21, 1, 2, 3 diff --git a/test/libsolidity/smtCheckerTests/array_members/push_storage_ref_unsafe_length.sol b/test/libsolidity/smtCheckerTests/array_members/push_storage_ref_unsafe_length.sol new file mode 100644 index 000000000000..70f8cb9fc51a --- /dev/null +++ b/test/libsolidity/smtCheckerTests/array_members/push_storage_ref_unsafe_length.sol @@ -0,0 +1,23 @@ +pragma experimental SMTChecker; + +contract C { + uint[][] a; + uint[][][] c; + uint[] d; + function f() public { + a.push(); + uint[] storage b = a[0]; + c[0][0][0] = 12; + d[5] = 7; + b.push(8); + assert(a[0].length == 0); + // Safe but knowledge about `c` is erased because `b` could be pointing to `c[x][y]`. + assert(c[0][0][0] == 12); + // Safe but knowledge about `d` is erased because `b` could be pointing to `d`. + assert(d[5] == 7); + } +} +// ---- +// Warning: (193-217): Assertion violation happens here +// Warning: (309-333): Assertion violation happens here +// Warning: (419-436): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/operators/fixed_point_add.sol b/test/libsolidity/smtCheckerTests/operators/fixed_point_add.sol new file mode 100644 index 000000000000..23a05e619bd5 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/fixed_point_add.sol @@ -0,0 +1,12 @@ +pragma experimental SMTChecker; +contract test { + function f() internal pure { + ufixed a = uint64(1) + ufixed(2); + } +} +// ---- +// Warning: (80-88): Unused local variable. +// Warning: (91-100): Type conversion is not yet fully supported and might yield false positives. +// Warning: (103-112): Type conversion is not yet fully supported and might yield false positives. +// Warning: (91-112): Underflow (resulting value less than 0) happens here +// Warning: (91-112): Overflow (resulting value larger than 2**256 - 1) happens here diff --git a/test/libsolidity/smtCheckerTests/operators/fixed_point_compound_add.sol b/test/libsolidity/smtCheckerTests/operators/fixed_point_compound_add.sol new file mode 100644 index 000000000000..d4cbbc696f8c --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/fixed_point_compound_add.sol @@ -0,0 +1,8 @@ +pragma experimental SMTChecker; +contract C { + fixed[] b; + function f() internal { b[0] += 1; } +} +// ---- +// Warning: (84-93): Underflow (resulting value less than 0) happens here +// Warning: (84-93): Overflow (resulting value larger than 2**256 - 1) happens here diff --git a/test/libsolidity/smtCheckerTests/types/tuple_tuple.sol b/test/libsolidity/smtCheckerTests/types/tuple_tuple.sol new file mode 100644 index 000000000000..c12e56a2d11e --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/tuple_tuple.sol @@ -0,0 +1,6 @@ +pragma experimental SMTChecker; +contract C { + function f3() public pure { + ((, ), ) = ((7, 8), 9); + } +} diff --git a/test/libsolidity/syntaxTests/bound/bound_calldata.sol b/test/libsolidity/syntaxTests/bound/bound_calldata.sol new file mode 100644 index 000000000000..f6fcf82cbf6b --- /dev/null +++ b/test/libsolidity/syntaxTests/bound/bound_calldata.sol @@ -0,0 +1,9 @@ +library D { function f(bytes calldata) internal pure {} } +contract C { + using D for bytes; + function f(bytes memory _x) public pure { + _x.f(); + } +} +// ---- +// TypeError: (136-140): Member "f" not found or not visible after argument-dependent lookup in bytes memory. diff --git a/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/assembly/switch_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/assembly/switch_declaration_fine.sol index d723109244a6..a32599d7bc1d 100644 --- a/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/assembly/switch_declaration_fine.sol +++ b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/assembly/switch_declaration_fine.sol @@ -1,15 +1,7 @@ contract C { struct S { bool f; } S s; - function f(uint256 a) internal pure { - S storage c; - assembly { - switch a - default { c_slot := s_slot } - } - c; - } - function g(bool flag) internal pure { + function f(bool flag) internal pure { S storage c; assembly { switch flag @@ -18,7 +10,7 @@ contract C { } c; } - function h(uint256 a) internal pure { + function g(uint256 a) internal pure { S storage c; assembly { switch a diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/switch_fine.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/switch_fine.sol index 9e73ecff1fc5..8d0b564fcfa3 100644 --- a/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/switch_fine.sol +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/switch_fine.sol @@ -1,20 +1,14 @@ contract C { struct S { bool f; } S s; - function f(uint256 a) internal pure returns (S storage c) { - assembly { - switch a - default { c_slot := s_slot } - } - } - function g(bool flag) internal pure returns (S storage c) { + function f(bool flag) internal pure returns (S storage c) { assembly { switch flag case 0 { c_slot := s_slot } default { c_slot := s_slot } } } - function h(uint256 a) internal pure returns (S storage c) { + function g(uint256 a) internal pure returns (S storage c) { assembly { switch a case 0 { revert(0, 0) } diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/switch_only_default_warn.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/switch_only_default_warn.sol new file mode 100644 index 000000000000..fff82c20d869 --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/switch_only_default_warn.sol @@ -0,0 +1,12 @@ +contract C { + struct S { bool f; } + S s; + function f(uint256 a) internal pure returns (S storage c) { + assembly { + switch a + default { c_slot := s_slot } + } + } +} +// ---- +// Warning: (142-195): "switch" statement with only a default case. diff --git a/test/libsolidity/util/BytesUtils.cpp b/test/libsolidity/util/BytesUtils.cpp index 72f7c7594975..fd2cd2fcf730 100644 --- a/test/libsolidity/util/BytesUtils.cpp +++ b/test/libsolidity/util/BytesUtils.cpp @@ -348,10 +348,10 @@ string BytesUtils::formatBytesRange( size_t BytesUtils::countRightPaddedZeros(bytes const& _bytes) { - return find_if( + return static_cast(find_if( _bytes.rbegin(), _bytes.rend(), [](uint8_t b) { return b != '\0'; } - ) - _bytes.rbegin(); + ) - _bytes.rbegin()); } diff --git a/test/libsolidity/util/TestFileParserTests.cpp b/test/libsolidity/util/TestFileParserTests.cpp index d24a80b95290..4fb44d7cdd07 100644 --- a/test/libsolidity/util/TestFileParserTests.cpp +++ b/test/libsolidity/util/TestFileParserTests.cpp @@ -66,7 +66,7 @@ void testFunctionCall( ABI_CHECK(_call.expectations.rawBytes(), _expectations); BOOST_REQUIRE_EQUAL(_call.displayMode, _mode); BOOST_REQUIRE_EQUAL(_call.value.value, _value.value); - BOOST_REQUIRE_EQUAL(size_t(_call.value.unit), size_t(_value.unit)); + BOOST_REQUIRE_EQUAL(static_cast(_call.value.unit), static_cast(_value.unit)); BOOST_REQUIRE_EQUAL(_call.arguments.comment, _argumentComment); BOOST_REQUIRE_EQUAL(_call.expectations.comment, _expectationComment); diff --git a/test/libyul/Common.cpp b/test/libyul/Common.cpp index ee6d77dab750..57ee7ffa619b 100644 --- a/test/libyul/Common.cpp +++ b/test/libyul/Common.cpp @@ -87,12 +87,12 @@ pair, shared_ptr> yul::test::parse( shared_ptr parserResult = yul::ObjectParser(errorReporter, _dialect).parse(scanner, false); if (!parserResult) return {}; - if (!parserResult->code || !errorReporter.errors().empty()) + if (!parserResult->code || errorReporter.hasErrors()) return {}; shared_ptr analysisInfo = make_shared(); AsmAnalyzer analyzer(*analysisInfo, errorReporter, _dialect, {}, parserResult->dataNames()); // TODO this should be done recursively. - if (!analyzer.analyze(*parserResult->code) || !errorReporter.errors().empty()) + if (!analyzer.analyze(*parserResult->code) || errorReporter.hasErrors()) return {}; return {std::move(parserResult->code), std::move(analysisInfo)}; } diff --git a/test/libyul/Metrics.cpp b/test/libyul/Metrics.cpp index 2d1cc1c4ec75..7ae9e44f5b00 100644 --- a/test/libyul/Metrics.cpp +++ b/test/libyul/Metrics.cpp @@ -332,7 +332,7 @@ BOOST_FIXTURE_TEST_CASE(if_statement_custom_weights, CustomWeightFixture) BOOST_AUTO_TEST_CASE(switch_statement_tiny) { BOOST_CHECK_EQUAL(codeSize( - "{ switch calldatasize() default {} }" + "{ switch calldatasize() case 0 {} }" ), 4); } diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp index bda7c6514e20..a4507e18031c 100644 --- a/test/libyul/YulOptimizerTest.cpp +++ b/test/libyul/YulOptimizerTest.cpp @@ -362,7 +362,7 @@ bool YulOptimizerTest::parse(ostream& _stream, string const& _linePrefix, bool c ErrorList errors; soltestAssert(m_dialect, ""); std::tie(m_ast, m_analysisInfo) = yul::test::parse(m_source, *m_dialect, errors); - if (!m_ast || !m_analysisInfo || !errors.empty()) + if (!m_ast || !m_analysisInfo || !Error::containsOnlyWarnings(errors)) { AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << endl; printErrors(_stream, errors); diff --git a/test/yulPhaser/Mutations.cpp b/test/yulPhaser/Mutations.cpp index 27e57be08f11..b20cb8e4cb7a 100644 --- a/test/yulPhaser/Mutations.cpp +++ b/test/yulPhaser/Mutations.cpp @@ -118,7 +118,7 @@ BOOST_AUTO_TEST_CASE(geneAddition_should_be_able_to_insert_before_first_position BOOST_TEST(mutatedChromosome.length() > chromosome.length()); vector suffix( - mutatedChromosome.optimisationSteps().end() - chromosome.length(), + mutatedChromosome.optimisationSteps().end() - static_cast(chromosome.length()), mutatedChromosome.optimisationSteps().end() ); BOOST_TEST(suffix == chromosome.optimisationSteps()); @@ -135,7 +135,7 @@ BOOST_AUTO_TEST_CASE(geneAddition_should_be_able_to_insert_after_last_position) vector prefix( mutatedChromosome.optimisationSteps().begin(), - mutatedChromosome.optimisationSteps().begin() + chromosome.length() + mutatedChromosome.optimisationSteps().begin() + static_cast(chromosome.length()) ); BOOST_TEST(prefix == chromosome.optimisationSteps()); } @@ -179,8 +179,8 @@ BOOST_AUTO_TEST_CASE(alternativeMutations_should_choose_between_mutations_with_g for (size_t i = 0; i < 10; ++i) { Chromosome mutatedChromosome = mutation(chromosome); - cCount += static_cast(mutatedChromosome == Chromosome("c")); - fCount += static_cast(mutatedChromosome == Chromosome("f")); + cCount += (mutatedChromosome == Chromosome("c") ? 1 : 0); + fCount += (mutatedChromosome == Chromosome("f") ? 1 : 0); } // This particular seed results in 7 "c"s out of 10 which looks plausible given the 80% chance. diff --git a/test/yulPhaser/Population.cpp b/test/yulPhaser/Population.cpp index 1657e97c99c9..5fd8c2073cf1 100644 --- a/test/yulPhaser/Population.cpp +++ b/test/yulPhaser/Population.cpp @@ -135,7 +135,7 @@ BOOST_FIXTURE_TEST_CASE(makeRandom_should_get_chromosome_lengths_from_specified_ size_t maxLength = 5; assert(chromosomeCount % maxLength == 0); - auto nextLength = [counter = 0, maxLength]() mutable { return counter++ % maxLength; }; + auto nextLength = [counter = 0ul, maxLength]() mutable { return counter++ % maxLength; }; auto population = Population::makeRandom(m_fitnessMetric, chromosomeCount, nextLength); // We can't rely on the order since the population sorts its chromosomes immediately but diff --git a/test/yulPhaser/TestHelpers.cpp b/test/yulPhaser/TestHelpers.cpp index 2379016fe246..2f4b40b02bbe 100644 --- a/test/yulPhaser/TestHelpers.cpp +++ b/test/yulPhaser/TestHelpers.cpp @@ -72,9 +72,13 @@ size_t phaser::test::countDifferences(Chromosome const& _chromosome1, Chromosome { size_t count = 0; for (size_t i = 0; i < min(_chromosome1.length(), _chromosome2.length()); ++i) - count += static_cast(_chromosome1.optimisationSteps()[i] != _chromosome2.optimisationSteps()[i]); + if (_chromosome1.optimisationSteps()[i] != _chromosome2.optimisationSteps()[i]) + ++count; - return count + abs(static_cast(_chromosome1.length() - _chromosome2.length())); + return count + static_cast(abs( + static_cast(_chromosome1.length()) - + static_cast(_chromosome2.length()) + )); } TemporaryDirectory::TemporaryDirectory(std::string const& _prefix): diff --git a/tools/solidityUpgrade/SourceUpgrade.cpp b/tools/solidityUpgrade/SourceUpgrade.cpp index 8c05ecc9fda2..7005fd336155 100644 --- a/tools/solidityUpgrade/SourceUpgrade.cpp +++ b/tools/solidityUpgrade/SourceUpgrade.cpp @@ -390,7 +390,7 @@ void SourceUpgrade::applyChange( void SourceUpgrade::printErrors() const { - auto formatter = make_unique(cout, true); + auto formatter = make_unique(cout, true, false); for (auto const& error: m_compiler->errors()) if (error->type() != langutil::Error::Type::Warning) diff --git a/tools/solidityUpgrade/UpgradeChange.cpp b/tools/solidityUpgrade/UpgradeChange.cpp index ff7d6d68f575..a897a4e130dc 100644 --- a/tools/solidityUpgrade/UpgradeChange.cpp +++ b/tools/solidityUpgrade/UpgradeChange.cpp @@ -36,7 +36,7 @@ void UpgradeChange::apply() void UpgradeChange::log(bool const _shorten) const { stringstream os; - SourceReferenceFormatterHuman formatter{os, true}; + SourceReferenceFormatterHuman formatter{os, true, false}; string start = to_string(m_location.start); string end = to_string(m_location.end); diff --git a/tools/yulPhaser/GeneticAlgorithms.cpp b/tools/yulPhaser/GeneticAlgorithms.cpp index 1da31645fd2e..4a90503aa1fd 100644 --- a/tools/yulPhaser/GeneticAlgorithms.cpp +++ b/tools/yulPhaser/GeneticAlgorithms.cpp @@ -155,7 +155,7 @@ Population ClassicGeneticAlgorithm::select(Population _population, size_t _selec vector selectedIndividuals; for (size_t i = 0; i < _selectionSize; ++i) { - uint32_t ball = SimulationRNG::uniformInt(0, rouletteRange - 1); + size_t ball = SimulationRNG::uniformInt(0, rouletteRange - 1); size_t cumulativeFitness = 0; for (auto const& individual: _population.individuals()) diff --git a/tools/yulPhaser/Mutations.cpp b/tools/yulPhaser/Mutations.cpp index 2b988e62206c..f2876e395ab9 100644 --- a/tools/yulPhaser/Mutations.cpp +++ b/tools/yulPhaser/Mutations.cpp @@ -126,12 +126,12 @@ ChromosomePair fixedPointSwap( return { Chromosome( - vector(begin1, begin1 + _crossoverPoint) + - vector(begin2 + _crossoverPoint, end2) + vector(begin1, begin1 + static_cast(_crossoverPoint)) + + vector(begin2 + static_cast(_crossoverPoint), end2) ), Chromosome( - vector(begin2, begin2 + _crossoverPoint) + - vector(begin1 + _crossoverPoint, end1) + vector(begin2, begin2 + static_cast(_crossoverPoint)) + + vector(begin1 + static_cast(_crossoverPoint), end1) ), }; } @@ -196,8 +196,8 @@ ChromosomePair fixedTwoPointSwap( assert(_crossoverPoint2 <= _chromosome1.length()); assert(_crossoverPoint2 <= _chromosome2.length()); - size_t lowPoint = min(_crossoverPoint1, _crossoverPoint2); - size_t highPoint = max(_crossoverPoint1, _crossoverPoint2); + auto lowPoint = static_cast(min(_crossoverPoint1, _crossoverPoint2)); + auto highPoint = static_cast(max(_crossoverPoint1, _crossoverPoint2)); auto begin1 = _chromosome1.optimisationSteps().begin(); auto begin2 = _chromosome2.optimisationSteps().begin(); @@ -282,17 +282,17 @@ ChromosomePair uniformSwap(Chromosome const& _chromosome1, Chromosome const& _ch if (_chromosome1.length() > minLength) { if (swapTail) - steps2.insert(steps2.end(), begin1 + minLength, end1); + steps2.insert(steps2.end(), begin1 + static_cast(minLength), end1); else - steps1.insert(steps1.end(), begin1 + minLength, end1); + steps1.insert(steps1.end(), begin1 + static_cast(minLength), end1); } if (_chromosome2.length() > minLength) { if (swapTail) - steps1.insert(steps1.end(), begin2 + minLength, end2); + steps1.insert(steps1.end(), begin2 + static_cast(minLength), end2); else - steps2.insert(steps2.end(), begin2 + minLength, end2); + steps2.insert(steps2.end(), begin2 + static_cast(minLength), end2); } return {Chromosome(steps1), Chromosome(steps2)}; diff --git a/tools/yulPhaser/PairSelections.cpp b/tools/yulPhaser/PairSelections.cpp index 7e744ff7053c..8934c3e1789c 100644 --- a/tools/yulPhaser/PairSelections.cpp +++ b/tools/yulPhaser/PairSelections.cpp @@ -30,7 +30,7 @@ vector> RandomPairSelection::materialise(size_t _poolSize) if (_poolSize < 2) return {}; - size_t count = static_cast(round(_poolSize * m_selectionSize)); + auto count = static_cast(round(_poolSize * m_selectionSize)); vector> selection; for (size_t i = 0; i < count; ++i) @@ -64,7 +64,10 @@ vector> PairsFromRandomSubset::materialise(size_t _poolSiz } while (selectedIndices.size() % 2 != 0); } else - selectedIndices.erase(selectedIndices.begin() + SimulationRNG::uniformInt(0, selectedIndices.size() - 1)); + selectedIndices.erase( + selectedIndices.begin() + + static_cast(SimulationRNG::uniformInt(0, selectedIndices.size() - 1)) + ); } assert(selectedIndices.size() % 2 == 0); @@ -73,14 +76,14 @@ vector> PairsFromRandomSubset::materialise(size_t _poolSiz { size_t position1 = SimulationRNG::uniformInt(0, selectedIndices.size() - 1); size_t value1 = selectedIndices[position1]; - selectedIndices.erase(selectedIndices.begin() + position1); + selectedIndices.erase(selectedIndices.begin() + static_cast(position1)); size_t position2 = SimulationRNG::uniformInt(0, selectedIndices.size() - 1); size_t value2 = selectedIndices[position2]; - selectedIndices.erase(selectedIndices.begin() + position2); + selectedIndices.erase(selectedIndices.begin() + static_cast(position2)); - selectedPairs.push_back({value1, value2}); + selectedPairs.emplace_back(value1, value2); } - assert(selectedIndices.size() == 0); + assert(selectedIndices.empty()); return selectedPairs; } diff --git a/tools/yulPhaser/SimulationRNG.cpp b/tools/yulPhaser/SimulationRNG.cpp index 2b596f4ed732..26f438909718 100644 --- a/tools/yulPhaser/SimulationRNG.cpp +++ b/tools/yulPhaser/SimulationRNG.cpp @@ -17,12 +17,17 @@ #include +// NOTE: The code would work with std::random but the results for a given seed would not be reproducible +// across different STL implementations. Boost does not guarantee this either but at least it has only one +// implementation. Reproducibility is not a hard requirement for yul-phaser but it's nice to have. #include #include #include #include +#include +using namespace std; using namespace solidity; using namespace solidity::phaser; @@ -30,21 +35,25 @@ thread_local boost::random::mt19937 SimulationRNG::s_generator(SimulationRNG::ge bool SimulationRNG::bernoulliTrial(double _successProbability) { - boost::random::bernoulli_distribution<> distribution(_successProbability); + boost::random::bernoulli_distribution distribution(_successProbability); - return static_cast(distribution(s_generator)); + return distribution(s_generator); } -uint32_t SimulationRNG::uniformInt(uint32_t _min, uint32_t _max) +size_t SimulationRNG::uniformInt(size_t _min, size_t _max) { - boost::random::uniform_int_distribution<> distribution(_min, _max); + boost::random::uniform_int_distribution distribution(_min, _max); return distribution(s_generator); } -uint32_t SimulationRNG::binomialInt(uint32_t _numTrials, double _successProbability) +size_t SimulationRNG::binomialInt(size_t _numTrials, double _successProbability) { - boost::random::binomial_distribution<> distribution(_numTrials, _successProbability); - return distribution(s_generator); + // NOTE: binomial_distribution would not work because it internally tries to use abs() + // and fails to compile due to ambiguous conversion. + assert(_numTrials <= static_cast(numeric_limits::max())); + + boost::random::binomial_distribution distribution(static_cast(_numTrials), _successProbability); + return static_cast(distribution(s_generator)); } uint32_t SimulationRNG::generateSeed() diff --git a/tools/yulPhaser/SimulationRNG.h b/tools/yulPhaser/SimulationRNG.h index 1e8a1da18b11..d16189f9ebca 100644 --- a/tools/yulPhaser/SimulationRNG.h +++ b/tools/yulPhaser/SimulationRNG.h @@ -38,8 +38,8 @@ class SimulationRNG { public: static bool bernoulliTrial(double _successProbability); - static uint32_t uniformInt(uint32_t _min, uint32_t _max); - static uint32_t binomialInt(uint32_t _numTrials, double _successProbability); + static size_t uniformInt(size_t _min, size_t _max); + static size_t binomialInt(size_t _numTrials, double _successProbability); /// Resets generator to a known state given by the @a seed. Given the same seed, a fixed /// sequence of calls to the members generating random values is guaranteed to produce the