diff --git a/Changelog.md b/Changelog.md index 65d11fdf4..5e35dc78e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -25,6 +25,9 @@ AST Changes: ### 0.7.5 (unreleased) +Language Features: + * Ability to select the abi coder using ``pragma abicoder v1`` and ``pragma abicoder v2``. + Compiler Features: * SMTChecker: Add division by zero checks in the CHC engine. * SMTChecker: Support ``selector`` for expressions with value known at compile-time. @@ -35,6 +38,10 @@ Bugfixes: * SMTChecker: Fix internal error on conversion from string literal to byte. * SMTChecker: Fix internal error when using tuples of rational literals inside the conditional operator. * SMTChecker: Fix internal error when assigning state variable via contract's name. + * SMTChecker: Fix incorrect counterexamples reported by the CHC engine. + * SMTChecker: Fix false negative in modifier applied multiple times. + * SMTChecker: Fix internal error in the BMC engine when inherited contract from a different source unit has private state variables. + * SMTChecker: Fix internal error when ``array.push()`` is used as the LHS of an assignment. * Code generator: Fix missing creation dependency tracking for abstract contracts. diff --git a/README.md b/README.md index 6696feabd..293cc2583 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # The Solidity Contract-Oriented Programming Language -You can talk to us on [![solidity at https://gitter.im/ethereum/solidity](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ethereum/solidity?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge). Questions, feedback and suggestions are welcome! +You can talk to us on [![solidity at https://gitter.im/ethereum/solidity](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ethereum/solidity?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge). Questions, feedback, and suggestions are welcome! Solidity is a statically typed, contract-oriented, high-level language for implementing smart contracts on the Ethereum platform. @@ -19,10 +19,10 @@ Solidity is a statically typed, contract-oriented, high-level language for imple Solidity is a statically-typed curly-braces programming language designed for developing smart contracts that run on the Ethereum Virtual Machine. Smart contracts are programs that are executed inside a peer-to-peer network where nobody has special authority over the execution, and thus they allow to implement tokens of value, -ownership, voting and other kinds of logics. +ownership, voting, and other kinds of logic. When deploying contracts, you should use the latest released version of -Solidity. This is because breaking changes as well as new features and bug fixes are +Solidity. This is because breaking changes, as well as new features and bug fixes are introduced regularly. We currently use a 0.x version number [to indicate this fast pace of change](https://semver.org/#spec-item-4). @@ -46,7 +46,7 @@ contract HelloWorld { } ``` -To get started with Solidity, you can use [Remix](https://remix.ethereum.org/), which is an +To get started with Solidity, you can use [Remix](https://remix.ethereum.org/), which is a browser-based IDE. Here are some example contracts: 1. [Voting](https://solidity.readthedocs.io/en/latest/solidity-by-example.html#voting) diff --git a/docs/060-breaking-changes.rst b/docs/060-breaking-changes.rst index 3173bca69..32397677c 100644 --- a/docs/060-breaking-changes.rst +++ b/docs/060-breaking-changes.rst @@ -132,7 +132,7 @@ Yul Optimizer Together with the legacy bytecode optimizer, the :doc:`Yul ` optimizer is now enabled by default when you call the compiler with ``--optimize``. It can be disabled by calling the compiler with ``--no-optimize-yul``. -This mostly affects code that uses ABIEncoderV2. +This mostly affects code that uses ABI coder v2. C API Changes ~~~~~~~~~~~~~ diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst index 9b0e6539b..f6bb208dc 100644 --- a/docs/abi-spec.rst +++ b/docs/abi-spec.rst @@ -589,8 +589,8 @@ As an example, the code :: // SPDX-License-Identifier: GPL-3.0 - pragma solidity >=0.4.19 <0.9.0; - pragma experimental ABIEncoderV2; + pragma solidity >0.7.4 <0.9.0; + pragma abicoder v2; contract Test { struct S { uint a; uint[] b; T[] c; } diff --git a/docs/contracts/functions.rst b/docs/contracts/functions.rst index 2c79d3578..cba3603ac 100644 --- a/docs/contracts/functions.rst +++ b/docs/contracts/functions.rst @@ -67,8 +67,8 @@ Function parameters can be used as any other local variable and they can also be An :ref:`external function` cannot accept a multi-dimensional array as an input - parameter. This functionality is possible if you enable the new - ``ABIEncoderV2`` feature by adding ``pragma experimental ABIEncoderV2;`` to your source file. + parameter. This functionality is possible if you enable the ABI coder v2 + by adding ``pragma abicoder v2;`` to your source file. An :ref:`internal function` can accept a multi-dimensional array without enabling the feature. @@ -128,8 +128,8 @@ you must provide return values together with the return statement. .. note:: You cannot return some types from non-internal functions, notably multi-dimensional dynamic arrays and structs. If you enable the - new ``ABIEncoderV2`` feature by adding ``pragma experimental - ABIEncoderV2;`` to your source file then more types are available, but + ABI coder v2 by adding ``pragma abicoder v2;`` + to your source file then more types are available, but ``mapping`` types are still limited to inside a single contract and you cannot transfer them. diff --git a/docs/installing-solidity.rst b/docs/installing-solidity.rst index 62ea63c6d..9a787b30b 100644 --- a/docs/installing-solidity.rst +++ b/docs/installing-solidity.rst @@ -239,7 +239,7 @@ For macOS builds, ensure that you have the latest version of `Xcode installed `_. This contains the `Clang C++ compiler `_, the `Xcode IDE `_ and other Apple development -tools which are required for building C++ applications on OS X. +tools that are required for building C++ applications on OS X. If you are installing Xcode for the first time, or have just installed a new version then you will need to agree to the license before you can do command-line builds: diff --git a/docs/layout-of-source-files.rst b/docs/layout-of-source-files.rst index 7c6b0c426..ea39e8a79 100644 --- a/docs/layout-of-source-files.rst +++ b/docs/layout-of-source-files.rst @@ -88,6 +88,41 @@ these follow the same syntax used by `npm `_ required by the pragma. If it does not match, the compiler issues an error. +ABI Coder Pragma +---------------- + +By using ``pragma abicoder v1`` or ``pragma abicoder v2`` you can +select between the two implementations of the ABI encoder and decoder. + +The new ABI coder (v2) is able to encode and decode arbitrarily nested +arrays and structs. It might produce less optimal code and has not +received as much testing as the old encoder, but is considered +non-experimental as of Solidity 0.6.0. You still have to explicitly +activate it using ``pragma abicoder v2;``. Since it will be +activated by default starting from Solidity 0.8.0, there is the option to select +the old coder using ``pragma abicoder v1;``. + +The set of types supported by the new encoder is a strict superset of +the ones supported by the old one. Contracts that use it can interact with ones +that do not without limitations. The reverse is possible only as long as the +non-``abicoder v2`` contract does not try to make calls that would require +decoding types only supported by the new encoder. The compiler can detect this +and will issue an error. Simply enabling ``abicoder v2`` for your contract is +enough to make the error go away. + +.. note:: + This pragma applies to all the code defined in the file where it is activated, + regardless of where that code ends up eventually. This means that a contract + whose source file is selected to compile with ABI coder v1 + can still contain code that uses the new encoder + by inheriting it from another contract. This is allowed if the new types are only + used internally and not in external function signatures. + +.. note:: + Up to Solidity 0.7.4, it was possible to select the ABI coder v2 + by using ``pragma experimental ABIEncoderV2``, but it was not possible + to explicitly select coder v1 because it was the default. + .. index:: ! pragma, experimental .. _experimental_pragma: @@ -103,28 +138,9 @@ The following experimental pragmas are currently supported: ABIEncoderV2 ~~~~~~~~~~~~ -The new ABI encoder is able to encode and decode arbitrarily nested -arrays and structs. It might produce less optimal code and has not -received as much testing as the old encoder, but is considered -non-experimental as of Solidity 0.6.0. You still have to explicitly -activate it using ``pragma experimental ABIEncoderV2;`` - we kept -the same pragma, even though it is not considered experimental -anymore. - -The set of types supported by the new encoder is a strict superset of -the ones supported by the old one. Contracts that use it can interact with ones -that do not without limitations. The reverse is possible only as long as the -non-``ABIEncoderV2`` contract does not try to make calls that would require -decoding types only supported by the new encoder. The compiler can detect this -and will issue an error. Simply enabling ``ABIEncoderV2`` for your contract is -enough to make the error go away. - -.. note:: - This pragma applies to all the code defined in the file where it is activated, - regardless of where that code ends up eventually. This means that a contract - without the ``ABIEncoderV2`` pragma can still contain code that uses the new encoder - by inheriting it from another contract. This is allowed if the new types are only - used internally and not in external function signatures. +Because the ABI coder v2 is not considered experimental anymore, +it can be selected via ``pragma abicoder v2`` (please see above) +since Solidity 0.7.4. .. _smt_checker: diff --git a/docs/security-considerations.rst b/docs/security-considerations.rst index 0ce93effc..fade26134 100644 --- a/docs/security-considerations.rst +++ b/docs/security-considerations.rst @@ -629,26 +629,32 @@ types. // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0; + pragma experimental ABIEncoderV2; pragma experimental SMTChecker; // This will report a warning contract Aliasing { - uint[] array; + uint[] array1; + uint[][] array2; function f( uint[] memory a, uint[] memory b, uint[][] memory c, uint[] storage d - ) internal view { - require(array[0] == 42); - require(a[0] == 2); - require(c[0][0] == 2); - require(d[0] == 2); + ) internal { + array1[0] = 42; + a[0] = 2; + c[0][0] = 2; b[0] = 1; // Erasing knowledge about memory references should not // erase knowledge about state variables. - assert(array[0] == 42); + assert(array1[0] == 42); + // However, an assignment to a storage reference will erase + // storage knowledge accordingly. + d[0] = 2; + // Fails as false positive because of the assignment above. + assert(array1[0] == 42); // Fails because `a == b` is possible. assert(a[0] == 2); // Fails because `c[i] == b` is possible. @@ -656,6 +662,14 @@ types. assert(d[0] == 2); assert(b[0] == 1); } + function g( + uint[] memory a, + uint[] memory b, + uint[][] memory c, + uint x + ) public { + f(a, b, c, array2[x]); + } } After the assignment to ``b[0]``, we need to clear knowledge about ``a`` since diff --git a/docs/types/reference-types.rst b/docs/types/reference-types.rst index 24db3781a..cedd2fd2a 100644 --- a/docs/types/reference-types.rst +++ b/docs/types/reference-types.rst @@ -290,7 +290,7 @@ Array Members .. note:: To use arrays of arrays in external (instead of public) functions, you need to - activate ABIEncoderV2. + activate ABI coder v2. .. note:: In EVM versions before Byzantium, it was not possible to access diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index e9e2247ff..8cfdc07c4 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -231,7 +231,7 @@ Input Description "cse": false, // Optimize representation of literal numbers and strings in code. "constantOptimizer": false, - // The new Yul optimizer. Mostly operates on the code of ABIEncoderV2 + // The new Yul optimizer. Mostly operates on the code of ABI coder v2 // and inline assembly. // It is activated together with the global optimizer setting // and can be deactivated here. @@ -321,8 +321,8 @@ Input Description // evm.deployedBytecode.immutableReferences - Map from AST ids to bytecode ranges that reference immutables // evm.methodIdentifiers - The list of function hashes // evm.gasEstimates - Function gas estimates - // ewasm.wast - eWASM S-expressions format (not supported at the moment) - // ewasm.wasm - eWASM binary format (not supported at the moment) + // ewasm.wast - Ewasm in WebAssembly S-expressions format + // ewasm.wasm - Ewasm in WebAssembly binary format // // Note that using a using `evm`, `evm.bytecode`, `ewasm`, etc. will select every // target part of that output. Additionally, `*` can be used as a wildcard to request everything. @@ -486,7 +486,7 @@ Output Description } } }, - // eWASM related outputs + // Ewasm related outputs "ewasm": { // S-expressions format "wast": "", diff --git a/docs/yul.rst b/docs/yul.rst index 1d0d414b5..5ab8eec1f 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -9,7 +9,7 @@ Yul Yul (previously also called JULIA or IULIA) is an intermediate language that can be compiled to bytecode for different backends. -Support for EVM 1.0, EVM 1.5 and eWASM is planned, and it is designed to +Support for EVM 1.0, EVM 1.5 and Ewasm is planned, and it is designed to be a usable common denominator of all three platforms. It can already be used in stand-alone mode and for "inline assembly" inside Solidity @@ -1028,7 +1028,7 @@ An example Yul Object is shown below: // executing code is the constructor code) size := datasize("runtime") offset := allocate(size) - // This will turn into a memory->memory copy for eWASM and + // This will turn into a memory->memory copy for Ewasm and // a codecopy for EVM datacopy(offset, dataoffset("runtime"), size) return(offset, size) diff --git a/libsolidity/analysis/ContractLevelChecker.cpp b/libsolidity/analysis/ContractLevelChecker.cpp index 84329c725..784c03d07 100644 --- a/libsolidity/analysis/ContractLevelChecker.cpp +++ b/libsolidity/analysis/ContractLevelChecker.cpp @@ -450,7 +450,7 @@ void ContractLevelChecker::checkLibraryRequirements(ContractDefinition const& _c void ContractLevelChecker::checkBaseABICompatibility(ContractDefinition const& _contract) { - if (_contract.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2)) + if (*_contract.sourceUnit().annotation().useABICoderV2) return; if (_contract.isLibrary()) @@ -469,7 +469,7 @@ void ContractLevelChecker::checkBaseABICompatibility(ContractDefinition const& _ { solAssert(func.second->hasDeclaration(), "Function has no declaration?!"); - if (!func.second->declaration().sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2)) + if (!*func.second->declaration().sourceUnit().annotation().useABICoderV2) continue; auto const& currentLoc = func.second->declaration().location(); @@ -489,9 +489,9 @@ void ContractLevelChecker::checkBaseABICompatibility(ContractDefinition const& _ errors, std::string("Contract \"") + _contract.name() + - "\" does not use ABIEncoderV2 but wants to inherit from a contract " + + "\" does not use ABI coder v2 but wants to inherit from a contract " + "which uses types that require it. " + - "Use \"pragma experimental ABIEncoderV2;\" for the inheriting contract as well to enable the feature." + "Use \"pragma abicoder v2;\" for the inheriting contract as well to enable the feature." ); } diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp index 0fc1fa4ab..e50e33ada 100644 --- a/libsolidity/analysis/SyntaxChecker.cpp +++ b/libsolidity/analysis/SyntaxChecker.cpp @@ -73,6 +73,8 @@ void SyntaxChecker::endVisit(SourceUnit const& _sourceUnit) // when reporting the warning, print the source name only m_errorReporter.warning(3420_error, {-1, -1, _sourceUnit.location().source}, errorString); } + if (!m_sourceUnit->annotation().useABICoderV2.set()) + m_sourceUnit->annotation().useABICoderV2 = false; m_sourceUnit = nullptr; } @@ -113,9 +115,45 @@ bool SyntaxChecker::visit(PragmaDirective const& _pragma) m_sourceUnit->annotation().experimentalFeatures.insert(feature); if (!ExperimentalFeatureWithoutWarning.count(feature)) m_errorReporter.warning(2264_error, _pragma.location(), "Experimental features are turned on. Do not use experimental features on live deployments."); + + if (feature == ExperimentalFeature::ABIEncoderV2) + { + if (m_sourceUnit->annotation().useABICoderV2.set()) + { + if (!*m_sourceUnit->annotation().useABICoderV2) + m_errorReporter.syntaxError( + 8273_error, + _pragma.location(), + "ABI coder v1 has already been selected through \"pragma abicoder v1\"." + ); + } + else + m_sourceUnit->annotation().useABICoderV2 = true; + } } } } + else if (_pragma.literals()[0] == "abicoder") + { + solAssert(m_sourceUnit, ""); + if ( + _pragma.literals().size() != 2 || + !set{"v1", "v2"}.count(_pragma.literals()[1]) + ) + m_errorReporter.syntaxError( + 2745_error, + _pragma.location(), + "Expected either \"pragma abicoder v1\" or \"pragma abicoder v2\"." + ); + else if (m_sourceUnit->annotation().useABICoderV2.set()) + m_errorReporter.syntaxError( + 3845_error, + _pragma.location(), + "ABI coder has already been selected for this source unit." + ); + else + m_sourceUnit->annotation().useABICoderV2 = (_pragma.literals()[1] == "v2"); + } else if (_pragma.literals()[0] == "solidity") { vector tokens(_pragma.tokens().begin() + 1, _pragma.tokens().end()); @@ -135,6 +173,7 @@ bool SyntaxChecker::visit(PragmaDirective const& _pragma) } else m_errorReporter.syntaxError(4936_error, _pragma.location(), "Unknown pragma \"" + _pragma.literals()[0] + "\""); + return true; } diff --git a/libsolidity/analysis/SyntaxChecker.h b/libsolidity/analysis/SyntaxChecker.h index 46f6c486e..ca36ed992 100644 --- a/libsolidity/analysis/SyntaxChecker.h +++ b/libsolidity/analysis/SyntaxChecker.h @@ -39,6 +39,7 @@ namespace solidity::frontend * - issues deprecation warnings for unary '+' * - issues deprecation warning for throw * - whether the msize instruction is used and the Yul optimizer is enabled at the same time. + * - selection of the ABI coder through pragmas. */ class SyntaxChecker: private ASTConstVisitor { diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 15d9bac5d..72ee13fd9 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -398,13 +398,13 @@ bool TypeChecker::visit(FunctionDefinition const& _function) m_errorReporter.typeError(4103_error, _var.location(), message); } else if ( - !experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2) && + !useABICoderV2() && !typeSupportedByOldABIEncoder(*type(_var), _function.libraryFunction()) ) { string message = - "This type is only supported in ABIEncoderV2. " - "Use \"pragma experimental ABIEncoderV2;\" to enable the feature."; + "This type is only supported in ABI coder v2. " + "Use \"pragma abicoder v2;\" to enable the feature."; if (_function.isConstructor()) message += " Alternatively, make the contract abstract and supply the " @@ -570,7 +570,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) else if (_variable.visibility() >= Visibility::Public) { FunctionType getter(_variable); - if (!experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2)) + if (!useABICoderV2()) { vector unsupportedTypes; for (auto const& param: getter.parameterTypes() + getter.returnParameterTypes()) @@ -580,9 +580,9 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) m_errorReporter.typeError( 2763_error, _variable.location(), - "The following types are only supported for getters in ABIEncoderV2: " + + "The following types are only supported for getters in ABI coder v2: " + joinHumanReadable(unsupportedTypes) + - ". Either remove \"public\" or use \"pragma experimental ABIEncoderV2;\" to enable the feature." + ". Either remove \"public\" or use \"pragma abicoder v2;\" to enable the feature." ); } if (!getter.interfaceFunctionType()) @@ -695,14 +695,14 @@ bool TypeChecker::visit(EventDefinition const& _eventDef) if (!type(*var)->interfaceType(false)) m_errorReporter.typeError(3417_error, var->location(), "Internal or recursive type is not allowed as event parameter type."); if ( - !experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2) && + !useABICoderV2() && !typeSupportedByOldABIEncoder(*type(*var), false /* isLibrary */) ) m_errorReporter.typeError( 3061_error, var->location(), - "This type is only supported in ABIEncoderV2. " - "Use \"pragma experimental ABIEncoderV2;\" to enable the feature." + "This type is only supported in ABI coder v2. " + "Use \"pragma abicoder v2;\" to enable the feature." ); } if (_eventDef.isAnonymous() && numIndexed > 4) @@ -1900,7 +1900,7 @@ void TypeChecker::typeCheckABIEncodeFunctions( bool const isPacked = _functionType->kind() == FunctionType::Kind::ABIEncodePacked; solAssert(_functionType->padArguments() != isPacked, "ABI function with unexpected padding"); - bool const abiEncoderV2 = experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2); + bool const abiEncoderV2 = useABICoderV2(); // Check for named arguments if (!_functionCall.names().empty()) @@ -2192,7 +2192,7 @@ void TypeChecker::typeCheckFunctionGeneralChecks( _functionType->kind() == FunctionType::Kind::Creation || _functionType->kind() == FunctionType::Kind::Event; - if (callRequiresABIEncoding && !experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2)) + if (callRequiresABIEncoding && !useABICoderV2()) { solAssert(!isVariadic, ""); solAssert(parameterTypes.size() == arguments.size(), ""); @@ -2208,8 +2208,8 @@ void TypeChecker::typeCheckFunctionGeneralChecks( 2443_error, paramArgMap[i]->location(), "The type of this parameter, " + parameterTypes[i]->toString(true) + ", " - "is only supported in ABIEncoderV2. " - "Use \"pragma experimental ABIEncoderV2;\" to enable the feature." + "is only supported in ABI coder v2. " + "Use \"pragma abicoder v2;\" to enable the feature." ); } @@ -2222,8 +2222,8 @@ void TypeChecker::typeCheckFunctionGeneralChecks( 2428_error, _functionCall.location(), "The type of return parameter " + toString(i + 1) + ", " + returnParameterTypes[i]->toString(true) + ", " - "is only supported in ABIEncoderV2. " - "Use \"pragma experimental ABIEncoderV2;\" to enable the feature." + "is only supported in ABI coder v2. " + "Use \"pragma abicoder v2;\" to enable the feature." ); } } @@ -2340,7 +2340,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) { returnTypes = typeCheckABIDecodeAndRetrieveReturnType( _functionCall, - experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2) + useABICoderV2() ); break; } @@ -3414,10 +3414,11 @@ void TypeChecker::requireLValue(Expression const& _expression, bool _ordinaryAss m_errorReporter.typeError(errorId, _expression.location(), description); } -bool TypeChecker::experimentalFeatureActive(ExperimentalFeature _feature) const +bool TypeChecker::useABICoderV2() const { solAssert(m_currentSourceUnit, ""); if (m_currentContract) solAssert(m_currentSourceUnit == &m_currentContract->sourceUnit(), ""); - return m_currentSourceUnit->annotation().experimentalFeatures.count(_feature); + return *m_currentSourceUnit->annotation().useABICoderV2; + } diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h index fdbcb11b4..d75bb8a57 100644 --- a/libsolidity/analysis/TypeChecker.h +++ b/libsolidity/analysis/TypeChecker.h @@ -168,7 +168,7 @@ private: /// 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); - bool experimentalFeatureActive(ExperimentalFeature _feature) const; + bool useABICoderV2() const; /// @returns the current scope that can have function or type definitions. /// This is either a contract or a source unit. diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 8943dc745..3c4e48890 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -84,16 +84,6 @@ TypePointer ImportDirective::type() const return TypeProvider::module(*annotation().sourceUnit); } -vector ContractDefinition::stateVariablesIncludingInherited() const -{ - vector stateVars; - for (auto const& contract: annotation().linearizedBaseContracts) - for (auto var: contract->stateVariables()) - if (*contract == *this || var->isVisibleInDerivedContracts()) - stateVars.push_back(var); - return stateVars; -} - bool ContractDefinition::derivesFrom(ContractDefinition const& _base) const { return util::contains(annotation().linearizedBaseContracts, &_base); diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index a4d1f1654..5894fa9cd 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -500,7 +500,6 @@ public: std::vector definedStructs() const { return filteredNodes(m_subNodes); } std::vector definedEnums() const { return filteredNodes(m_subNodes); } std::vector stateVariables() const { return filteredNodes(m_subNodes); } - std::vector stateVariablesIncludingInherited() const; std::vector functionModifiers() const { return filteredNodes(m_subNodes); } std::vector definedFunctions() const { return filteredNodes(m_subNodes); } std::vector events() const { return filteredNodes(m_subNodes); } diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index 3f65f0280..b370d54d5 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -94,6 +94,7 @@ struct SourceUnitAnnotation: ASTAnnotation SetOnce>> exportedSymbols; /// Experimental features. std::set experimentalFeatures; + SetOnce useABICoderV2; }; struct ScopableAnnotation diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp index 97b9bb9e0..8554621bf 100644 --- a/libsolidity/codegen/ArrayUtils.cpp +++ b/libsolidity/codegen/ArrayUtils.cpp @@ -1172,7 +1172,7 @@ void ArrayUtils::accessCallDataArrayElement(ArrayType const& _arrayType, bool _d if ( !_arrayType.isByteArray() && _arrayType.baseType()->storageBytes() < 32 && - m_context.experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2) + m_context.useABICoderV2() ) { m_context << u256(32); diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index 5402d46ff..f6f7aacc1 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -77,11 +77,8 @@ public: langutil::EVMVersion const& evmVersion() const { return m_evmVersion; } - /// Update currently enabled set of experimental features. - void setExperimentalFeatures(std::set const& _features) { m_experimentalFeatures = _features; } - std::set const& experimentalFeaturesActive() const { return m_experimentalFeatures; } - /// @returns true if the given feature is enabled. - bool experimentalFeatureActive(ExperimentalFeature _feature) const { return m_experimentalFeatures.count(_feature); } + void setUseABICoderV2(bool _value) { m_useABICoderV2 = _value; } + bool useABICoderV2() const { return m_useABICoderV2; } void addStateVariable(VariableDeclaration const& _declaration, u256 const& _storageOffset, unsigned _byteOffset); void addImmutable(VariableDeclaration const& _declaration); @@ -365,8 +362,7 @@ private: /// Version of the EVM to compile against. langutil::EVMVersion m_evmVersion; RevertStrings const m_revertStrings; - /// Activated experimental features. - std::set m_experimentalFeatures; + bool m_useABICoderV2 = false; /// Other already compiled contracts to be used in contract creation calls. std::map> m_otherCompilers; /// Storage offsets of state variables diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index da6477b64..07cb3b4ca 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -230,7 +230,7 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMemory) { /// Stack: - if (m_context.experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2)) + if (m_context.useABICoderV2()) { // Use the new Yul-based decoding function auto stackHeightBefore = m_context.stackHeight(); @@ -412,7 +412,7 @@ void CompilerUtils::encodeToMemory( ) { // stack: ... - bool const encoderV2 = m_context.experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2); + bool const encoderV2 = m_context.useABICoderV2(); TypePointers targetTypes = _targetTypes.empty() ? _givenTypes : _targetTypes; solAssert(targetTypes.size() == _givenTypes.size(), ""); for (TypePointer& t: targetTypes) diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 6b1d2a292..bed30f124 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -127,7 +127,7 @@ void ContractCompiler::initializeContext( map> const& _otherCompilers ) { - m_context.setExperimentalFeatures(_contract.sourceUnit().annotation().experimentalFeatures); + m_context.setUseABICoderV2(*_contract.sourceUnit().annotation().useABICoderV2); m_context.setOtherCompilers(_otherCompilers); m_context.setMostDerivedContract(_contract); if (m_runtimeCompiler) @@ -1349,13 +1349,13 @@ void ContractCompiler::appendModifierOrFunctionCode() { m_context.setArithmetic(Arithmetic::Checked); - std::set experimentalFeaturesOutside = m_context.experimentalFeaturesActive(); - m_context.setExperimentalFeatures(codeBlock->sourceUnit().annotation().experimentalFeatures); + bool coderV2Outside = m_context.useABICoderV2(); + m_context.setUseABICoderV2(*codeBlock->sourceUnit().annotation().useABICoderV2); m_returnTags.emplace_back(m_context.newTag(), m_context.stackHeight()); codeBlock->accept(*this); - m_context.setExperimentalFeatures(experimentalFeaturesOutside); + m_context.setUseABICoderV2(coderV2Outside); solAssert(!m_returnTags.empty(), ""); m_context << m_returnTags.back().first; diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 6b7a3b71a..0d36fa7de 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1676,7 +1676,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) { solAssert(memberType->calldataEncodedSize() > 0, ""); solAssert(memberType->storageBytes() <= 32, ""); - if (memberType->storageBytes() < 32 && m_context.experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2)) + if (memberType->storageBytes() < 32 && m_context.useABICoderV2()) { m_context << u256(32); CompilerUtils(m_context).abiDecodeV2({memberType}, false); @@ -2522,7 +2522,7 @@ void ExpressionCompiler::appendExternalFunctionCall( // memory pointer), but kept references to the return data for // (statically-sized) arrays bool needToUpdateFreeMemoryPtr = false; - if (dynamicReturnSize || m_context.experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2)) + if (dynamicReturnSize || m_context.useABICoderV2()) needToUpdateFreeMemoryPtr = true; else for (auto const& retType: returnTypes) diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 7005d2b36..86fed77cd 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -1556,13 +1556,14 @@ string YulUtilFunctions::clearStorageStructFunction(StructType const& _type) }); } -string YulUtilFunctions::copyArrayToStorage(ArrayType const& _fromType, ArrayType const& _toType) +string YulUtilFunctions::copyArrayToStorageFunction(ArrayType const& _fromType, ArrayType const& _toType) { solAssert( *_fromType.copyForLocation(_toType.location(), _toType.isPointer()) == dynamic_cast(_toType), "" ); - solUnimplementedAssert(!_fromType.isByteArray(), ""); + if (_fromType.isByteArray()) + return copyByteArrayToStorageFunction(_fromType, _toType); solUnimplementedAssert(!_fromType.dataStoredIn(DataLocation::Storage), ""); string functionName = "copy_array_to_storage_from_" + _fromType.identifier() + "_to_" + _toType.identifier(); @@ -1655,6 +1656,84 @@ string YulUtilFunctions::copyArrayToStorage(ArrayType const& _fromType, ArrayTyp }); } + +string YulUtilFunctions::copyByteArrayToStorageFunction(ArrayType const& _fromType, ArrayType const& _toType) +{ + solAssert( + *_fromType.copyForLocation(_toType.location(), _toType.isPointer()) == dynamic_cast(_toType), + "" + ); + solAssert(_fromType.isByteArray(), ""); + solAssert(_toType.isByteArray(), ""); + solUnimplementedAssert(!_fromType.dataStoredIn(DataLocation::Storage), ""); + + string functionName = "copy_byte_array_to_storage_from_" + _fromType.identifier() + "_to_" + _toType.identifier(); + return m_functionCollector.createFunction(functionName, [&](){ + Whiskers templ(R"( + function (slot, src, len) { + let newLen := (src, len) + // Make sure array length is sane + if gt(newLen, 0xffffffffffffffff) { () } + + let oldLen := (sload(slot)) + + + src := add(src, 0x20) + + + // This is not needed in all branches. + let dstDataArea + if or(gt(oldLen, 31), gt(newLen, 31)) { + dstDataArea := (slot) + } + + if gt(oldLen, 31) { + // potentially truncate data + let deleteStart := add(dstDataArea, div(add(newLen, 31), 32)) + if lt(newLen, 32) { deleteStart := dstDataArea } + (deleteStart, add(dstDataArea, div(add(oldLen, 31), 32))) + } + switch gt(newLen, 31) + case 1 { + let loopEnd := and(newLen, not(0x1f)) + let dstPtr := dstDataArea + let i := 0 + for { } lt(i, loopEnd) { i := add(i, 32) } { + sstore(dstPtr, (add(src, i))) + dstPtr := add(dstPtr, 1) + } + if lt(loopEnd, newLen) { + let lastValue := (add(src, i)) + sstore(dstPtr, (lastValue, and(newLen, 0x1f))) + } + sstore(slot, add(mul(newLen, 2), 1)) + } + default { + let value := 0 + if newLen { + value := (src) + } + sstore(slot, (value, newLen)) + } + } + )"); + templ("functionName", functionName); + bool fromCalldata = _fromType.dataStoredIn(DataLocation::CallData); + templ("fromMemory", _fromType.dataStoredIn(DataLocation::Memory)); + templ("fromCalldata", fromCalldata); + templ("arrayLength", arrayLengthFunction(_fromType)); + templ("panic", panicFunction(PanicCode::ResourceError)); + templ("byteArrayLength", extractByteArrayLengthFunction()); + templ("dstDataLocation", arrayDataAreaFunction(_toType)); + templ("clearStorageRange", clearStorageRangeFunction(*_toType.baseType())); + templ("readFromCalldataOrMemory", readFromMemoryOrCalldata(*TypeProvider::uint256(), fromCalldata)); + templ("maskBytes", maskBytesFunctionDynamic()); + templ("byteArrayCombineShort", shortByteArrayEncodeUsedAreaSetLengthFunction()); + + return templ.render(); + }); +} + string YulUtilFunctions::arrayConvertLengthToSize(ArrayType const& _type) { string functionName = "array_convert_length_to_size_" + _type.identifier(); @@ -2207,8 +2286,9 @@ string YulUtilFunctions::updateStorageValueFunction( solAssert(_toType.storageBytes() > 0, "Invalid storage bytes size."); return Whiskers(R"( - function (slot, value) { - sstore(slot, (sload(slot), (value))) + function (slot, ) { + let := () + sstore(slot, (sload(slot), ())) } )") @@ -2219,6 +2299,9 @@ string YulUtilFunctions::updateStorageValueFunction( updateByteSliceFunctionDynamic(_toType.storageBytes()) ) ("offset", _offset.has_value() ? "" : "offset, ") + ("convert", conversionFunction(_fromType, _toType)) + ("fromValues", suffixedVariableNameList("value_", 0, _fromType.sizeOnStack())) + ("toValues", suffixedVariableNameList("convertedValue_", 0, _toType.sizeOnStack())) ("prepare", prepareStoreFunction(_toType)) .render(); } @@ -2248,7 +2331,7 @@ string YulUtilFunctions::updateStorageValueFunction( )"); templ("functionName", functionName); templ("value", suffixedVariableNameList("value_", 0, _fromType.sizeOnStack())); - templ("copyArrayToStorage", copyArrayToStorage( + templ("copyArrayToStorage", copyArrayToStorageFunction( dynamic_cast(_fromType), dynamic_cast(_toType) )); @@ -2478,9 +2561,16 @@ string YulUtilFunctions::cleanupFromStorageFunction(Type const& _type, bool _spl return templ.render(); } + bool leftAligned = false; + if ( + _type.category() != Type::Category::Function || + dynamic_cast(_type).kind() == FunctionType::Kind::External + ) + leftAligned = _type.leftAligned(); + if (storageBytes == 32) templ("cleaned", "value"); - else if (_type.leftAligned()) + else if (leftAligned) templ("cleaned", shiftLeftFunction(256 - 8 * storageBytes) + "(value)"); else templ("cleaned", "and(value, " + toCompactHexWithPrefix((u256(1) << (8 * storageBytes)) - 1) + ")"); @@ -2491,7 +2581,8 @@ string YulUtilFunctions::cleanupFromStorageFunction(Type const& _type, bool _spl string YulUtilFunctions::prepareStoreFunction(Type const& _type) { - solUnimplementedAssert(_type.category() != Type::Category::Function, ""); + if (_type.category() == Type::Category::Function) + solUnimplementedAssert(dynamic_cast(_type).kind() == FunctionType::Kind::Internal, ""); string functionName = "prepare_store_" + _type.identifier(); return m_functionCollector.createFunction(functionName, [&]() { @@ -2718,12 +2809,13 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) _to.identifier(); return m_functionCollector.createFunction(functionName, [&]() { return Whiskers(R"( - function (addr, functionId) -> outAddr, outFunctionId { - outAddr := addr + function (addr, functionId) -> outAddr, outFunctionId { + outAddr := addr outFunctionId := functionId } )") ("functionName", functionName) + ("external", fromType.kind() == FunctionType::Kind::External) .render(); }); } diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index 41f586595..06ed376e7 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -205,7 +205,11 @@ public: /// @returns the name of a function that will copy array from calldata or memory to storage /// signature (to_slot, from_ptr) -> - std::string copyArrayToStorage(ArrayType const& _fromType, ArrayType const& _toType); + std::string copyArrayToStorageFunction(ArrayType const& _fromType, ArrayType const& _toType); + + /// @returns the name of a function that will copy a byte array from calldata or memory to storage + /// signature (to_slot, from_ptr) -> + std::string copyByteArrayToStorageFunction(ArrayType const& _fromType, ArrayType const& _toType); /// Returns the name of a function that will convert a given length to the /// size in memory (number of storage slots or calldata/memory bytes) it diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index e7b8fe071..9ce8f1fab 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -425,7 +425,7 @@ bool IRGeneratorForStatements::visit(TupleExpression const& _tuple) "(" << ("add(" + mpos + ", " + to_string(i * arrayType.memoryStride()) + ")") << ", " << - converted.name() << + converted.commaSeparatedList() << ")\n"; } } @@ -2543,47 +2543,50 @@ string IRGeneratorForStatements::binaryOperation( !TokenTraits::isShiftOp(_operator), "Have to use specific shift operation function for shifts." ); - if (IntegerType const* type = dynamic_cast(&_type)) + string fun; + if (TokenTraits::isBitOp(_operator)) { - string fun; + solAssert( + _type.category() == Type::Category::Integer || + _type.category() == Type::Category::FixedBytes, + ""); + switch (_operator) + { + case Token::BitOr: fun = "or"; break; + case Token::BitXor: fun = "xor"; break; + case Token::BitAnd: fun = "and"; break; + default: break; + } + } + else if (TokenTraits::isArithmeticOp(_operator)) + { + IntegerType const* type = dynamic_cast(&_type); + solAssert(type, ""); bool checked = m_context.arithmetic() == Arithmetic::Checked; switch (_operator) { - case Token::Add: - fun = checked ? m_utils.overflowCheckedIntAddFunction(*type) : m_utils.wrappingIntAddFunction(*type); - break; - case Token::Sub: - fun = checked ? m_utils.overflowCheckedIntSubFunction(*type) : m_utils.wrappingIntSubFunction(*type); - break; - case Token::Mul: - fun = checked ? m_utils.overflowCheckedIntMulFunction(*type) : m_utils.wrappingIntMulFunction(*type); - break; - case Token::Div: - fun = checked ? m_utils.overflowCheckedIntDivFunction(*type) : m_utils.wrappingIntDivFunction(*type); - break; - case Token::Mod: - fun = m_utils.intModFunction(*type); - break; - case Token::BitOr: - fun = "or"; - break; - case Token::BitXor: - fun = "xor"; - break; - case Token::BitAnd: - fun = "and"; - break; - default: - break; + case Token::Add: + fun = checked ? m_utils.overflowCheckedIntAddFunction(*type) : m_utils.wrappingIntAddFunction(*type); + break; + case Token::Sub: + fun = checked ? m_utils.overflowCheckedIntSubFunction(*type) : m_utils.wrappingIntSubFunction(*type); + break; + case Token::Mul: + fun = checked ? m_utils.overflowCheckedIntMulFunction(*type) : m_utils.wrappingIntMulFunction(*type); + break; + case Token::Div: + fun = checked ? m_utils.overflowCheckedIntDivFunction(*type) : m_utils.wrappingIntDivFunction(*type); + break; + case Token::Mod: + fun = m_utils.intModFunction(*type); + break; + default: + break; } - - solUnimplementedAssert(!fun.empty(), ""); - return fun + "(" + _left + ", " + _right + ")\n"; } - else - solUnimplementedAssert(false, ""); - return {}; + solUnimplementedAssert(!fun.empty(), "Type: " + _type.toString()); + return fun + "(" + _left + ", " + _right + ")\n"; } std::string IRGeneratorForStatements::shiftOperation( diff --git a/libsolidity/formal/CHC.cpp b/libsolidity/formal/CHC.cpp index e10785093..87f5ad1b8 100644 --- a/libsolidity/formal/CHC.cpp +++ b/libsolidity/formal/CHC.cpp @@ -134,7 +134,7 @@ void CHC::endVisit(ContractDefinition const& _contract) setCurrentBlock(*m_constructorSummaryPredicate); - addAssertVerificationTarget(m_currentContract, m_currentBlock, smtutil::Expression(true), errorFlag().currentValue()); + m_queryPlaceholders[&_contract].push_back({smtutil::Expression(true), errorFlag().currentValue(), m_currentBlock}); connectBlocks(m_currentBlock, interface(), errorFlag().currentValue() == 0); SMTEncoder::endVisit(_contract); @@ -231,16 +231,14 @@ void CHC::endVisit(FunctionDefinition const& _function) auto assertionError = errorFlag().currentValue(); auto sum = summary(_function); connectBlocks(m_currentBlock, sum); - auto iface = interface(); - setCurrentBlock(*m_interfaces.at(m_currentContract)); auto ifacePre = smt::interfacePre(*m_interfaces.at(m_currentContract), *m_currentContract, m_context); if (_function.isPublic()) { auto txConstraints = m_context.state().txConstraints(_function); - addAssertVerificationTarget(&_function, ifacePre, txConstraints && sum, assertionError); + m_queryPlaceholders[&_function].push_back({txConstraints && sum, assertionError, ifacePre}); connectBlocks(ifacePre, iface, txConstraints && sum && (assertionError == 0)); } } @@ -512,30 +510,15 @@ void CHC::visitAssert(FunctionCall const& _funCall) solAssert(m_currentContract, ""); solAssert(m_currentFunction, ""); - if (m_currentFunction->isConstructor()) - m_functionAssertions[m_currentContract].insert(&_funCall); - else - m_functionAssertions[m_currentFunction].insert(&_funCall); - - auto previousError = errorFlag().currentValue(); - errorFlag().increaseIndex(); - - connectBlocks( - m_currentBlock, - m_currentFunction->isConstructor() ? summary(*m_currentContract) : summary(*m_currentFunction), - currentPathConditions() && !m_context.expression(*args.front())->currentValue() && ( - errorFlag().currentValue() == newErrorId(_funCall) - ) - ); - - m_context.addAssertion(errorFlag().currentValue() == previousError); + auto errorCondition = !m_context.expression(*args.front())->currentValue(); + verificationTargetEncountered(&_funCall, VerificationTarget::Type::Assert, errorCondition); } void CHC::visitAddMulMod(FunctionCall const& _funCall) { solAssert(_funCall.arguments().at(2), ""); - addVerificationTarget(_funCall, VerificationTarget::Type::DivByZero, expr(*_funCall.arguments().at(2)) == 0); + verificationTargetEncountered(&_funCall, VerificationTarget::Type::DivByZero, expr(*_funCall.arguments().at(2)) == 0); SMTEncoder::visitAddMulMod(_funCall); } @@ -634,7 +617,7 @@ void CHC::makeArrayPopVerificationTarget(FunctionCall const& _arrayPop) auto symbArray = dynamic_pointer_cast(m_context.expression(memberAccess->expression())); solAssert(symbArray, ""); - addVerificationTarget(_arrayPop, VerificationTarget::Type::PopEmptyArray, symbArray->length() <= 0); + verificationTargetEncountered(&_arrayPop, VerificationTarget::Type::PopEmptyArray, symbArray->length() <= 0); } pair CHC::arithmeticOperation( @@ -646,7 +629,7 @@ pair CHC::arithmeticOperation( ) { if (_op == Token::Mod || _op == Token::Div) - addVerificationTarget(_expression, VerificationTarget::Type::DivByZero, _right == 0); + verificationTargetEncountered(&_expression, VerificationTarget::Type::DivByZero, _right == 0); auto values = SMTEncoder::arithmeticOperation(_op, _left, _right, _commonType, _expression); @@ -662,16 +645,16 @@ pair CHC::arithmeticOperation( return values; if (_op == Token::Div) - addVerificationTarget(_expression, VerificationTarget::Type::Overflow, values.second > intType->maxValue()); + verificationTargetEncountered(&_expression, VerificationTarget::Type::Overflow, values.second > intType->maxValue()); else if (intType->isSigned()) { - addVerificationTarget(_expression, VerificationTarget::Type::Underflow, values.second < intType->minValue()); - addVerificationTarget(_expression, VerificationTarget::Type::Overflow, values.second > intType->maxValue()); + verificationTargetEncountered(&_expression, VerificationTarget::Type::Underflow, values.second < intType->minValue()); + verificationTargetEncountered(&_expression, VerificationTarget::Type::Overflow, values.second > intType->maxValue()); } else if (_op == Token::Sub) - addVerificationTarget(_expression, VerificationTarget::Type::Underflow, values.second < intType->minValue()); + verificationTargetEncountered(&_expression, VerificationTarget::Type::Underflow, values.second < intType->minValue()); else if (_op == Token::Add || _op == Token::Mul) - addVerificationTarget(_expression, VerificationTarget::Type::Overflow, values.second > intType->maxValue()); + verificationTargetEncountered(&_expression, VerificationTarget::Type::Overflow, values.second > intType->maxValue()); else solAssert(false, ""); return values; @@ -679,11 +662,11 @@ pair CHC::arithmeticOperation( void CHC::resetSourceAnalysis() { - m_verificationTargets.clear(); m_safeTargets.clear(); m_unsafeTargets.clear(); - m_functionAssertions.clear(); - m_errorIds.clear(); + m_functionTargetIds.clear(); + m_verificationTargets.clear(); + m_queryPlaceholders.clear(); m_callGraph.clear(); m_summaries.clear(); m_interfaces.clear(); @@ -713,6 +696,7 @@ void CHC::resetSourceAnalysis() } m_context.clear(); + m_context.resetUniqueId(); m_context.setAssertionAccumulation(false); } @@ -759,15 +743,15 @@ void CHC::setCurrentBlock(Predicate const& _block) m_currentBlock = predicate(_block); } -set CHC::transactionAssertions(ASTNode const* _txRoot) +set CHC::transactionVerificationTargetsIds(ASTNode const* _txRoot) { - set assertions; + set verificationTargetsIds; solidity::util::BreadthFirstSearch{{_txRoot}}.run([&](auto const* function, auto&& _addChild) { - assertions.insert(m_functionAssertions[function].begin(), m_functionAssertions[function].end()); + verificationTargetsIds.insert(m_functionTargetIds[function].begin(), m_functionTargetIds[function].end()); for (auto const* called: m_callGraph[function]) _addChild(called); }); - return assertions; + return verificationTargetsIds; } SortPointer CHC::sort(FunctionDefinition const& _function) @@ -1101,186 +1085,171 @@ pair CHC::query(smtutil::Expression c return {result, cex}; } -void CHC::addVerificationTarget( - ASTNode const* _scope, +void CHC::verificationTargetEncountered( + ASTNode const* const _errorNode, VerificationTarget::Type _type, - smtutil::Expression _from, - smtutil::Expression _constraints, - smtutil::Expression _errorId + smtutil::Expression const& _errorCondition ) { solAssert(m_currentContract || m_currentFunction, ""); - SourceUnit const* source = nullptr; - if (m_currentContract) - source = sourceUnitContaining(*m_currentContract); - else - source = sourceUnitContaining(*m_currentFunction); + SourceUnit const* source = m_currentContract ? sourceUnitContaining(*m_currentContract) : sourceUnitContaining(*m_currentFunction); solAssert(source, ""); if (!source->annotation().experimentalFeatures.count(ExperimentalFeature::SMTChecker)) return; - m_verificationTargets[_scope].push_back(CHCVerificationTarget{{_type, _from, _constraints}, _errorId}); -} - -void CHC::addVerificationTarget(ASTNode const* _scope, VerificationTarget::Type _type, smtutil::Expression _errorId) -{ - solAssert(m_currentContract, ""); - - if (!m_currentFunction || m_currentFunction->isConstructor()) - addVerificationTarget(_scope, _type, summary(*m_currentContract), smtutil::Expression(true), _errorId); + bool scopeIsFunction = m_currentFunction && !m_currentFunction->isConstructor(); + auto errorId = newErrorId(); + solAssert(m_verificationTargets.count(errorId) == 0, "Error ID is not unique!"); + m_verificationTargets.emplace(errorId, CHCVerificationTarget{{_type, _errorCondition, smtutil::Expression(true)}, errorId, _errorNode}); + if (scopeIsFunction) + m_functionTargetIds[m_currentFunction].push_back(errorId); else - { - auto iface = smt::interfacePre(*m_interfaces.at(m_currentContract), *m_currentContract, m_context); - auto sum = summary(*m_currentFunction); - addVerificationTarget(_scope, _type, iface, sum, _errorId); - } -} - -void CHC::addVerificationTarget(frontend::Expression const& _scope, VerificationTarget::Type _type, smtutil::Expression const& _target) -{ + m_functionTargetIds[m_currentContract].push_back(errorId); auto previousError = errorFlag().currentValue(); errorFlag().increaseIndex(); - addVerificationTarget(&_scope, _type, errorFlag().currentValue()); - m_context.addAssertion( - errorFlag().currentValue() == previousError || - (_target && errorFlag().currentValue() == newErrorId(_scope)) + // create an error edge to the summary + connectBlocks( + m_currentBlock, + scopeIsFunction ? summary(*m_currentFunction) : summary(*m_currentContract), + currentPathConditions() && _errorCondition && errorFlag().currentValue() == errorId ); -} -void CHC::addAssertVerificationTarget(ASTNode const* _scope, smtutil::Expression _from, smtutil::Expression _constraints, smtutil::Expression _errorId) -{ - addVerificationTarget(_scope, VerificationTarget::Type::Assert, _from, _constraints, _errorId); + m_context.addAssertion(errorFlag().currentValue() == previousError); } void CHC::checkVerificationTargets() { - for (auto const& [scope, targets]: m_verificationTargets) + // The verification conditions have been collected per function where they have been encountered (m_verificationTargets). + // Also, all possible contexts in which an external function can be called has been recorded (m_queryPlaceholders). + // Here we combine every context in which an external function can be called with all possible verification conditions + // in its call graph. Each such combination forms a unique verification target. + vector verificationTargets; + for (auto const& [function, placeholders]: m_queryPlaceholders) { - for (size_t i = 0; i < targets.size(); ++i) - { - auto const& target = targets[i]; - - if (target.type == VerificationTarget::Type::Assert) - checkAssertTarget(scope, target); - else + auto functionTargets = transactionVerificationTargetsIds(function); + for (auto const& placeholder: placeholders) + for (unsigned id: functionTargets) { - string satMsg; - string satMsgUnderflow; - string satMsgOverflow; - string unknownMsg; - ErrorId errorReporterId; - ErrorId underflowErrorId = 3944_error; - ErrorId overflowErrorId = 4984_error; + auto const& target = m_verificationTargets.at(id); + verificationTargets.push_back(CHCVerificationTarget{ + {target.type, placeholder.fromPredicate, placeholder.constraints && placeholder.errorExpression == target.errorId}, + target.errorId, + target.errorNode + }); + } + } - if (target.type == VerificationTarget::Type::PopEmptyArray) - { - solAssert(dynamic_cast(scope), ""); - satMsg = "Empty array \"pop\" detected here."; - unknownMsg = "Empty array \"pop\" might happen here."; - errorReporterId = 2529_error; - } - else if ( - target.type == VerificationTarget::Type::Underflow || - target.type == VerificationTarget::Type::Overflow - ) - { - auto const* expr = dynamic_cast(scope); - solAssert(expr, ""); - auto const* intType = dynamic_cast(expr->annotation().type); - if (!intType) - intType = TypeProvider::uint256(); + set checkedErrorIds; + for (auto const& target: verificationTargets) + { + string errorType; + ErrorId errorReporterId; - satMsgUnderflow = "Underflow (resulting value less than " + formatNumberReadable(intType->minValue()) + ")"; - satMsgOverflow = "Overflow (resulting value larger than " + formatNumberReadable(intType->maxValue()) + ")"; - if (target.type == VerificationTarget::Type::Underflow) - { - satMsg = satMsgUnderflow + " happens here."; - unknownMsg = satMsgUnderflow + " might happen here."; - errorReporterId = underflowErrorId; - } - else if (target.type == VerificationTarget::Type::Overflow) - { - satMsg = satMsgOverflow + " happens here."; - unknownMsg = satMsgOverflow + " might happen here."; - errorReporterId = overflowErrorId; - } - } - else if (target.type == VerificationTarget::Type::DivByZero) - { - satMsg = "Division by zero happens here."; - unknownMsg = "Division by zero might happen here."; - errorReporterId = 4281_error; - } - else - solAssert(false, ""); + if (target.type == VerificationTarget::Type::PopEmptyArray) + { + solAssert(dynamic_cast(target.errorNode), ""); + errorType = "Empty array \"pop\""; + errorReporterId = 2529_error; + } + else if ( + target.type == VerificationTarget::Type::Underflow || + target.type == VerificationTarget::Type::Overflow + ) + { + auto const* expr = dynamic_cast(target.errorNode); + solAssert(expr, ""); + auto const* intType = dynamic_cast(expr->annotation().type); + if (!intType) + intType = TypeProvider::uint256(); - auto it = m_errorIds.find(scope->id()); - solAssert(it != m_errorIds.end(), ""); - solAssert(i < it->second.size(), ""); - unsigned errorId = it->second[i]; - - checkAndReportTarget(scope, target, errorId, errorReporterId, satMsg, unknownMsg); + if (target.type == VerificationTarget::Type::Underflow) + { + errorType = "Underflow (resulting value less than " + formatNumberReadable(intType->minValue()) + ")"; + errorReporterId = 3944_error; + } + else if (target.type == VerificationTarget::Type::Overflow) + { + errorType = "Overflow (resulting value larger than " + formatNumberReadable(intType->maxValue()) + ")"; + errorReporterId = 4984_error; } } - } -} + else if (target.type == VerificationTarget::Type::DivByZero) + { + errorType = "Division by zero"; + errorReporterId = 4281_error; + } + else if (target.type == VerificationTarget::Type::Assert) + { + errorType = "Assertion violation"; + errorReporterId = 6328_error; + } + else + solAssert(false, ""); -void CHC::checkAssertTarget(ASTNode const* _scope, CHCVerificationTarget const& _target) -{ - solAssert(_target.type == VerificationTarget::Type::Assert, ""); - auto assertions = transactionAssertions(_scope); - for (auto const* assertion: assertions) - { - auto it = m_errorIds.find(assertion->id()); - solAssert(it != m_errorIds.end(), ""); - solAssert(!it->second.empty(), ""); - unsigned errorId = it->second[0]; - - checkAndReportTarget(assertion, _target, errorId, 6328_error, "Assertion violation happens here.", "Assertion violation might happen here."); + checkAndReportTarget(target, errorReporterId, errorType + " happens here.", errorType + " might happen here."); + checkedErrorIds.insert(target.errorId); } + + // There can be targets in internal functions that are not reachable from the external interface. + // These are safe by definition and are not even checked by the CHC engine, but this information + // must still be reported safe by the BMC engine. + set allErrorIds; + for (auto const& entry: m_functionTargetIds) + for (unsigned id: entry.second) + allErrorIds.insert(id); + + set unreachableErrorIds; + set_difference( + allErrorIds.begin(), + allErrorIds.end(), + checkedErrorIds.begin(), + checkedErrorIds.end(), + inserter(unreachableErrorIds, unreachableErrorIds.begin()) + ); + for (auto id: unreachableErrorIds) + m_safeTargets[m_verificationTargets.at(id).errorNode].insert(m_verificationTargets.at(id).type); } void CHC::checkAndReportTarget( - ASTNode const* _scope, CHCVerificationTarget const& _target, - unsigned _errorId, ErrorId _errorReporterId, string _satMsg, string _unknownMsg ) { - if (m_unsafeTargets.count(_scope) && m_unsafeTargets.at(_scope).count(_target.type)) + if (m_unsafeTargets.count(_target.errorNode) && m_unsafeTargets.at(_target.errorNode).count(_target.type)) return; createErrorBlock(); - connectBlocks(_target.value, error(), _target.constraints && (_target.errorId == _errorId)); - auto const& [result, model] = query(error(), _scope->location()); + connectBlocks(_target.value, error(), _target.constraints); + auto const& location = _target.errorNode->location(); + auto const& [result, model] = query(error(), location); if (result == CheckResult::UNSATISFIABLE) - m_safeTargets[_scope].insert(_target.type); + m_safeTargets[_target.errorNode].insert(_target.type); else if (result == CheckResult::SATISFIABLE) { solAssert(!_satMsg.empty(), ""); - m_unsafeTargets[_scope].insert(_target.type); + m_unsafeTargets[_target.errorNode].insert(_target.type); auto cex = generateCounterexample(model, error().name); if (cex) m_outerErrorReporter.warning( _errorReporterId, - _scope->location(), + location, "CHC: " + _satMsg, SecondarySourceLocation().append("Counterexample:\n" + *cex, SourceLocation{}) ); else m_outerErrorReporter.warning( _errorReporterId, - _scope->location(), + location, "CHC: " + _satMsg ); } else if (!_unknownMsg.empty()) m_outerErrorReporter.warning( _errorReporterId, - _scope->location(), + location, "CHC: " + _unknownMsg ); } @@ -1431,14 +1400,13 @@ string CHC::contractSuffix(ContractDefinition const& _contract) return _contract.name() + "_" + to_string(_contract.id()); } -unsigned CHC::newErrorId(frontend::Expression const& _expr) +unsigned CHC::newErrorId() { unsigned errorId = m_context.newUniqueId(); // We need to make sure the error id is not zero, // because error id zero actually means no error in the CHC encoding. if (errorId == 0) errorId = m_context.newUniqueId(); - m_errorIds[_expr.id()].push_back(errorId); return errorId; } diff --git a/libsolidity/formal/CHC.h b/libsolidity/formal/CHC.h index f82b2f64f..179ae62af 100644 --- a/libsolidity/formal/CHC.h +++ b/libsolidity/formal/CHC.h @@ -114,7 +114,7 @@ private: void eraseKnowledge(); void clearIndices(ContractDefinition const* _contract, FunctionDefinition const* _function = nullptr) override; void setCurrentBlock(Predicate const& _block); - std::set transactionAssertions(ASTNode const* _txRoot); + std::set transactionVerificationTargetsIds(ASTNode const* _txRoot); //@} /// Sort helpers. @@ -181,19 +181,14 @@ private: /// @returns otherwise. std::pair query(smtutil::Expression const& _query, langutil::SourceLocation const& _location); - void addVerificationTarget(ASTNode const* _scope, VerificationTarget::Type _type, smtutil::Expression _from, smtutil::Expression _constraints, smtutil::Expression _errorId); - void addVerificationTarget(ASTNode const* _scope, VerificationTarget::Type _type, smtutil::Expression _errorId); - void addVerificationTarget(frontend::Expression const& _scope, VerificationTarget::Type _type, smtutil::Expression const& _target); - void addAssertVerificationTarget(ASTNode const* _scope, smtutil::Expression _from, smtutil::Expression _constraints, smtutil::Expression _errorId); + void verificationTargetEncountered(ASTNode const* const _errorNode, VerificationTarget::Type _type, smtutil::Expression const& _errorCondition); void checkVerificationTargets(); // Forward declaration. Definition is below. struct CHCVerificationTarget; void checkAssertTarget(ASTNode const* _scope, CHCVerificationTarget const& _target); void checkAndReportTarget( - ASTNode const* _scope, CHCVerificationTarget const& _target, - unsigned _errorId, langutil::ErrorId _errorReporterId, std::string _satMsg, std::string _unknownMsg = "" @@ -234,7 +229,7 @@ private: /// @returns a new unique error id associated with _expr and stores /// it into m_errorIds. - unsigned newErrorId(Expression const& _expr); + unsigned newErrorId(); smt::SymbolicState& state(); smt::SymbolicIntVariable& errorFlag(); @@ -275,12 +270,30 @@ private: //@{ struct CHCVerificationTarget: VerificationTarget { - smtutil::Expression errorId; + unsigned const errorId; + ASTNode const* const errorNode; }; - /// Verification targets corresponding to ASTNodes. There can be multiple targets for a single ASTNode, - /// e.g., divByZero and Overflow for signed division. - std::map, IdCompare> m_verificationTargets; + /// Query placeholder stores information necessary to create the final query edge in the CHC system. + /// It is combined with the unique error id (and error type) to create a complete Verification Target. + struct CHCQueryPlaceholder + { + smtutil::Expression const constraints; + smtutil::Expression const errorExpression; + smtutil::Expression const fromPredicate; + }; + + /// Query placeholders for constructors, if the key has type ContractDefinition*, + /// or external functions, if the key has type FunctionDefinition*. + /// A placeholder is created for each possible context of a function (e.g. multiple contracts in contract inheritance hierarchy). + std::map, IdCompare> m_queryPlaceholders; + + /// Records verification conditions IDs per function encountered during an analysis of that function. + /// The key is the ASTNode of the function where the verification condition has been encountered, + /// or the ASTNode of the contract if the verification condition happens inside an implicit constructor. + std::map, IdCompare> m_functionTargetIds; + /// Helper mapping unique IDs to actual verification targets. + std::map m_verificationTargets; /// Targets proven safe. std::map> m_safeTargets; @@ -294,12 +307,6 @@ private: std::map, IdCompare> m_callGraph; - std::map, IdCompare> m_functionAssertions; - - /// Maps ASTNode ids to error ids. - /// There can be multiple errorIds associated with a single ASTNode. - std::map> m_errorIds; - /// The current block. smtutil::Expression m_currentBlock = smtutil::Expression(true); diff --git a/libsolidity/formal/EncodingContext.cpp b/libsolidity/formal/EncodingContext.cpp index 422eb44ee..da690a05f 100644 --- a/libsolidity/formal/EncodingContext.cpp +++ b/libsolidity/formal/EncodingContext.cpp @@ -33,7 +33,6 @@ EncodingContext::EncodingContext(): void EncodingContext::reset() { resetAllVariables(); - resetUniqueId(); m_expressions.clear(); m_globalContext.clear(); m_state.reset(); diff --git a/libsolidity/formal/SMTEncoder.cpp b/libsolidity/formal/SMTEncoder.cpp index f27f93693..2d2d3646c 100644 --- a/libsolidity/formal/SMTEncoder.cpp +++ b/libsolidity/formal/SMTEncoder.cpp @@ -348,6 +348,36 @@ void SMTEncoder::endVisit(VariableDeclarationStatement const& _varDecl) } +bool SMTEncoder::visit(Assignment const& _assignment) +{ + auto const& left = _assignment.leftHandSide(); + auto const& right = _assignment.rightHandSide(); + + if (auto const* memberAccess = isEmptyPush(left)) + { + right.accept(*this); + left.accept(*this); + + auto const& memberExpr = memberAccess->expression(); + auto& symbArray = dynamic_cast(*m_context.expression(memberExpr)); + smtutil::Expression oldElements = symbArray.elements(); + smtutil::Expression length = symbArray.length(); + symbArray.increaseIndex(); + m_context.addAssertion(symbArray.elements() == smtutil::Expression::store( + oldElements, + length - 1, + expr(right) + )); + m_context.addAssertion(symbArray.length() == length); + + arrayPushPopAssign(memberExpr, symbArray.currentValue()); + defineExpr(_assignment, expr(left)); + return false; + } + + return true; +} + void SMTEncoder::endVisit(Assignment const& _assignment) { createExpr(_assignment); @@ -355,6 +385,9 @@ void SMTEncoder::endVisit(Assignment const& _assignment) Token op = _assignment.assignmentOperator(); solAssert(TokenTraits::isAssignmentOp(op), ""); + if (isEmptyPush(_assignment.leftHandSide())) + return; + if (!smt::isSupportedType(*_assignment.annotation().type)) { // Give it a new index anyway to keep the SSA scheme sound. @@ -465,14 +498,14 @@ void SMTEncoder::endVisit(UnaryOperation const& _op) assignment(*decl, newValue); } else if ( - dynamic_cast(&_op.subExpression()) || - dynamic_cast(&_op.subExpression()) + dynamic_cast(subExpr) || + dynamic_cast(subExpr) ) { auto innerValue = expr(*subExpr); auto newValue = _op.getOperator() == Token::Inc ? innerValue + 1 : innerValue - 1; defineExpr(_op, _op.isPrefixOperation() ? newValue : innerValue); - indexOrMemberAssignment(_op.subExpression(), newValue); + indexOrMemberAssignment(*subExpr, newValue); } else m_errorReporter.warning( @@ -502,11 +535,12 @@ void SMTEncoder::endVisit(UnaryOperation const& _op) symbVar->increaseIndex(); m_context.setZeroValue(*symbVar); if ( - dynamic_cast(&_op.subExpression()) || - dynamic_cast(&_op.subExpression()) + dynamic_cast(subExpr) || + dynamic_cast(subExpr) ) - indexOrMemberAssignment(_op.subExpression(), symbVar->currentValue()); - else + indexOrMemberAssignment(*subExpr, symbVar->currentValue()); + // Empty push added a zero value anyway, so no need to delete extra. + else if (!isEmptyPush(*subExpr)) solAssert(false, ""); } break; @@ -1968,7 +2002,7 @@ void SMTEncoder::initializeFunctionCallParameters(CallableDeclaration const& _fu void SMTEncoder::createStateVariables(ContractDefinition const& _contract) { - for (auto var: _contract.stateVariablesIncludingInherited()) + for (auto var: stateVariablesIncludingInheritedAndPrivate(_contract)) createVariable(*var); } @@ -2252,7 +2286,7 @@ void SMTEncoder::resetVariableIndices(VariableIndices const& _indices) void SMTEncoder::clearIndices(ContractDefinition const* _contract, FunctionDefinition const* _function) { solAssert(_contract, ""); - for (auto var: _contract->stateVariablesIncludingInherited()) + for (auto var: stateVariablesIncludingInheritedAndPrivate(*_contract)) m_context.variable(*var)->resetIndex(); if (_function) { @@ -2309,7 +2343,7 @@ set SMTEncoder::touchedVariables(ASTNode const& _nod return m_variableUsage.touchedVariables(_node, callStack); } -Declaration const* SMTEncoder::expressionToDeclaration(Expression const& _expr) +Declaration const* SMTEncoder::expressionToDeclaration(Expression const& _expr) const { if (auto const* identifier = dynamic_cast(&_expr)) return identifier->annotation().referencedDeclaration; @@ -2318,7 +2352,7 @@ Declaration const* SMTEncoder::expressionToDeclaration(Expression const& _expr) return nullptr; } -VariableDeclaration const* SMTEncoder::identifierToVariable(Expression const& _expr) +VariableDeclaration const* SMTEncoder::identifierToVariable(Expression const& _expr) const { // We do not use `expressionToDeclaration` here because we are not interested in // struct.field, for example. @@ -2331,6 +2365,20 @@ VariableDeclaration const* SMTEncoder::identifierToVariable(Expression const& _e return nullptr; } +MemberAccess const* SMTEncoder::isEmptyPush(Expression const& _expr) const +{ + if ( + auto const* funCall = dynamic_cast(&_expr); + funCall && funCall->arguments().empty() + ) + { + auto const& funType = dynamic_cast(*funCall->expression().annotation().type); + if (funType.kind() == FunctionType::Kind::ArrayPush) + return &dynamic_cast(funCall->expression()); + } + return nullptr; +} + string SMTEncoder::extraComment() { string extra; diff --git a/libsolidity/formal/SMTEncoder.h b/libsolidity/formal/SMTEncoder.h index 748dcc80b..366cfc0b2 100644 --- a/libsolidity/formal/SMTEncoder.h +++ b/libsolidity/formal/SMTEncoder.h @@ -90,6 +90,7 @@ protected: bool visit(WhileStatement const&) override { return false; } bool visit(ForStatement const&) override { return false; } void endVisit(VariableDeclarationStatement const& _node) override; + bool visit(Assignment const& _node) override; void endVisit(Assignment const& _node) override; void endVisit(TupleExpression const& _node) override; bool visit(UnaryOperation const& _node) override; @@ -282,10 +283,14 @@ protected: /// @returns the declaration referenced by _expr, if any, /// and nullptr otherwise. - Declaration const* expressionToDeclaration(Expression const& _expr); + Declaration const* expressionToDeclaration(Expression const& _expr) const; /// @returns the VariableDeclaration referenced by an Expression or nullptr. - VariableDeclaration const* identifierToVariable(Expression const& _expr); + VariableDeclaration const* identifierToVariable(Expression const& _expr) const; + + /// @returns the MemberAccess .push if _expr is an empty array push call, + /// otherwise nullptr. + MemberAccess const* isEmptyPush(Expression const& _expr) const; /// Creates symbolic expressions for the returned values /// and set them as the components of the symbolic tuple. diff --git a/libsolidity/formal/SymbolicVariables.cpp b/libsolidity/formal/SymbolicVariables.cpp index 2d6eaa748..2d58704d1 100644 --- a/libsolidity/formal/SymbolicVariables.cpp +++ b/libsolidity/formal/SymbolicVariables.cpp @@ -332,12 +332,12 @@ smtutil::Expression SymbolicArrayVariable::valueAtIndex(unsigned _index) const return m_pair.valueAtIndex(_index); } -smtutil::Expression SymbolicArrayVariable::elements() +smtutil::Expression SymbolicArrayVariable::elements() const { return m_pair.component(0); } -smtutil::Expression SymbolicArrayVariable::length() +smtutil::Expression SymbolicArrayVariable::length() const { return m_pair.component(1); } diff --git a/libsolidity/formal/SymbolicVariables.h b/libsolidity/formal/SymbolicVariables.h index d81f770a5..6dda692b1 100644 --- a/libsolidity/formal/SymbolicVariables.h +++ b/libsolidity/formal/SymbolicVariables.h @@ -260,8 +260,8 @@ public: 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(); } - smtutil::Expression elements(); - smtutil::Expression length(); + smtutil::Expression elements() const; + smtutil::Expression length() const; smtutil::SortPointer tupleSort() { return m_pair.sort(); } diff --git a/test/libsolidity/ABIDecoderTests.cpp b/test/libsolidity/ABIDecoderTests.cpp index 611bc7cd3..768ab9b3b 100644 --- a/test/libsolidity/ABIDecoderTests.cpp +++ b/test/libsolidity/ABIDecoderTests.cpp @@ -73,28 +73,6 @@ BOOST_AUTO_TEST_CASE(value_types) ) } -BOOST_AUTO_TEST_CASE(enums) -{ - string sourceCode = R"( - contract C { - enum E { A, B } - function f(E e) public pure returns (uint x) { - assembly { x := e } - } - } - )"; - bool newDecoder = solidity::test::CommonOptions::get().useABIEncoderV2; - BOTH_ENCODERS( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(uint8)", 0), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f(uint8)", 1), encodeArgs(u256(1))); - // The old decoder was not as strict about enums - ABI_CHECK(callContractFunction("f(uint8)", 2), (newDecoder ? encodeArgs() : encodeArgs(2))); - ABI_CHECK(callContractFunction("f(uint8)", u256(-1)), (newDecoder? encodeArgs() : encodeArgs(u256(0xff)))); - newDecoder = true; - ) -} - BOOST_AUTO_TEST_CASE(cleanup) { string sourceCode = R"( @@ -184,113 +162,6 @@ BOOST_AUTO_TEST_CASE(fixed_arrays) ) } -BOOST_AUTO_TEST_CASE(dynamic_arrays) -{ - string sourceCode = R"( - contract C { - function f(uint a, uint16[] memory b, uint c) - public pure returns (uint, uint, uint) { - return (b.length, b[a], c); - } - } - )"; - BOTH_ENCODERS( - compileAndRun(sourceCode); - bytes args = encodeArgs( - 6, 0x60, 9, - 7, - 11, 12, 13, 14, 15, 16, 17 - ); - ABI_CHECK( - callContractFunction("f(uint256,uint16[],uint256)", args), - encodeArgs(u256(7), u256(17), u256(9)) - ); - ) -} - -BOOST_AUTO_TEST_CASE(dynamic_nested_arrays) -{ - string sourceCode = R"( - contract C { - function f(uint a, uint16[][] memory b, uint[2][][3] memory c, uint d) - public pure returns (uint, uint, uint, uint, uint, uint, uint) { - return (a, b.length, b[1].length, b[1][1], c[1].length, c[1][1][1], d); - } - function test() public view returns (uint, uint, uint, uint, uint, uint, uint) { - uint16[][] memory b = new uint16[][](3); - b[0] = new uint16[](2); - b[0][0] = 0x55; - b[0][1] = 0x56; - b[1] = new uint16[](4); - b[1][0] = 0x65; - b[1][1] = 0x66; - b[1][2] = 0x67; - b[1][3] = 0x68; - - uint[2][][3] memory c; - c[0] = new uint[2][](1); - c[0][0][1] = 0x75; - c[1] = new uint[2][](5); - c[1][1][1] = 0x85; - - return this.f(0x12, b, c, 0x13); - } - } - )"; - NEW_ENCODER( - compileAndRun(sourceCode); - bytes args = encodeArgs( - 0x12, 4 * 0x20, 17 * 0x20, 0x13, - // b - 3, 3 * 0x20, 6 * 0x20, 11 * 0x20, - 2, 85, 86, - 4, 101, 102, 103, 104, - 0, - // c - 3 * 0x20, 6 * 0x20, 17 * 0x20, - 1, 0, 117, - 5, 0, 0, 0, 133, 0, 0, 0, 0, 0, 0, - 0 - ); - - bytes expectation = encodeArgs(0x12, 3, 4, 0x66, 5, 0x85, 0x13); - ABI_CHECK(callContractFunction("test()"), expectation); - ABI_CHECK(callContractFunction("f(uint256,uint16[][],uint256[2][][3],uint256)", args), expectation); - ) -} - -BOOST_AUTO_TEST_CASE(byte_arrays) -{ - string sourceCode = R"( - contract C { - function f(uint a, bytes memory b, uint c) - public pure returns (uint, uint, byte, uint) { - return (a, b.length, b[3], c); - } - - function f_external(uint a, bytes calldata b, uint c) - external pure returns (uint, uint, byte, uint) { - return (a, b.length, b[3], c); - } - } - )"; - BOTH_ENCODERS( - compileAndRun(sourceCode); - bytes args = encodeArgs( - 6, 0x60, 9, - 7, "abcdefg" - ); - ABI_CHECK( - callContractFunction("f(uint256,bytes,uint256)", args), - encodeArgs(u256(6), u256(7), "d", 9) - ); - ABI_CHECK( - callContractFunction("f_external(uint256,bytes,uint256)", args), - encodeArgs(u256(6), u256(7), "d", 9) - ); - ) -} - BOOST_AUTO_TEST_CASE(calldata_arrays_too_large) { string sourceCode = R"( diff --git a/test/libsolidity/Assembly.cpp b/test/libsolidity/Assembly.cpp index a10604aee..4b599da68 100644 --- a/test/libsolidity/Assembly.cpp +++ b/test/libsolidity/Assembly.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -61,6 +62,7 @@ evmasm::AssemblyItems compileContract(std::shared_ptr _sourceCode) BOOST_CHECK(!!sourceUnit); Scoper::assignScopes(*sourceUnit); + BOOST_REQUIRE(SyntaxChecker(errorReporter, false).checkSyntax(*sourceUnit)); GlobalContext globalContext; NameAndTypeResolver resolver(globalContext, solidity::test::CommonOptions::get().evmVersion(), errorReporter); DeclarationTypeChecker declarationTypeChecker(errorReporter, solidity::test::CommonOptions::get().evmVersion()); diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index bc518a816..9babdacbc 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -537,39 +537,6 @@ BOOST_AUTO_TEST_CASE(for_loop) ) } -BOOST_AUTO_TEST_CASE(for_loop_empty) -{ - char const* sourceCode = R"( - contract test { - function f() public returns(uint ret) { - ret = 1; - for (;;) { - ret += 1; - if (ret >= 10) break; - } - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - - compileAndRun(sourceCode); - - auto for_loop_empty_cpp = []() -> u256 - { - u256 ret = 1; - for (;;) - { - ret += 1; - if (ret >= 10) break; - } - return ret; - }; - - testContractAgainstCpp("f()", for_loop_empty_cpp); - ) -} - BOOST_AUTO_TEST_CASE(for_loop_simple_init_expr) { char const* sourceCode = R"( @@ -649,85 +616,6 @@ BOOST_AUTO_TEST_CASE(for_loop_break_continue) ); } -BOOST_AUTO_TEST_CASE(calling_other_functions) -{ - char const* sourceCode = R"( - contract collatz { - function run(uint x) public returns(uint y) { - while ((y = x) > 1) { - if (x % 2 == 0) x = evenStep(x); - else x = oddStep(x); - } - } - function evenStep(uint x) public returns(uint y) { - return x / 2; - } - function oddStep(uint x) public returns(uint y) { - return 3 * x + 1; - } - } - )"; - auto evenStep_cpp = [](u256 const& n) -> u256 - { - return n / 2; - }; - - auto oddStep_cpp = [](u256 const& n) -> u256 - { - return 3 * n + 1; - }; - - auto collatz_cpp = [&evenStep_cpp, &oddStep_cpp](u256 n) -> u256 - { - u256 y; - while ((y = n) > 1) - { - if (n % 2 == 0) - n = evenStep_cpp(n); - else - n = oddStep_cpp(n); - } - return y; - }; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - compileAndRun(sourceCode); - - testContractAgainstCpp("run(uint256)", collatz_cpp, u256(0)); - testContractAgainstCpp("run(uint256)", collatz_cpp, u256(1)); - testContractAgainstCpp("run(uint256)", collatz_cpp, u256(2)); - testContractAgainstCpp("run(uint256)", collatz_cpp, u256(8)); - testContractAgainstCpp("run(uint256)", collatz_cpp, u256(127)); - ) -} - -BOOST_AUTO_TEST_CASE(many_local_variables) -{ - char const* sourceCode = R"( - contract test { - function run(uint x1, uint x2, uint x3) public returns(uint y) { - uint8 a = 0x1; uint8 b = 0x10; uint16 c = 0x100; - y = a + b + c + x1 + x2 + x3; - y += b + x2; - } - } - )"; - auto f = [](u256 const& x1, u256 const& x2, u256 const& x3) -> u256 - { - u256 a = 0x1; - u256 b = 0x10; - u256 c = 0x100; - u256 y = a + b + c + x1 + x2 + x3; - return y + b + x2; - }; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - - compileAndRun(sourceCode); - testContractAgainstCpp("run(uint256,uint256,uint256)", f, u256(0x1000), u256(0x10000), u256(0x100000)); - ) -} - BOOST_AUTO_TEST_CASE(short_circuiting) { char const* sourceCode = R"( @@ -826,149 +714,6 @@ BOOST_AUTO_TEST_CASE(small_unsigned_types) testContractAgainstCpp("run()", small_unsigned_types_cpp); } -BOOST_AUTO_TEST_CASE(small_signed_types) -{ - char const* sourceCode = R"( - contract test { - function run() public returns(int256 y) { - return -int32(10) * -int64(20); - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - compileAndRun(sourceCode); - auto small_signed_types_cpp = []() -> u256 - { - return -int32_t(10) * -int64_t(20); - }; - testContractAgainstCpp("run()", small_signed_types_cpp); - ); -} - -BOOST_AUTO_TEST_CASE(compound_assign) -{ - char const* sourceCode = R"( - contract test { - uint value1; - uint value2; - function f(uint x, uint y) public returns (uint w) { - uint value3 = y; - value1 += x; - value3 *= x; - value2 *= value3 + value1; - return value2 += 7; - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - - compileAndRun(sourceCode); - - u256 value1; - u256 value2; - auto f = [&](u256 const& _x, u256 const& _y) -> u256 - { - u256 value3 = _y; - value1 += _x; - value3 *= _x; - value2 *= value3 + value1; - return value2 += 7; - }; - testContractAgainstCpp("f(uint256,uint256)", f, u256(0), u256(6)); - testContractAgainstCpp("f(uint256,uint256)", f, u256(1), u256(3)); - testContractAgainstCpp("f(uint256,uint256)", f, u256(2), u256(25)); - testContractAgainstCpp("f(uint256,uint256)", f, u256(3), u256(69)); - testContractAgainstCpp("f(uint256,uint256)", f, u256(4), u256(84)); - testContractAgainstCpp("f(uint256,uint256)", f, u256(5), u256(2)); - testContractAgainstCpp("f(uint256,uint256)", f, u256(6), u256(51)); - testContractAgainstCpp("f(uint256,uint256)", f, u256(7), u256(48)); - ) -} - -BOOST_AUTO_TEST_CASE(mapping_state) -{ - char const* sourceCode = R"( - contract Ballot { - mapping(address => bool) canVote; - mapping(address => uint) voteCount; - mapping(address => bool) voted; - function getVoteCount(address addr) public returns (uint retVoteCount) { - return voteCount[addr]; - } - function grantVoteRight(address addr) public { - canVote[addr] = true; - } - function vote(address voter, address vote) public returns (bool success) { - if (!canVote[voter] || voted[voter]) return false; - voted[voter] = true; - voteCount[vote] = voteCount[vote] + 1; - return true; - } - } - )"; - class Ballot - { - public: - u256 getVoteCount(u160 _address) { return m_voteCount[_address]; } - void grantVoteRight(u160 _address) { m_canVote[_address] = true; } - bool vote(u160 _voter, u160 _vote) - { - if (!m_canVote[_voter] || m_voted[_voter]) return false; - m_voted[_voter] = true; - m_voteCount[_vote]++; - return true; - } - private: - map m_canVote; - map m_voteCount; - map m_voted; - }; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - - compileAndRun(sourceCode); - Ballot ballot; - - auto getVoteCount = bind(&Ballot::getVoteCount, &ballot, _1); - auto grantVoteRight = bind(&Ballot::grantVoteRight, &ballot, _1); - auto vote = bind(&Ballot::vote, &ballot, _1, _2); - testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(0)); - testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(1)); - testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(2)); - // voting without vote right should be rejected - testContractAgainstCpp("vote(address,address)", vote, u160(0), u160(2)); - testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(0)); - testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(1)); - testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(2)); - // grant vote rights - testContractAgainstCpp("grantVoteRight(address)", grantVoteRight, u160(0)); - testContractAgainstCpp("grantVoteRight(address)", grantVoteRight, u160(1)); - // vote, should increase 2's vote count - testContractAgainstCpp("vote(address,address)", vote, u160(0), u160(2)); - testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(0)); - testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(1)); - testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(2)); - // vote again, should be rejected - testContractAgainstCpp("vote(address,address)", vote, u160(0), u160(1)); - testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(0)); - testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(1)); - testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(2)); - // vote without right to vote - testContractAgainstCpp("vote(address,address)", vote, u160(2), u160(1)); - testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(0)); - testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(1)); - testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(2)); - // grant vote right and now vote again - testContractAgainstCpp("grantVoteRight(address)", grantVoteRight, u160(2)); - testContractAgainstCpp("vote(address,address)", vote, u160(2), u160(1)); - testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(0)); - testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(1)); - testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(2)); - ) -} - BOOST_AUTO_TEST_CASE(mapping_state_inc_dec) { char const* sourceCode = R"( @@ -2764,11 +2509,14 @@ BOOST_AUTO_TEST_CASE(delete_removes_bytes_data) bytes data; } )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("---", 7), bytes()); - BOOST_CHECK(!storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("del()", 7), encodeArgs(true)); - BOOST_CHECK(storageEmpty(m_contractAddress)); + ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("---", 7), bytes()); + BOOST_CHECK(!storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("del()", 7), encodeArgs(true)); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ); } BOOST_AUTO_TEST_CASE(copy_from_calldata_removes_bytes_data) @@ -2780,13 +2528,16 @@ BOOST_AUTO_TEST_CASE(copy_from_calldata_removes_bytes_data) bytes data; } )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("set()", 1, 2, 3, 4, 5), encodeArgs(true)); - BOOST_CHECK(!storageEmpty(m_contractAddress)); - sendMessage(bytes(), false); - BOOST_CHECK(m_transactionSuccessful); - BOOST_CHECK(m_output.empty()); - BOOST_CHECK(storageEmpty(m_contractAddress)); + ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("set()", 1, 2, 3, 4, 5), encodeArgs(true)); + BOOST_CHECK(!storageEmpty(m_contractAddress)); + sendMessage(bytes(), false); + BOOST_CHECK(m_transactionSuccessful); + BOOST_CHECK(m_output.empty()); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ); } BOOST_AUTO_TEST_CASE(copy_removes_bytes_data) @@ -3032,17 +2783,21 @@ BOOST_AUTO_TEST_CASE(bytes_in_arguments) } } )"; - compileAndRun(sourceCode); + ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() - string innercalldata1 = asString(FixedHash<4>(util::keccak256("f(uint256,uint256)")).asBytes() + encodeArgs(8, 9)); - string innercalldata2 = asString(FixedHash<4>(util::keccak256("g(uint256)")).asBytes() + encodeArgs(3)); - bytes calldata = encodeArgs( - 12, 32 * 4, u256(32 * 4 + 32 + (innercalldata1.length() + 31) / 32 * 32), 13, - u256(innercalldata1.length()), innercalldata1, - u256(innercalldata2.length()), innercalldata2); - ABI_CHECK( - callContractFunction("test(uint256,bytes,bytes,uint256)", calldata), - encodeArgs(12, (8 + 9) * 3, 13, u256(innercalldata1.length())) + compileAndRun(sourceCode); + + string innercalldata1 = asString(FixedHash<4>(util::keccak256("f(uint256,uint256)")).asBytes() + encodeArgs(8, 9)); + string innercalldata2 = asString(FixedHash<4>(util::keccak256("g(uint256)")).asBytes() + encodeArgs(3)); + bytes calldata = encodeArgs( + 12, 32 * 4, u256(32 * 4 + 32 + (innercalldata1.length() + 31) / 32 * 32), 13, + u256(innercalldata1.length()), innercalldata1, + u256(innercalldata2.length()), innercalldata2); + ABI_CHECK( + callContractFunction("test(uint256,bytes,bytes,uint256)", calldata), + encodeArgs(12, (8 + 9) * 3, 13, u256(innercalldata1.length())) + ); ); } @@ -3146,12 +2901,16 @@ BOOST_AUTO_TEST_CASE(dynamic_multi_array_cleanup) function clear() public { delete data; } } )"; - compileAndRun(sourceCode); - BOOST_CHECK(storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("fill()"), encodeArgs(8)); - BOOST_CHECK(!storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("clear()"), bytes()); - BOOST_CHECK(storageEmpty(m_contractAddress)); + ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + + compileAndRun(sourceCode); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("fill()"), encodeArgs(8)); + BOOST_CHECK(!storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("clear()"), bytes()); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ); } BOOST_AUTO_TEST_CASE(array_copy_storage_storage_dyn_dyn) @@ -3268,20 +3027,24 @@ BOOST_AUTO_TEST_CASE(array_copy_storage_abi) } } )"; - compileAndRun(sourceCode); - bytes valueSequence; - for (size_t i = 0; i < 101; ++i) - valueSequence += toBigEndian(u256(i)); - ABI_CHECK(callContractFunction("test1()"), encodeArgs(0x20, 101) + valueSequence); - ABI_CHECK(callContractFunction("test2()"), encodeArgs(0x20, 101) + valueSequence); - ABI_CHECK(callContractFunction("test3()"), encodeArgs(0x20, 101) + valueSequence); - ABI_CHECK(callContractFunction("test4()"), - encodeArgs(0x20, 5, 0xa0, 0xa0 + 102 * 32 * 1, 0xa0 + 102 * 32 * 2, 0xa0 + 102 * 32 * 3, 0xa0 + 102 * 32 * 4) + - encodeArgs(101) + valueSequence + - encodeArgs(101) + valueSequence + - encodeArgs(101) + valueSequence + - encodeArgs(101) + valueSequence + - encodeArgs(101) + valueSequence + ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + + compileAndRun(sourceCode); + bytes valueSequence; + for (size_t i = 0; i < 101; ++i) + valueSequence += toBigEndian(u256(i)); + ABI_CHECK(callContractFunction("test1()"), encodeArgs(0x20, 101) + valueSequence); + ABI_CHECK(callContractFunction("test2()"), encodeArgs(0x20, 101) + valueSequence); + ABI_CHECK(callContractFunction("test3()"), encodeArgs(0x20, 101) + valueSequence); + ABI_CHECK(callContractFunction("test4()"), + encodeArgs(0x20, 5, 0xa0, 0xa0 + 102 * 32 * 1, 0xa0 + 102 * 32 * 2, 0xa0 + 102 * 32 * 3, 0xa0 + 102 * 32 * 4) + + encodeArgs(101) + valueSequence + + encodeArgs(101) + valueSequence + + encodeArgs(101) + valueSequence + + encodeArgs(101) + valueSequence + + encodeArgs(101) + valueSequence + ); ); } @@ -3307,9 +3070,12 @@ BOOST_AUTO_TEST_CASE(array_pop_uint16_transition) } } )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(38, 28, 18)); - BOOST_CHECK(storageEmpty(m_contractAddress)); + ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("test()"), encodeArgs(38, 28, 18)); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ); } BOOST_AUTO_TEST_CASE(array_pop_uint24_transition) @@ -3334,9 +3100,12 @@ BOOST_AUTO_TEST_CASE(array_pop_uint24_transition) } } )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(20, 10)); - BOOST_CHECK(storageEmpty(m_contractAddress)); + ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("test()"), encodeArgs(20, 10)); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ); } BOOST_AUTO_TEST_CASE(array_pop_array_transition) @@ -3382,9 +3151,12 @@ BOOST_AUTO_TEST_CASE(array_pop_storage_empty) } } )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs()); - BOOST_CHECK(storageEmpty(m_contractAddress)); + ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("test()"), encodeArgs()); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ); } BOOST_AUTO_TEST_CASE(byte_array_pop_storage_empty) @@ -3402,9 +3174,12 @@ BOOST_AUTO_TEST_CASE(byte_array_pop_storage_empty) } } )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs()); - BOOST_CHECK(storageEmpty(m_contractAddress)); + ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("test()"), encodeArgs()); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ); } BOOST_AUTO_TEST_CASE(byte_array_pop_long_storage_empty) @@ -3427,9 +3202,12 @@ BOOST_AUTO_TEST_CASE(byte_array_pop_long_storage_empty) } } )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(true)); - BOOST_CHECK(storageEmpty(m_contractAddress)); + ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("test()"), encodeArgs(true)); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ); } BOOST_AUTO_TEST_CASE(byte_array_pop_long_storage_empty_garbage_ref) @@ -3505,15 +3283,19 @@ BOOST_AUTO_TEST_CASE(bytes_index_access) } } )"; - compileAndRun(sourceCode); string array{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33}; - ABI_CHECK(callContractFunction("direct(bytes,uint256)", 64, 33, u256(array.length()), array), encodeArgs(33)); - ABI_CHECK(callContractFunction("storageCopyRead(bytes,uint256)", 64, 33, u256(array.length()), array), encodeArgs(33)); - ABI_CHECK(callContractFunction("storageWrite()"), encodeArgs(0x193)); + ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("direct(bytes,uint256)", 64, 33, u256(array.length()), array), encodeArgs(33)); + ABI_CHECK(callContractFunction("storageCopyRead(bytes,uint256)", 64, 33, u256(array.length()), array), encodeArgs(33)); + ABI_CHECK(callContractFunction("storageWrite()"), encodeArgs(0x193)); + ); } BOOST_AUTO_TEST_CASE(array_copy_calldata_storage) diff --git a/test/libsolidity/SolidityExpressionCompiler.cpp b/test/libsolidity/SolidityExpressionCompiler.cpp index 564699f1d..8999ac565 100644 --- a/test/libsolidity/SolidityExpressionCompiler.cpp +++ b/test/libsolidity/SolidityExpressionCompiler.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -93,18 +94,20 @@ Declaration const& resolveDeclaration( } bytes compileFirstExpression( - const string& _sourceCode, + string const& _sourceCode, vector> _functions = {}, vector> _localVariables = {} ) { + string sourceCode = "pragma solidity >=0.0; // SPDX-License-Identifier: GPL-3\n" + _sourceCode; + ASTPointer sourceUnit; try { ErrorList errors; ErrorReporter errorReporter(errors); sourceUnit = Parser(errorReporter, solidity::test::CommonOptions::get().evmVersion()).parse( - make_shared(CharStream(_sourceCode, "")) + make_shared(CharStream(sourceCode, "")) ); if (!sourceUnit) return bytes(); @@ -119,6 +122,7 @@ bytes compileFirstExpression( ErrorReporter errorReporter(errors); GlobalContext globalContext; Scoper::assignScopes(*sourceUnit); + BOOST_REQUIRE(SyntaxChecker(errorReporter, false).checkSyntax(*sourceUnit)); NameAndTypeResolver resolver(globalContext, solidity::test::CommonOptions::get().evmVersion(), errorReporter); resolver.registerDeclarations(*sourceUnit); BOOST_REQUIRE_MESSAGE(resolver.resolveNamesAndTypes(*sourceUnit), "Resolving names failed"); @@ -187,7 +191,7 @@ BOOST_AUTO_TEST_CASE(literal_false) { char const* sourceCode = R"( contract test { - function f() { bool x = false; } + function f() public { bool x = false; } } )"; bytes code = compileFirstExpression(sourceCode); @@ -200,7 +204,7 @@ BOOST_AUTO_TEST_CASE(int_literal) { char const* sourceCode = R"( contract test { - function f() { uint x = 0x12345678901234567890; } + function f() public { uint x = 0x12345678901234567890; } } )"; bytes code = compileFirstExpression(sourceCode); @@ -229,7 +233,7 @@ BOOST_AUTO_TEST_CASE(int_with_gwei_ether_subdenomination) { char const* sourceCode = R"( contract test { - function test () { + function f() public { uint x = 1 gwei; } } @@ -259,7 +263,7 @@ BOOST_AUTO_TEST_CASE(comparison) { char const* sourceCode = R"( contract test { - function f() { bool x = (0x10aa < 0x11aa) != true; } + function f() public { bool x = (0x10aa < 0x11aa) != true; } } )"; bytes code = compileFirstExpression(sourceCode); @@ -291,7 +295,7 @@ BOOST_AUTO_TEST_CASE(short_circuiting) { char const* sourceCode = R"( contract test { - function f() { bool x = true != (4 <= 8 + 10 || 9 != 2); } + function f() public { bool x = true != (4 <= 8 + 10 || 9 != 2); } } )"; bytes code = compileFirstExpression(sourceCode); @@ -322,7 +326,7 @@ BOOST_AUTO_TEST_CASE(arithmetic) { char const* sourceCode = R"( contract test { - function f(uint y) { unchecked { ((((((((y ^ 8) & 7) | 6) - 5) + 4) % 3) / 2) * 1); } } + function f(uint y) public { unchecked { ((((((((y ^ 8) & 7) | 6) - 5) + 4) % 3) / 2) * 1); } } } )"; bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}}); @@ -418,7 +422,7 @@ BOOST_AUTO_TEST_CASE(unary_operators) { char const* sourceCode = R"( contract test { - function f(int y) { unchecked { !(~- y == 2); } } + function f(int y) public { unchecked { !(~- y == 2); } } } )"; bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}}); @@ -508,7 +512,7 @@ BOOST_AUTO_TEST_CASE(assignment) { char const* sourceCode = R"( contract test { - function f(uint a, uint b) { unchecked { (a += b) * 2; } } + function f(uint a, uint b) public { unchecked { (a += b) * 2; } } } )"; bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "b"}}); @@ -546,7 +550,7 @@ BOOST_AUTO_TEST_CASE(negative_literals_8bits) { char const* sourceCode = R"( contract test { - function f() { int8 x = -0x80; } + function f() public { int8 x = -0x80; } } )"; bytes code = compileFirstExpression(sourceCode); @@ -559,7 +563,7 @@ BOOST_AUTO_TEST_CASE(negative_literals_16bits) { char const* sourceCode = R"( contract test { - function f() { int64 x = ~0xabc; } + function f() public { int64 x = ~0xabc; } } )"; bytes code = compileFirstExpression(sourceCode); @@ -574,7 +578,7 @@ BOOST_AUTO_TEST_CASE(intermediately_overflowing_literals) // have been applied char const* sourceCode = R"( contract test { - function f() { uint8 x = (0x00ffffffffffffffffffffffffffffffffffffffff * 0xffffffffffffffffffffffffff01) & 0xbf; } + function f() public { uint8 x = (0x00ffffffffffffffffffffffffffffffffffffffff * 0xffffffffffffffffffffffffff01) & 0xbf; } } )"; bytes code = compileFirstExpression(sourceCode); @@ -587,7 +591,7 @@ BOOST_AUTO_TEST_CASE(blockhash) { char const* sourceCode = R"( contract test { - function f() { + function f() public { blockhash(3); } } @@ -619,7 +623,7 @@ BOOST_AUTO_TEST_CASE(selfbalance) { char const* sourceCode = R"( contract test { - function f() returns (uint) { + function f() public returns (uint) { return address(this).balance; } } diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_storage.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_storage.sol index 95b667e47..79c450556 100644 --- a/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_storage.sol +++ b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_storage.sol @@ -20,5 +20,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> 0x20, 0x8, 0x40, 0x3, 0x9, 0xa, 0xb diff --git a/test/libsolidity/semanticTests/abiEncoderV1/byte_arrays.sol b/test/libsolidity/semanticTests/abiEncoderV1/byte_arrays.sol new file mode 100644 index 000000000..3eab393b5 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV1/byte_arrays.sol @@ -0,0 +1,16 @@ +contract C { + function f(uint a, bytes memory b, uint c) + public pure returns (uint, uint, byte, uint) { + return (a, b.length, b[3], c); + } + + function f_external(uint a, bytes calldata b, uint c) + external pure returns (uint, uint, byte, uint) { + return (a, b.length, b[3], c); + } +} +// ==== +// compileViaYul: also +// ---- +// f(uint256,bytes,uint256): 6, 0x60, 9, 7, "abcdefg" -> 6, 7, "d", 9 +// f_external(uint256,bytes,uint256): 6, 0x60, 9, 7, "abcdefg" -> 6, 7, "d", 9 \ No newline at end of file diff --git a/test/libsolidity/semanticTests/abiEncoderV1/dynamic_arrays.sol b/test/libsolidity/semanticTests/abiEncoderV1/dynamic_arrays.sol new file mode 100644 index 000000000..8813be109 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV1/dynamic_arrays.sol @@ -0,0 +1,10 @@ +contract C { + function f(uint a, uint16[] memory b, uint c) + public pure returns (uint, uint, uint) { + return (b.length, b[a], c); + } +} +// ==== +// compileViaYul: also +// ---- +// f(uint256,uint16[],uint256): 6, 0x60, 9, 7, 11, 12, 13, 14, 15, 16, 17 -> 7, 17, 9 diff --git a/test/libsolidity/semanticTests/abiEncoderV1/enums.sol b/test/libsolidity/semanticTests/abiEncoderV1/enums.sol new file mode 100644 index 000000000..ad69e268f --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV1/enums.sol @@ -0,0 +1,13 @@ +contract C { + enum E { A, B } + function f(E e) public pure returns (uint x) { + assembly { x := e } + } +} +// ==== +// ABIEncoderV1Only: true +// ---- +// f(uint8): 0 -> 0 +// f(uint8): 1 -> 1 +// f(uint8): 2 -> 2 +// f(uint8): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -> 0xff diff --git a/test/libsolidity/semanticTests/abiEncoderV2/byte_arrays.sol b/test/libsolidity/semanticTests/abiEncoderV2/byte_arrays.sol new file mode 100644 index 000000000..4492c6f9d --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV2/byte_arrays.sol @@ -0,0 +1,18 @@ +pragma experimental ABIEncoderV2; + +contract C { + function f(uint a, bytes memory b, uint c) + public pure returns (uint, uint, byte, uint) { + return (a, b.length, b[3], c); + } + + function f_external(uint a, bytes calldata b, uint c) + external pure returns (uint, uint, byte, uint) { + return (a, b.length, b[3], c); + } +} +// ==== +// compileViaYul: also +// ---- +// f(uint256,bytes,uint256): 6, 0x60, 9, 7, "abcdefg" -> 6, 7, "d", 9 +// f_external(uint256,bytes,uint256): 6, 0x60, 9, 7, "abcdefg" -> 6, 7, "d", 9 \ No newline at end of file diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static_dynamic_static.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static_dynamic_static.sol index 6e8361d4a..2688f899d 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static_dynamic_static.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static_dynamic_static.sol @@ -41,6 +41,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >homestead // ---- // g() -> 32, 132, hex"15cfcc01", 32, 32, 1, 42, hex"00000000000000000000000000000000000000000000000000000000" diff --git a/test/libsolidity/semanticTests/abiEncoderV2/dynamic_arrays.sol b/test/libsolidity/semanticTests/abiEncoderV2/dynamic_arrays.sol new file mode 100644 index 000000000..9dfa00175 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV2/dynamic_arrays.sol @@ -0,0 +1,12 @@ +pragma experimental ABIEncoderV2; + +contract C { + function f(uint a, uint16[] memory b, uint c) + public pure returns (uint, uint, uint) { + return (b.length, b[a], c); + } +} +// ==== +// compileViaYul: also +// ---- +// f(uint256,uint16[],uint256): 6, 0x60, 9, 7, 11, 12, 13, 14, 15, 16, 17 -> 7, 17, 9 \ No newline at end of file diff --git a/test/libsolidity/semanticTests/abiEncoderV2/dynamic_nested_arrays.sol b/test/libsolidity/semanticTests/abiEncoderV2/dynamic_nested_arrays.sol new file mode 100644 index 000000000..21672f080 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV2/dynamic_nested_arrays.sol @@ -0,0 +1,32 @@ +pragma experimental ABIEncoderV2; + +contract C { + function f(uint a, uint16[][] memory b, uint[2][][3] memory c, uint d) + public pure returns (uint, uint, uint, uint, uint, uint, uint) { + return (a, b.length, b[1].length, b[1][1], c[1].length, c[1][1][1], d); + } + function test() public view returns (uint, uint, uint, uint, uint, uint, uint) { + uint16[][] memory b = new uint16[][](3); + b[0] = new uint16[](2); + b[0][0] = 0x55; + b[0][1] = 0x56; + b[1] = new uint16[](4); + b[1][0] = 0x65; + b[1][1] = 0x66; + b[1][2] = 0x67; + b[1][3] = 0x68; + + uint[2][][3] memory c; + c[0] = new uint[2][](1); + c[0][0][1] = 0x75; + c[1] = new uint[2][](5); + c[1][1][1] = 0x85; + + return this.f(12, b, c, 13); + } +} +// ==== +// compileViaYul: also +// ---- +// test() -> 12, 3, 4, 0x66, 5, 0x85, 13 +// f(uint256,uint16[][],uint256[2][][3],uint256): 12, 0x80, 0x220, 13, 3, 0x60, 0xC0, 0x160, 2, 85, 86, 4, 101, 102, 103, 104, 0, 0x60, 0xC0, 0x220, 1, 0, 117, 5, 0, 0, 0, 133, 0, 0, 0, 0, 0, 0, 0 -> 12, 3, 4, 0x66, 5, 0x85, 13 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/enums.sol b/test/libsolidity/semanticTests/abiEncoderV2/enums.sol new file mode 100644 index 000000000..41a42d570 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV2/enums.sol @@ -0,0 +1,15 @@ +pragma experimental ABIEncoderV2; + +contract C { + enum E { A, B } + function f(E e) public pure returns (uint x) { + assembly { x := e } + } +} +// ==== +// compileViaYul: also +// ---- +// f(uint8): 0 -> 0 +// f(uint8): 1 -> 1 +// f(uint8): 2 -> FAILURE +// f(uint8): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -> FAILURE diff --git a/test/libsolidity/semanticTests/abiencodedecode/abi_decode_simple_storage.sol b/test/libsolidity/semanticTests/abiencodedecode/abi_decode_simple_storage.sol index d08e2ff82..119c33aeb 100644 --- a/test/libsolidity/semanticTests/abiencodedecode/abi_decode_simple_storage.sol +++ b/test/libsolidity/semanticTests/abiencodedecode/abi_decode_simple_storage.sol @@ -7,5 +7,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(bytes): 0x20, 0x80, 0x21, 0x40, 0x7, "abcdefg" -> 0x21, 0x40, 0x7, "abcdefg" diff --git a/test/libsolidity/semanticTests/array/bytes_delete_element.sol b/test/libsolidity/semanticTests/array/bytes_delete_element.sol index 2f6b8176d..6cf0da3bb 100644 --- a/test/libsolidity/semanticTests/array/bytes_delete_element.sol +++ b/test/libsolidity/semanticTests/array/bytes_delete_element.sol @@ -14,5 +14,7 @@ contract c { uint8(data[97]) == 97; } } +// ==== +// compileViaYul: also // ---- // test1() -> true diff --git a/test/libsolidity/semanticTests/array/bytes_length_member.sol b/test/libsolidity/semanticTests/array/bytes_length_member.sol index d35fc88d3..fbff51f02 100644 --- a/test/libsolidity/semanticTests/array/bytes_length_member.sol +++ b/test/libsolidity/semanticTests/array/bytes_length_member.sol @@ -10,6 +10,8 @@ contract c { bytes data; } +// ==== +// compileViaYul: also // ---- // getLength() -> 0 // set(): 1, 2 -> true diff --git a/test/libsolidity/semanticTests/array/copying/bytes_memory_to_storage.sol b/test/libsolidity/semanticTests/array/copying/bytes_memory_to_storage.sol index eebdb7e9b..75bd9c5b3 100644 --- a/test/libsolidity/semanticTests/array/copying/bytes_memory_to_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/bytes_memory_to_storage.sol @@ -6,5 +6,7 @@ contract C { return s[0]; } } +// ==== +// compileViaYul: also // ---- // f() -> "a" diff --git a/test/libsolidity/semanticTests/array/copying/calldata_bytes_to_storage.sol b/test/libsolidity/semanticTests/array/copying/calldata_bytes_to_storage.sol index 07041910d..efd67e10c 100644 --- a/test/libsolidity/semanticTests/array/copying/calldata_bytes_to_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/calldata_bytes_to_storage.sol @@ -5,5 +5,7 @@ contract C { return s[0]; } } +// ==== +// compileViaYul: also // ---- // f(bytes): 0x20, 0x08, "abcdefgh" -> "a" diff --git a/test/libsolidity/semanticTests/array/copying/copy_byte_array_in_struct_to_storage.sol b/test/libsolidity/semanticTests/array/copying/copy_byte_array_in_struct_to_storage.sol new file mode 100644 index 000000000..2f983e022 --- /dev/null +++ b/test/libsolidity/semanticTests/array/copying/copy_byte_array_in_struct_to_storage.sol @@ -0,0 +1,42 @@ +pragma experimental ABIEncoderV2; +struct S { + uint16 x; + bytes a; + uint16 y; + bytes b; +} +contract C { + uint padding; + S data; + + function f() public returns (bytes memory, bytes memory) { + S memory x; + x.x = 7; + x.b = "1234567890123456789012345678901 1234567890123456789012345678901 123456789"; + x.a = "abcdef"; + x.y = 9; + data = x; + return (data.a, data.b); + } + function g() public returns (bytes memory, bytes memory) { + S memory x; + x.x = 7; + x.b = "12345678923456789"; + x.a = "1234567890123456789012345678901 1234567890123456789012345678901 123456789"; + x.y = 9; + data = x; + return (data.a, data.b); + } + function h() public returns (bytes memory, bytes memory) { + S memory x; + data = x; + return (data.a, data.b); + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> 0x40, 0x80, 6, 0x6162636465660000000000000000000000000000000000000000000000000000, 0x49, 0x3132333435363738393031323334353637383930313233343536373839303120, 0x3132333435363738393031323334353637383930313233343536373839303120, 0x3132333435363738390000000000000000000000000000000000000000000000 +// g() -> 0x40, 0xc0, 0x49, 0x3132333435363738393031323334353637383930313233343536373839303120, 0x3132333435363738393031323334353637383930313233343536373839303120, 0x3132333435363738390000000000000000000000000000000000000000000000, 0x11, 0x3132333435363738393233343536373839000000000000000000000000000000 +// h() -> 0x40, 0x60, 0x00, 0x00 +// storage: empty diff --git a/test/libsolidity/semanticTests/array/copying/copy_byte_array_to_storage.sol b/test/libsolidity/semanticTests/array/copying/copy_byte_array_to_storage.sol new file mode 100644 index 000000000..de36b0a29 --- /dev/null +++ b/test/libsolidity/semanticTests/array/copying/copy_byte_array_to_storage.sol @@ -0,0 +1,50 @@ +function dataslot() pure returns (bytes32) { + return keccak256(abi.encode(1)); +} + +function readDataSlot(uint offset) view returns (bytes32 r) { + bytes32 s = dataslot(); + assembly { r := sload(add(s, offset)) } +} + +function readDataSlot() view returns (bytes32) { + return readDataSlot(0); +} + +function readHead() view returns (bytes32 r) { + assembly { r := sload(1) } +} + +contract C { + uint padding; + bytes data; + + function f() public returns (uint) { + bytes32 zero; + if (!(readDataSlot() == zero)) return 1; + data = "abc"; + if (!(readDataSlot() == zero)) return 2; + data = "1234567890123456789012345678901234567890123456789012345678901234567890"; + if (!(readDataSlot() != zero)) return 3; + if (!(readDataSlot(1) != zero)) return 4; + if (!(readDataSlot(2) != zero)) return 5; + if (!(readDataSlot(3) == zero)) return 6; + if (!(readDataSlot(4) == zero)) return 7; + data = "abc"; + if (!(readDataSlot() == zero)) return 8; + if (!(readDataSlot(1) == zero)) return 9; + if (!(readDataSlot(2) == zero)) return 10; + if (!(readDataSlot(3) == zero)) return 11; + data = "1234567890123456789012345678901234567890123456789012345678901234567890"; + data = "123456789012345678901234567890123456"; + if (!(readDataSlot() != zero)) return 12; + if (!(readDataSlot(1) != zero)) return 13; + if (!(readDataSlot(2) == zero)) return 14; + if (!(readDataSlot(3) == zero)) return 15; + return 0xff; + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> 0xff diff --git a/test/libsolidity/semanticTests/array/copying/copy_internal_function_array_to_storage.sol b/test/libsolidity/semanticTests/array/copying/copy_internal_function_array_to_storage.sol index 7b3817946..7a342e93a 100644 --- a/test/libsolidity/semanticTests/array/copying/copy_internal_function_array_to_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/copy_internal_function_array_to_storage.sol @@ -17,6 +17,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // one() -> 3 // two() -> FAILURE, hex"4e487b71", 0x51 diff --git a/test/libsolidity/semanticTests/array/inline_array_strings_from_document.sol b/test/libsolidity/semanticTests/array/inline_array_strings_from_document.sol index ebcae638a..134e9d8a8 100644 --- a/test/libsolidity/semanticTests/array/inline_array_strings_from_document.sol +++ b/test/libsolidity/semanticTests/array/inline_array_strings_from_document.sol @@ -5,6 +5,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint256): 0 -> 0x20, 0x4, "This" // f(uint256): 1 -> 0x20, 0x2, "is" diff --git a/test/libsolidity/semanticTests/calldata/calldata_internal_function_pointer.sol b/test/libsolidity/semanticTests/calldata/calldata_internal_function_pointer.sol index 1c900b497..d7993cbd4 100644 --- a/test/libsolidity/semanticTests/calldata/calldata_internal_function_pointer.sol +++ b/test/libsolidity/semanticTests/calldata/calldata_internal_function_pointer.sol @@ -13,5 +13,7 @@ contract C { return this.h(a); } } +// ==== +// compileViaYul: also // ---- // g() -> 0x0700000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/constructor/store_function_in_constructor.sol b/test/libsolidity/semanticTests/constructor/store_function_in_constructor.sol index 72833717d..8541a1434 100644 --- a/test/libsolidity/semanticTests/constructor/store_function_in_constructor.sol +++ b/test/libsolidity/semanticTests/constructor/store_function_in_constructor.sol @@ -16,6 +16,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // use(uint256): 3 -> 6 // result_in_constructor() -> 4 diff --git a/test/libsolidity/semanticTests/constructor/store_function_in_constructor_packed.sol b/test/libsolidity/semanticTests/constructor/store_function_in_constructor_packed.sol new file mode 100644 index 000000000..87c0110db --- /dev/null +++ b/test/libsolidity/semanticTests/constructor/store_function_in_constructor_packed.sol @@ -0,0 +1,25 @@ +contract C { + uint16 public result_in_constructor; + function(uint16) returns (uint16) internal x; + uint16 public other = 0x1fff; + + constructor() { + x = doubleInv; + result_in_constructor = use(2); + } + + function doubleInv(uint16 _arg) public returns (uint16 _ret) { + _ret = ~(_arg * 2); + } + + function use(uint16 _arg) public returns (uint16) { + return x(_arg); + } +} + +// ==== +// compileViaYul: also +// ---- +// use(uint16): 3 -> 0xfff9 +// result_in_constructor() -> 0xfffb +// other() -> 0x1fff diff --git a/test/libsolidity/semanticTests/constructor/store_internal_unused_function_in_constructor.sol b/test/libsolidity/semanticTests/constructor/store_internal_unused_function_in_constructor.sol index 04be9f8ed..e116b2ef8 100644 --- a/test/libsolidity/semanticTests/constructor/store_internal_unused_function_in_constructor.sol +++ b/test/libsolidity/semanticTests/constructor/store_internal_unused_function_in_constructor.sol @@ -14,5 +14,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // t() -> 7 diff --git a/test/libsolidity/semanticTests/constructor/store_internal_unused_library_function_in_constructor.sol b/test/libsolidity/semanticTests/constructor/store_internal_unused_library_function_in_constructor.sol index 7b166489f..89795124a 100644 --- a/test/libsolidity/semanticTests/constructor/store_internal_unused_library_function_in_constructor.sol +++ b/test/libsolidity/semanticTests/constructor/store_internal_unused_library_function_in_constructor.sol @@ -17,5 +17,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // t() -> 7 diff --git a/test/libsolidity/semanticTests/empty_for_loop.sol b/test/libsolidity/semanticTests/empty_for_loop.sol new file mode 100644 index 000000000..5d1c09a9e --- /dev/null +++ b/test/libsolidity/semanticTests/empty_for_loop.sol @@ -0,0 +1,13 @@ +contract test { + function f() public returns(uint ret) { + ret = 1; + for (;;) { + ret += 1; + if (ret >= 10) break; + } + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> 10 diff --git a/test/libsolidity/semanticTests/functionCall/calling_other_functions.sol b/test/libsolidity/semanticTests/functionCall/calling_other_functions.sol new file mode 100644 index 000000000..c06f714c2 --- /dev/null +++ b/test/libsolidity/semanticTests/functionCall/calling_other_functions.sol @@ -0,0 +1,22 @@ +contract collatz { + function run(uint x) public returns(uint y) { + while ((y = x) > 1) { + if (x % 2 == 0) x = evenStep(x); + else x = oddStep(x); + } + } + function evenStep(uint x) public returns(uint y) { + return x / 2; + } + function oddStep(uint x) public returns(uint y) { + return 3 * x + 1; + } +} +// ==== +// compileViaYul: also +// ---- +// run(uint256): 0 -> 0 +// run(uint256): 1 -> 1 +// run(uint256): 2 -> 1 +// run(uint256): 8 -> 1 +// run(uint256): 127 -> 1 diff --git a/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function_in_detail.sol b/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function_in_detail.sol index fd8a377ab..9ff334473 100644 --- a/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function_in_detail.sol +++ b/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function_in_detail.sol @@ -16,5 +16,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // t() -> FAILURE, hex"4e487b71", 0x51 diff --git a/test/libsolidity/semanticTests/functionTypes/function_delete_storage.sol b/test/libsolidity/semanticTests/functionTypes/function_delete_storage.sol index 49455918b..96800da06 100644 --- a/test/libsolidity/semanticTests/functionTypes/function_delete_storage.sol +++ b/test/libsolidity/semanticTests/functionTypes/function_delete_storage.sol @@ -20,6 +20,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // set() -> 7 // ca() -> 7 diff --git a/test/libsolidity/semanticTests/functionTypes/inline_array_with_value_call_option.sol b/test/libsolidity/semanticTests/functionTypes/inline_array_with_value_call_option.sol index e65da6e1e..3b9a70aa1 100644 --- a/test/libsolidity/semanticTests/functionTypes/inline_array_with_value_call_option.sol +++ b/test/libsolidity/semanticTests/functionTypes/inline_array_with_value_call_option.sol @@ -6,5 +6,7 @@ contract C { return [this.f, this.g][0]{value: 1}(); } } +// ==== +// compileViaYul: also // ---- // h(), 1 ether -> 1 diff --git a/test/libsolidity/semanticTests/functionTypes/mapping_of_functions.sol b/test/libsolidity/semanticTests/functionTypes/mapping_of_functions.sol index 353844723..64f55a420 100644 --- a/test/libsolidity/semanticTests/functionTypes/mapping_of_functions.sol +++ b/test/libsolidity/semanticTests/functionTypes/mapping_of_functions.sol @@ -25,6 +25,8 @@ contract Flow { } } +// ==== +// compileViaYul: also // ---- // success() -> false // f() -> 7 diff --git a/test/libsolidity/semanticTests/functionTypes/pass_function_types_internally.sol b/test/libsolidity/semanticTests/functionTypes/pass_function_types_internally.sol index 0acbcc585..f25a3298e 100644 --- a/test/libsolidity/semanticTests/functionTypes/pass_function_types_internally.sol +++ b/test/libsolidity/semanticTests/functionTypes/pass_function_types_internally.sol @@ -11,5 +11,7 @@ contract C { return x + 1; } } +// ==== +// compileViaYul: also // ---- // f(uint256): 7 -> 8 diff --git a/test/libsolidity/semanticTests/functionTypes/same_function_in_construction_and_runtime_equality_check.sol b/test/libsolidity/semanticTests/functionTypes/same_function_in_construction_and_runtime_equality_check.sol index a778589ab..2a631f332 100644 --- a/test/libsolidity/semanticTests/functionTypes/same_function_in_construction_and_runtime_equality_check.sol +++ b/test/libsolidity/semanticTests/functionTypes/same_function_in_construction_and_runtime_equality_check.sol @@ -14,5 +14,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // test() -> true diff --git a/test/libsolidity/semanticTests/functionTypes/struct_with_functions.sol b/test/libsolidity/semanticTests/functionTypes/struct_with_functions.sol new file mode 100644 index 000000000..6461701c0 --- /dev/null +++ b/test/libsolidity/semanticTests/functionTypes/struct_with_functions.sol @@ -0,0 +1,34 @@ +struct S { + uint16 a; + function() returns (uint) x; + uint16 b; +} +contract Flow { + S[2] t; + + function X() internal pure returns (uint) { + return 1; + } + + function Y() internal pure returns (uint) { + return 2; + } + + constructor() { + t[0].a = 0xff07; + t[0].b = 0xff07; + t[1].x = Y; + t[1].a = 0xff07; + t[1].b = 0xff07; + t[0].x = X; + } + + function f() public returns (uint, uint) { + return (t[0].x(), t[1].x()); + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 1, 2 diff --git a/test/libsolidity/semanticTests/functionTypes/uninitialized_internal_storage_function_call.sol b/test/libsolidity/semanticTests/functionTypes/uninitialized_internal_storage_function_call.sol index 85c2519dc..942099a77 100644 --- a/test/libsolidity/semanticTests/functionTypes/uninitialized_internal_storage_function_call.sol +++ b/test/libsolidity/semanticTests/functionTypes/uninitialized_internal_storage_function_call.sol @@ -7,5 +7,7 @@ contract Test { } } +// ==== +// compileViaYul: also // ---- // f() -> FAILURE, hex"4e487b71", 0x51 diff --git a/test/libsolidity/semanticTests/integer/many_local_variables.sol b/test/libsolidity/semanticTests/integer/many_local_variables.sol new file mode 100644 index 000000000..b626f730d --- /dev/null +++ b/test/libsolidity/semanticTests/integer/many_local_variables.sol @@ -0,0 +1,11 @@ +contract test { + function run(uint x1, uint x2, uint x3) public returns(uint y) { + uint8 a = 0x1; uint8 b = 0x10; uint16 c = 0x100; + y = a + b + c + x1 + x2 + x3; + y += b + x2; + } +} +// ==== +// compileViaYul: also +// ---- +// run(uint256,uint256,uint256): 0x1000, 0x10000, 0x100000 -> 0x121121 diff --git a/test/libsolidity/semanticTests/integer/small_signed_types.sol b/test/libsolidity/semanticTests/integer/small_signed_types.sol new file mode 100644 index 000000000..8180f7a9c --- /dev/null +++ b/test/libsolidity/semanticTests/integer/small_signed_types.sol @@ -0,0 +1,9 @@ +contract test { + function run() public returns(int256 y) { + return -int32(10) * -int64(20); + } +} +// ==== +// compileViaYul: also +// ---- +// run() -> 200 diff --git a/test/libsolidity/semanticTests/interfaceID/homer.sol b/test/libsolidity/semanticTests/interfaceID/homer.sol index 243cba0b4..148e08f0f 100644 --- a/test/libsolidity/semanticTests/interfaceID/homer.sol +++ b/test/libsolidity/semanticTests/interfaceID/homer.sol @@ -29,6 +29,8 @@ contract Homer is ERC165, Simpson { } } +// ==== +// compileViaYul: also // ---- // supportsInterface(bytes4): left(0x01ffc9a0) -> false // supportsInterface(bytes4): left(0x01ffc9a7) -> true diff --git a/test/libsolidity/semanticTests/interfaceID/lisa.sol b/test/libsolidity/semanticTests/interfaceID/lisa.sol index 885cf9b24..7c50b5f16 100644 --- a/test/libsolidity/semanticTests/interfaceID/lisa.sol +++ b/test/libsolidity/semanticTests/interfaceID/lisa.sol @@ -40,6 +40,8 @@ contract Lisa is ERC165MappingImplementation, Simpson { } } +// ==== +// compileViaYul: also // ---- // supportsInterface(bytes4): left(0x01ffc9a0) -> false // supportsInterface(bytes4): left(0x01ffc9a7) -> true diff --git a/test/libsolidity/semanticTests/intheritance/base_access_to_function_type_variables.sol b/test/libsolidity/semanticTests/intheritance/base_access_to_function_type_variables.sol index 5f56f78ed..9dec3fc70 100644 --- a/test/libsolidity/semanticTests/intheritance/base_access_to_function_type_variables.sol +++ b/test/libsolidity/semanticTests/intheritance/base_access_to_function_type_variables.sol @@ -14,6 +14,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // g() -> 2 // h() -> FAILURE, hex"4e487b71", 0x51 diff --git a/test/libsolidity/semanticTests/operators/compound_assign.sol b/test/libsolidity/semanticTests/operators/compound_assign.sol new file mode 100644 index 000000000..6796ed23c --- /dev/null +++ b/test/libsolidity/semanticTests/operators/compound_assign.sol @@ -0,0 +1,22 @@ +contract test { + uint value1; + uint value2; + function f(uint x, uint y) public returns (uint w) { + uint value3 = y; + value1 += x; + value3 *= x; + value2 *= value3 + value1; + return value2 += 7; + } +} +// ==== +// compileViaYul: also +// ---- +// f(uint256,uint256): 0, 6 -> 7 +// f(uint256,uint256): 1, 3 -> 0x23 +// f(uint256,uint256): 2, 25 -> 0x0746 +// f(uint256,uint256): 3, 69 -> 396613 +// f(uint256,uint256): 4, 84 -> 137228105 +// f(uint256,uint256): 5, 2 -> 0xcc7c5e28 +// f(uint256,uint256): 6, 51 -> 1121839760671 +// f(uint256,uint256): 7, 48 -> 408349672884251 diff --git a/test/libsolidity/semanticTests/shifts/bitwise_shifting_constantinople.sol b/test/libsolidity/semanticTests/operators/shifts/bitwise_shifting_constantinople.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/bitwise_shifting_constantinople.sol rename to test/libsolidity/semanticTests/operators/shifts/bitwise_shifting_constantinople.sol diff --git a/test/libsolidity/semanticTests/shifts/bitwise_shifting_constantinople_combined.sol b/test/libsolidity/semanticTests/operators/shifts/bitwise_shifting_constantinople_combined.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/bitwise_shifting_constantinople_combined.sol rename to test/libsolidity/semanticTests/operators/shifts/bitwise_shifting_constantinople_combined.sol diff --git a/test/libsolidity/semanticTests/shifts/bitwise_shifting_constants_constantinople.sol b/test/libsolidity/semanticTests/operators/shifts/bitwise_shifting_constants_constantinople.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/bitwise_shifting_constants_constantinople.sol rename to test/libsolidity/semanticTests/operators/shifts/bitwise_shifting_constants_constantinople.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_cleanup.sol b/test/libsolidity/semanticTests/operators/shifts/shift_cleanup.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_cleanup.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_cleanup.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_cleanup_garbled.sol b/test/libsolidity/semanticTests/operators/shifts/shift_cleanup_garbled.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_cleanup_garbled.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_cleanup_garbled.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_constant_left.sol b/test/libsolidity/semanticTests/operators/shifts/shift_constant_left.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_constant_left.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_constant_left.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_constant_left_assignment.sol b/test/libsolidity/semanticTests/operators/shifts/shift_constant_left_assignment.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_constant_left_assignment.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_constant_left_assignment.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_constant_right.sol b/test/libsolidity/semanticTests/operators/shifts/shift_constant_right.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_constant_right.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_constant_right.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_constant_right_assignment.sol b/test/libsolidity/semanticTests/operators/shifts/shift_constant_right_assignment.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_constant_right_assignment.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_constant_right_assignment.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_left.sol b/test/libsolidity/semanticTests/operators/shifts/shift_left.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_left.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_left.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_left_assignment.sol b/test/libsolidity/semanticTests/operators/shifts/shift_left_assignment.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_left_assignment.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_left_assignment.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_left_assignment_different_type.sol b/test/libsolidity/semanticTests/operators/shifts/shift_left_assignment_different_type.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_left_assignment_different_type.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_left_assignment_different_type.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_left_larger_type.sol b/test/libsolidity/semanticTests/operators/shifts/shift_left_larger_type.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_left_larger_type.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_left_larger_type.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_left_uint32.sol b/test/libsolidity/semanticTests/operators/shifts/shift_left_uint32.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_left_uint32.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_left_uint32.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_left_uint8.sol b/test/libsolidity/semanticTests/operators/shifts/shift_left_uint8.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_left_uint8.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_left_uint8.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_negative_constant_left.sol b/test/libsolidity/semanticTests/operators/shifts/shift_negative_constant_left.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_negative_constant_left.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_negative_constant_left.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_negative_constant_right.sol b/test/libsolidity/semanticTests/operators/shifts/shift_negative_constant_right.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_negative_constant_right.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_negative_constant_right.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_overflow.sol b/test/libsolidity/semanticTests/operators/shifts/shift_overflow.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_overflow.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_overflow.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_right.sol b/test/libsolidity/semanticTests/operators/shifts/shift_right.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_right.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_right.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_right_assignment.sol b/test/libsolidity/semanticTests/operators/shifts/shift_right_assignment.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_right_assignment.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_right_assignment.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_right_garbled.sol b/test/libsolidity/semanticTests/operators/shifts/shift_right_garbled.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_right_garbled.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_right_garbled.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_right_garbled_signed.sol b/test/libsolidity/semanticTests/operators/shifts/shift_right_garbled_signed.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_right_garbled_signed.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_right_garbled_signed.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_right_garbled_signed_v2.sol b/test/libsolidity/semanticTests/operators/shifts/shift_right_garbled_signed_v2.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_right_garbled_signed_v2.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_right_garbled_signed_v2.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_right_garbled_v2.sol b/test/libsolidity/semanticTests/operators/shifts/shift_right_garbled_v2.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_right_garbled_v2.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_right_garbled_v2.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_literal.sol b/test/libsolidity/semanticTests/operators/shifts/shift_right_negative_literal.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_right_negative_literal.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_right_negative_literal.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue.sol b/test/libsolidity/semanticTests/operators/shifts/shift_right_negative_lvalue.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_right_negative_lvalue.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_assignment.sol b/test/libsolidity/semanticTests/operators/shifts/shift_right_negative_lvalue_assignment.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_assignment.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_right_negative_lvalue_assignment.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int16.sol b/test/libsolidity/semanticTests/operators/shifts/shift_right_negative_lvalue_int16.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int16.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_right_negative_lvalue_int16.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int32.sol b/test/libsolidity/semanticTests/operators/shifts/shift_right_negative_lvalue_int32.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int32.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_right_negative_lvalue_int32.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int8.sol b/test/libsolidity/semanticTests/operators/shifts/shift_right_negative_lvalue_int8.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int8.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_right_negative_lvalue_int8.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int16.sol b/test/libsolidity/semanticTests/operators/shifts/shift_right_negative_lvalue_signextend_int16.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int16.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_right_negative_lvalue_signextend_int16.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int16_v2.sol b/test/libsolidity/semanticTests/operators/shifts/shift_right_negative_lvalue_signextend_int16_v2.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int16_v2.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_right_negative_lvalue_signextend_int16_v2.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int32.sol b/test/libsolidity/semanticTests/operators/shifts/shift_right_negative_lvalue_signextend_int32.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int32.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_right_negative_lvalue_signextend_int32.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int32_v2.sol b/test/libsolidity/semanticTests/operators/shifts/shift_right_negative_lvalue_signextend_int32_v2.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int32_v2.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_right_negative_lvalue_signextend_int32_v2.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int8.sol b/test/libsolidity/semanticTests/operators/shifts/shift_right_negative_lvalue_signextend_int8.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int8.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_right_negative_lvalue_signextend_int8.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int8_v2.sol b/test/libsolidity/semanticTests/operators/shifts/shift_right_negative_lvalue_signextend_int8_v2.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int8_v2.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_right_negative_lvalue_signextend_int8_v2.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_right_uint32.sol b/test/libsolidity/semanticTests/operators/shifts/shift_right_uint32.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_right_uint32.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_right_uint32.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_right_uint8.sol b/test/libsolidity/semanticTests/operators/shifts/shift_right_uint8.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_right_uint8.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_right_uint8.sol diff --git a/test/libsolidity/semanticTests/shifts/shift_underflow_negative_rvalue.sol b/test/libsolidity/semanticTests/operators/shifts/shift_underflow_negative_rvalue.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shift_underflow_negative_rvalue.sol rename to test/libsolidity/semanticTests/operators/shifts/shift_underflow_negative_rvalue.sol diff --git a/test/libsolidity/semanticTests/shifts/shifts.sol b/test/libsolidity/semanticTests/operators/shifts/shifts.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts/shifts.sol rename to test/libsolidity/semanticTests/operators/shifts/shifts.sol diff --git a/test/libsolidity/semanticTests/reverts/invalid_enum_stored.sol b/test/libsolidity/semanticTests/reverts/invalid_enum_stored.sol index 8049a977e..74853a7f4 100644 --- a/test/libsolidity/semanticTests/reverts/invalid_enum_stored.sol +++ b/test/libsolidity/semanticTests/reverts/invalid_enum_stored.sol @@ -17,6 +17,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >=byzantium // ---- // test_store_ok() -> 1 diff --git a/test/libsolidity/semanticTests/smoke/alignment.sol b/test/libsolidity/semanticTests/smoke/alignment.sol index 621581468..bb4ba9317 100644 --- a/test/libsolidity/semanticTests/smoke/alignment.sol +++ b/test/libsolidity/semanticTests/smoke/alignment.sol @@ -18,6 +18,8 @@ contract D { return (stateBool, stateDecimal, stateBytes); } } +// ==== +// compileViaYul: also // ---- // stateBool() -> true // stateBool() -> right(true) diff --git a/test/libsolidity/semanticTests/smoke/arrays.sol b/test/libsolidity/semanticTests/smoke/arrays.sol index 34ec984bb..67706929e 100644 --- a/test/libsolidity/semanticTests/smoke/arrays.sol +++ b/test/libsolidity/semanticTests/smoke/arrays.sol @@ -32,6 +32,8 @@ contract C { return (["any", "any"], ["any", "any", "any"]); } } +// ==== +// compileViaYul: also // ---- // r() -> true, false, true // s() -> 123, 456, 789 @@ -41,4 +43,3 @@ contract C { // w2() -> 0x20, 0x40, 0x80, 3, "any", 3, "any" // w3() -> 0x20, 0x60, 0xa0, 0xe0, 3, "any", 3, "any", 3, "any" // x() -> 0x40, 0x0100, 0x40, 0x80, 3, "any", 3, "any", 0x60, 0xa0, 0xe0, 3, "any", 3, "any", 3, "any" - diff --git a/test/libsolidity/semanticTests/storage/empty_nonempty_empty.sol b/test/libsolidity/semanticTests/storage/empty_nonempty_empty.sol index 70d72ac62..234f0191f 100644 --- a/test/libsolidity/semanticTests/storage/empty_nonempty_empty.sol +++ b/test/libsolidity/semanticTests/storage/empty_nonempty_empty.sol @@ -2,6 +2,8 @@ contract Test { bytes x; function set(bytes memory _a) public { x = _a; } } +// ==== +// compileViaYul: also // ---- // set(bytes): 0x20, 3, "abc" // storage: nonempty diff --git a/test/libsolidity/semanticTests/storage/mapping_state.sol b/test/libsolidity/semanticTests/storage/mapping_state.sol new file mode 100644 index 000000000..28178bca2 --- /dev/null +++ b/test/libsolidity/semanticTests/storage/mapping_state.sol @@ -0,0 +1,46 @@ +contract Ballot { + mapping(address => bool) canVote; + mapping(address => uint) voteCount; + mapping(address => bool) voted; + function getVoteCount(address addr) public returns (uint retVoteCount) { + return voteCount[addr]; + } + function grantVoteRight(address addr) public { + canVote[addr] = true; + } + function vote(address voter, address vote) public returns (bool success) { + if (!canVote[voter] || voted[voter]) return false; + voted[voter] = true; + voteCount[vote] = voteCount[vote] + 1; + return true; + } +} +// ==== +// compileViaYul: also +// ---- +// getVoteCount(address): 0 -> 0 +// getVoteCount(address): 1 -> 0 +// getVoteCount(address): 2 -> 0 +// vote(address,address): 0, 2 -> false +// getVoteCount(address): 0 -> 0 +// getVoteCount(address): 1 -> 0 +// getVoteCount(address): 2 -> 0 +// grantVoteRight(address): 0 -> +// grantVoteRight(address): 1 -> +// vote(address,address): 0, 2 -> true +// getVoteCount(address): 0 -> 0 +// getVoteCount(address): 1 -> 0 +// getVoteCount(address): 2 -> 1 +// vote(address,address): 0, 1 -> false +// getVoteCount(address): 0 -> 0 +// getVoteCount(address): 1 -> 0 +// getVoteCount(address): 2 -> 1 +// vote(address,address): 2, 1 -> false +// getVoteCount(address): 0 -> 0 +// getVoteCount(address): 1 -> 0 +// getVoteCount(address): 2 -> 1 +// grantVoteRight(address): 2 -> +// vote(address,address): 2, 1 -> true +// getVoteCount(address): 0 -> 0 +// getVoteCount(address): 1 -> 1 +// getVoteCount(address): 2 -> 1 diff --git a/test/libsolidity/semanticTests/structs/array_of_recursive_struct.sol b/test/libsolidity/semanticTests/structs/array_of_recursive_struct.sol index 16ee9d59b..8aa27c062 100644 --- a/test/libsolidity/semanticTests/structs/array_of_recursive_struct.sol +++ b/test/libsolidity/semanticTests/structs/array_of_recursive_struct.sol @@ -8,5 +8,7 @@ contract Test { assert(val[0].vals.length == 42); } } -// ----- +// ==== +// compileViaYul: also +// ---- // func() -> diff --git a/test/libsolidity/semanticTests/uninitializedFunctionPointer/store2.sol b/test/libsolidity/semanticTests/uninitializedFunctionPointer/store2.sol index 1c1e596ab..b46adaf18 100644 --- a/test/libsolidity/semanticTests/uninitializedFunctionPointer/store2.sol +++ b/test/libsolidity/semanticTests/uninitializedFunctionPointer/store2.sol @@ -35,5 +35,7 @@ contract InvalidTest { x++; } } +// ==== +// compileViaYul: also // ---- // run() -> FAILURE, hex"4e487b71", 0x51 diff --git a/test/libsolidity/semanticTests/uninitializedFunctionPointer/storeInConstructor.sol b/test/libsolidity/semanticTests/uninitializedFunctionPointer/storeInConstructor.sol index 08a96792c..bc12dc15e 100644 --- a/test/libsolidity/semanticTests/uninitializedFunctionPointer/storeInConstructor.sol +++ b/test/libsolidity/semanticTests/uninitializedFunctionPointer/storeInConstructor.sol @@ -14,6 +14,8 @@ contract InvalidTest { storedFn(); } } +// ==== +// compileViaYul: also // ---- // f() -> FAILURE, hex"4e487b71", 0x51 // f() -> FAILURE, hex"4e487b71", 0x51 diff --git a/test/libsolidity/semanticTests/various/destructuring_assignment.sol b/test/libsolidity/semanticTests/various/destructuring_assignment.sol index 0c8dc3835..345d76ca1 100644 --- a/test/libsolidity/semanticTests/various/destructuring_assignment.sol +++ b/test/libsolidity/semanticTests/various/destructuring_assignment.sol @@ -32,5 +32,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(bytes): 0x20, 0x5, "abcde" -> 0 diff --git a/test/libsolidity/semanticTests/various/skip_dynamic_types_for_static_arrays_with_dynamic_elements.sol b/test/libsolidity/semanticTests/various/skip_dynamic_types_for_static_arrays_with_dynamic_elements.sol index 86509cfe4..b320c2bce 100644 --- a/test/libsolidity/semanticTests/various/skip_dynamic_types_for_static_arrays_with_dynamic_elements.sol +++ b/test/libsolidity/semanticTests/various/skip_dynamic_types_for_static_arrays_with_dynamic_elements.sol @@ -19,5 +19,7 @@ contract C { return (a, b); } } +// ==== +// compileViaYul: also // ---- // g() -> 5, 6 diff --git a/test/libsolidity/semanticTests/various/store_bytes.sol b/test/libsolidity/semanticTests/various/store_bytes.sol index 4b92a251a..34c0b6f3d 100644 --- a/test/libsolidity/semanticTests/various/store_bytes.sol +++ b/test/libsolidity/semanticTests/various/store_bytes.sol @@ -8,6 +8,8 @@ contract C { bytes savedData; } +// ==== +// compileViaYul: also // ---- // save() -> 24 # empty copy loop # // save(): "abcdefg" -> 24 diff --git a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_1.sol b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_1.sol index 8950f1ca1..f0f5e7a64 100644 --- a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_1.sol +++ b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_1.sol @@ -8,4 +8,4 @@ contract C { } } // ---- -// Warning 2529: (82-89): CHC: Empty array "pop" detected here. +// Warning 2529: (82-89): CHC: Empty array "pop" happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_2.sol b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_2.sol index cd16d340d..b5af63dc3 100644 --- a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_2.sol +++ b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_2.sol @@ -8,4 +8,4 @@ contract C { } } // ---- -// Warning 2529: (82-89): CHC: Empty array "pop" detected here. +// Warning 2529: (82-89): CHC: Empty array "pop" happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_3.sol b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_3.sol index ea8679afd..3e73eb4e2 100644 --- a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_3.sol +++ b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_3.sol @@ -8,5 +8,5 @@ contract C { } } // ---- -// Warning 2529: (82-89): CHC: Empty array "pop" detected here. -// Warning 2529: (93-100): CHC: Empty array "pop" detected here. +// Warning 2529: (82-89): CHC: Empty array "pop" happens here. +// Warning 2529: (93-100): CHC: Empty array "pop" happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_4.sol b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_4.sol index 28f309e43..242942b23 100644 --- a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_4.sol +++ b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_4.sol @@ -8,4 +8,4 @@ contract C { } } // ---- -// Warning 2529: (94-101): CHC: Empty array "pop" detected here. +// Warning 2529: (94-101): CHC: Empty array "pop" happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_5.sol b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_5.sol index 0d8c689c5..ccd5aaf11 100644 --- a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_5.sol +++ b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_5.sol @@ -11,4 +11,4 @@ contract C { } } // ---- -// Warning 2529: (122-129): CHC: Empty array "pop" detected here. +// Warning 2529: (122-129): CHC: Empty array "pop" happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_6.sol b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_6.sol index 8847d29f2..28370af59 100644 --- a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_6.sol +++ b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_6.sol @@ -11,4 +11,4 @@ contract C { } } // ---- -// Warning 2529: (127-134): CHC: Empty array "pop" detected here. +// Warning 2529: (127-134): CHC: Empty array "pop" happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_8.sol b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_8.sol index 4f14142b1..ec96a274d 100644 --- a/test/libsolidity/smtCheckerTests/array_members/array_pop_length_8.sol +++ b/test/libsolidity/smtCheckerTests/array_members/array_pop_length_8.sol @@ -13,4 +13,4 @@ contract C { } } // ---- -// Warning 2529: (82-89): CHC: Empty array "pop" detected here. +// Warning 2529: (82-89): CHC: Empty array "pop" happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/pop_1_unsafe.sol b/test/libsolidity/smtCheckerTests/array_members/pop_1_unsafe.sol index 2073cec2e..6aebb6104 100644 --- a/test/libsolidity/smtCheckerTests/array_members/pop_1_unsafe.sol +++ b/test/libsolidity/smtCheckerTests/array_members/pop_1_unsafe.sol @@ -7,4 +7,4 @@ contract C { } } // ---- -// Warning 2529: (82-89): CHC: Empty array "pop" detected here. +// Warning 2529: (82-89): CHC: Empty array "pop" happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/pop_2d_unsafe.sol b/test/libsolidity/smtCheckerTests/array_members/pop_2d_unsafe.sol index e90a9175a..da299e5e8 100644 --- a/test/libsolidity/smtCheckerTests/array_members/pop_2d_unsafe.sol +++ b/test/libsolidity/smtCheckerTests/array_members/pop_2d_unsafe.sol @@ -9,4 +9,4 @@ contract C { } } // ---- -// Warning 2529: (111-121): CHC: Empty array "pop" detected here. +// Warning 2529: (111-121): CHC: Empty array "pop" happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/pop_constructor_unsafe.sol b/test/libsolidity/smtCheckerTests/array_members/pop_constructor_unsafe.sol index e42659cde..055167bd8 100644 --- a/test/libsolidity/smtCheckerTests/array_members/pop_constructor_unsafe.sol +++ b/test/libsolidity/smtCheckerTests/array_members/pop_constructor_unsafe.sol @@ -7,4 +7,4 @@ contract C { } } // ---- -// Warning 2529: (76-83): CHC: Empty array "pop" detected here. +// Warning 2529: (76-83): CHC: Empty array "pop" happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/pop_loop_unsafe.sol b/test/libsolidity/smtCheckerTests/array_members/pop_loop_unsafe.sol index d94e3cabe..a12e8098f 100644 --- a/test/libsolidity/smtCheckerTests/array_members/pop_loop_unsafe.sol +++ b/test/libsolidity/smtCheckerTests/array_members/pop_loop_unsafe.sol @@ -11,4 +11,4 @@ contract C { } } // ---- -// Warning 2529: (150-157): CHC: Empty array "pop" detected here. +// Warning 2529: (150-157): CHC: Empty array "pop" happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/push_as_lhs_1d.sol b/test/libsolidity/smtCheckerTests/array_members/push_as_lhs_1d.sol new file mode 100644 index 000000000..bf2cab345 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/array_members/push_as_lhs_1d.sol @@ -0,0 +1,21 @@ +pragma experimental SMTChecker; + +contract C { + uint[] b; + + function f() public { + require(b.length == 0); + b.push() = 1; + assert(b[0] == 1); + } + + function g() public { + b.push() = 1; + assert(b[b.length - 1] == 1); + // Fails + assert(b[b.length - 1] == 100); + } + +} +// ---- +// Warning 6328: (232-262): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/push_as_lhs_2d.sol b/test/libsolidity/smtCheckerTests/array_members/push_as_lhs_2d.sol new file mode 100644 index 000000000..5eebd74a1 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/array_members/push_as_lhs_2d.sol @@ -0,0 +1,24 @@ +pragma experimental SMTChecker; + +contract C { + uint[][] c; + + function f() public { + require(c.length == 0); + c.push().push() = 2; + assert(c.length == 1); + assert(c[0].length == 1); + assert(c[0][0] == 2); + } + + function g() public { + c.push().push() = 2; + assert(c.length > 0); + assert(c[c.length - 1].length == 1); + assert(c[c.length - 1][c[c.length - 1].length - 1] == 2); + // Fails + assert(c[c.length - 1][c[c.length - 1].length - 1] == 200); + } +} +// ---- +// Warning 6328: (395-453): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/push_as_lhs_2d_2.sol b/test/libsolidity/smtCheckerTests/array_members/push_as_lhs_2d_2.sol new file mode 100644 index 000000000..90222a591 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/array_members/push_as_lhs_2d_2.sol @@ -0,0 +1,9 @@ +pragma experimental SMTChecker; +contract C { + int[][] array2d; + function s() public returns (int[] memory) { + array2d.push() = array2d.push(); + assert(array2d[array2d.length - 1].length == array2d[array2d.length - 2].length); + return array2d[2]; + } +} diff --git a/test/libsolidity/smtCheckerTests/array_members/push_as_lhs_3d.sol b/test/libsolidity/smtCheckerTests/array_members/push_as_lhs_3d.sol new file mode 100644 index 000000000..fa8965eab --- /dev/null +++ b/test/libsolidity/smtCheckerTests/array_members/push_as_lhs_3d.sol @@ -0,0 +1,30 @@ +pragma experimental SMTChecker; + +contract C { + uint[][][] c; + + function f() public { + require(c.length == 0); + c.push().push().push() = 2; + assert(c.length == 1); + assert(c[0].length == 1); + assert(c[0][0].length == 1); + assert(c[0][0][0] == 2); + } + + function g() public { + c.push().push().push() = 2; + uint length1 = c.length; + uint length2 = c[length1 - 1].length; + uint length3 = c[length1 - 1][length2 - 1].length; + assert(length1 > 0); + assert(length2 == 1); + assert(length3 == 1); + assert(c[length1 - 1][length2 - 1][length3 - 1] == 2); + // Fails + assert(c[length1 - 1][length2 - 1][length3 - 1] == 200); + } +} +// ---- +// Warning 6328: (570-625): CHC: Assertion violation might happen here. +// Warning 4661: (570-625): BMC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/push_as_lhs_and_rhs_1d.sol b/test/libsolidity/smtCheckerTests/array_members/push_as_lhs_and_rhs_1d.sol new file mode 100644 index 000000000..cf7aebd4f --- /dev/null +++ b/test/libsolidity/smtCheckerTests/array_members/push_as_lhs_and_rhs_1d.sol @@ -0,0 +1,16 @@ +pragma experimental SMTChecker; + +contract C { + uint[] b; + function f() public { + b.push() = b.push(); + uint length = b.length; + assert(length >= 2); + assert(b[length - 1] == 0); + assert(b[length - 1] == b[length - 2]); + // Fails + assert(b[length - 1] == 1); + } +} +// ---- +// Warning 6328: (237-263): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/push_as_lhs_and_rhs_2d_1.sol b/test/libsolidity/smtCheckerTests/array_members/push_as_lhs_and_rhs_2d_1.sol new file mode 100644 index 000000000..3cffe84b3 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/array_members/push_as_lhs_and_rhs_2d_1.sol @@ -0,0 +1,19 @@ +pragma experimental SMTChecker; + +contract C { + uint[][] b; + function f() public { + require(b.length == 0); + b.push().push() = b.push().push(); + assert(b.length == 2); + assert(b[0].length == 1); + assert(b[0].length == 1); + assert(b[0][0] == 0); + assert(b[1][0] == 0); + assert(b[0][0] == b[1][0]); + // Fails + assert(b[0][0] != b[1][0]); + } +} +// ---- +// Warning 6328: (317-343): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/array_members/push_as_lhs_and_rhs_2d_2.sol b/test/libsolidity/smtCheckerTests/array_members/push_as_lhs_and_rhs_2d_2.sol new file mode 100644 index 000000000..69b62803a --- /dev/null +++ b/test/libsolidity/smtCheckerTests/array_members/push_as_lhs_and_rhs_2d_2.sol @@ -0,0 +1,15 @@ +pragma experimental SMTChecker; + +contract C { + uint[][] b; + function f() public { + b.push().push() = b.push().push(); + uint length = b.length; + assert(length >= 2); + uint length1 = b[length - 1].length; + uint length2 = b[length - 2].length; + assert(length1 == 1); + assert(length2 == 1); + assert(b[length - 1][length1 - 1] == 0); + } +} diff --git a/test/libsolidity/smtCheckerTests/array_members/push_as_lhs_struct.sol b/test/libsolidity/smtCheckerTests/array_members/push_as_lhs_struct.sol new file mode 100644 index 000000000..87773a7ea --- /dev/null +++ b/test/libsolidity/smtCheckerTests/array_members/push_as_lhs_struct.sol @@ -0,0 +1,15 @@ +pragma experimental SMTChecker; +contract C { + struct S { + int[] b; + } + S s; + struct T { + S s; + } + T t; + function f() public { + s.b.push() = t.s.b.push(); + assert(s.b[s.b.length -1] == t.s.b[t.s.b.length - 1]); + } +} diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_4.sol b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_4.sol index 69e2233ee..bf8ff11d5 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_4.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_4.sol @@ -18,6 +18,6 @@ contract A is B { } } // ---- -// Warning 4984: (198-203): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. // Warning 4984: (207-212): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4984: (198-203): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. // Warning 4984: (230-235): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_state_value_parameter.sol b/test/libsolidity/smtCheckerTests/functions/constructor_state_value_parameter.sol index 4da5ff525..121611dc3 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_state_value_parameter.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_state_value_parameter.sol @@ -13,5 +13,5 @@ contract C { } } // ---- -// Warning 4984: (115-120): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. // Warning 6328: (162-176): CHC: Assertion violation happens here. +// Warning 4984: (115-120): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/imports/imported_fail_1.sol b/test/libsolidity/smtCheckerTests/imports/imported_fail_1.sol index cfa1c8cf4..f619b6a9f 100644 --- a/test/libsolidity/smtCheckerTests/imports/imported_fail_1.sol +++ b/test/libsolidity/smtCheckerTests/imports/imported_fail_1.sol @@ -21,4 +21,5 @@ contract B is A { } } // ---- +// Warning 6328: (B.sol:71-85): CHC: Assertion violation happens here. // Warning 6328: (C.sol:103-117): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/imports/private_vars.sol b/test/libsolidity/smtCheckerTests/imports/private_vars.sol new file mode 100644 index 000000000..c17cdb46f --- /dev/null +++ b/test/libsolidity/smtCheckerTests/imports/private_vars.sol @@ -0,0 +1,16 @@ +==== Source: ERC20.sol ==== +pragma experimental SMTChecker; +contract ERC20 { + uint256 private a; + function f() internal virtual { + a = 2; + } +} +==== Source: Token.sol ==== +pragma experimental SMTChecker; +import "ERC20.sol"; +contract Token is ERC20 { + constructor() { + f(); + } +} diff --git a/test/libsolidity/smtCheckerTests/loops/for_1_false_positive.sol b/test/libsolidity/smtCheckerTests/loops/for_1_false_positive.sol index 29afb548f..10cda8723 100644 --- a/test/libsolidity/smtCheckerTests/loops/for_1_false_positive.sol +++ b/test/libsolidity/smtCheckerTests/loops/for_1_false_positive.sol @@ -15,4 +15,6 @@ contract C } // ---- // Warning 4984: (176-181): CHC: Overflow (resulting value larger than 2**256 - 1) might happen here. +// Warning 6328: (296-309): CHC: Assertion violation might happen here. // Warning 2661: (176-181): BMC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 4661: (296-309): BMC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_memory_memory.sol b/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_memory_memory.sol index 97f9b658c..99ecca3f6 100644 --- a/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_memory_memory.sol +++ b/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_memory_memory.sol @@ -16,5 +16,7 @@ contract LoopFor2 { } } // ---- +// Warning 4984: (252-257): CHC: Overflow (resulting value larger than 2**256 - 1) might happen here. +// Warning 4984: (232-238): CHC: Overflow (resulting value larger than 2**256 - 1) might happen here. // Warning 6328: (373-392): CHC: Assertion violation happens here. // Warning 6328: (396-415): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_memory_storage.sol b/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_memory_storage.sol index ce8784f09..9b2cc7e94 100644 --- a/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_memory_storage.sol +++ b/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_memory_storage.sol @@ -20,3 +20,5 @@ contract LoopFor2 { // ==== // SMTSolvers: z3 // ---- +// Warning 4984: (245-250): CHC: Overflow (resulting value larger than 2**256 - 1) might happen here. +// Warning 4984: (225-231): CHC: Overflow (resulting value larger than 2**256 - 1) might happen here. diff --git a/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_storage_memory.sol b/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_storage_memory.sol index b3581fbc0..0e925049b 100644 --- a/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_storage_memory.sol +++ b/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_storage_memory.sol @@ -19,4 +19,6 @@ contract LoopFor2 { } } // ---- +// Warning 4984: (236-241): CHC: Overflow (resulting value larger than 2**256 - 1) might happen here. +// Warning 4984: (216-222): CHC: Overflow (resulting value larger than 2**256 - 1) might happen here. // Warning 6328: (363-382): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_storage_storage.sol b/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_storage_storage.sol index 88bb839c1..85584e7d3 100644 --- a/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_storage_storage.sol +++ b/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_storage_storage.sol @@ -19,5 +19,7 @@ contract LoopFor2 { } } // ---- +// Warning 4984: (237-242): CHC: Overflow (resulting value larger than 2**256 - 1) might happen here. +// Warning 4984: (217-223): CHC: Overflow (resulting value larger than 2**256 - 1) might happen here. // Warning 6328: (341-360): CHC: Assertion violation happens here. // Warning 6328: (364-383): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/loops/while_loop_array_assignment_storage_storage.sol b/test/libsolidity/smtCheckerTests/loops/while_loop_array_assignment_storage_storage.sol index 44a94090b..c76ba05c4 100644 --- a/test/libsolidity/smtCheckerTests/loops/while_loop_array_assignment_storage_storage.sol +++ b/test/libsolidity/smtCheckerTests/loops/while_loop_array_assignment_storage_storage.sol @@ -14,12 +14,12 @@ contract LoopFor2 { c[i] = b[i]; ++i; } - assert(b[0] == c[0]); + //assert(b[0] == c[0]); // Removed because of Spacer's nondeterminism assert(a[0] == 900); assert(b[0] == 900); } } // ---- // Warning 4984: (229-234): CHC: Overflow (resulting value larger than 2**256 - 1) might happen here. -// Warning 6328: (290-309): CHC: Assertion violation happens here. -// Warning 6328: (313-332): CHC: Assertion violation happens here. +// Warning 6328: (338-357): CHC: Assertion violation happens here. +// Warning 6328: (361-380): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/modifiers/modifier_two_invocations_2.sol b/test/libsolidity/smtCheckerTests/modifiers/modifier_two_invocations_2.sol new file mode 100644 index 000000000..04719a6b8 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/modifiers/modifier_two_invocations_2.sol @@ -0,0 +1,19 @@ +pragma experimental SMTChecker; + +contract C +{ + uint x; + + modifier m { + require(x == 0); + _; + x = x + 1; + assert(x <= 2); + } + + function f() m m public { + x = x + 1; + } +} +// ---- +// Warning 6328: (109-123): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/delete_array_push.sol b/test/libsolidity/smtCheckerTests/operators/delete_array_push.sol new file mode 100644 index 000000000..a4dd6cdf7 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/delete_array_push.sol @@ -0,0 +1,20 @@ +pragma experimental SMTChecker; +contract C { + int[][] array2d; + function s() public returns (int[] memory) { + delete array2d.push(); + assert(array2d[array2d.length - 1].length == 0); + // Fails + assert(array2d[array2d.length - 1].length != 0); + delete array2d.push().push(); + uint length = array2d.length; + uint length2 = array2d[length - 1].length; + assert(array2d[length - 1][length2 - 1] == 0); + // Fails + assert(array2d[length - 1][length2 - 1] != 0); + return array2d[2]; + } +} +// ---- +// Warning 6328: (198-245): CHC: Assertion violation happens here. +// Warning 6328: (418-463): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/delete_tuple.sol b/test/libsolidity/smtCheckerTests/operators/delete_tuple.sol new file mode 100644 index 000000000..cb37864d5 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/operators/delete_tuple.sol @@ -0,0 +1,7 @@ +pragma experimental SMTChecker; + +contract A{ + function f() public pure { + delete ([""][0]); + } +} diff --git a/test/libsolidity/smtCheckerTests/operators/slice_default_end.sol b/test/libsolidity/smtCheckerTests/operators/slice_default_end.sol index 4cb63ac44..b35f6f2bb 100644 --- a/test/libsolidity/smtCheckerTests/operators/slice_default_end.sol +++ b/test/libsolidity/smtCheckerTests/operators/slice_default_end.sol @@ -7,14 +7,10 @@ contract C { require(b[b.length - 1] == 0xaa); assert(bytes(b[10:]).length == 20); assert(bytes(b[10:])[0] == 0xff); - assert(bytes(b[10:])[5] == 0xff); + //assert(bytes(b[10:])[5] == 0xff); // Removed because of Spacer's nondeterminism assert(bytes(b[10:])[19] == 0xaa); } } // ---- // Warning 6328: (221-253): CHC: Assertion violation might happen here. -// Warning 6328: (257-289): CHC: Assertion violation might happen here. -// Warning 6328: (293-326): CHC: Assertion violation might happen here. // Warning 4661: (221-253): BMC: Assertion violation happens here. -// Warning 4661: (257-289): BMC: Assertion violation happens here. -// Warning 4661: (293-326): BMC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/overflow_sum.sol b/test/libsolidity/smtCheckerTests/overflow/overflow_sum.sol index 61fa7839c..594eabcde 100644 --- a/test/libsolidity/smtCheckerTests/overflow/overflow_sum.sol +++ b/test/libsolidity/smtCheckerTests/overflow/overflow_sum.sol @@ -14,5 +14,6 @@ contract C } } // ---- +// Warning 4984: (109-116): CHC: Overflow (resulting value larger than 255) happens here. // Warning 4984: (154-159): CHC: Overflow (resulting value larger than 255) happens here. // Warning 4984: (185-192): CHC: Overflow (resulting value larger than 255) happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/safe_add_1.sol b/test/libsolidity/smtCheckerTests/overflow/safe_add_1.sol index 97e7ea343..8a521db60 100644 --- a/test/libsolidity/smtCheckerTests/overflow/safe_add_1.sol +++ b/test/libsolidity/smtCheckerTests/overflow/safe_add_1.sol @@ -7,3 +7,5 @@ contract C return x + y; } } +// ---- +// Warning 4984: (115-120): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/safe_add_2.sol b/test/libsolidity/smtCheckerTests/overflow/safe_add_2.sol index 9b64a8885..c33f7d8da 100644 --- a/test/libsolidity/smtCheckerTests/overflow/safe_add_2.sol +++ b/test/libsolidity/smtCheckerTests/overflow/safe_add_2.sol @@ -8,3 +8,5 @@ contract C return z; } } +// ---- +// Warning 4984: (116-121): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/signed_guard_sum_overflow.sol b/test/libsolidity/smtCheckerTests/overflow/signed_guard_sum_overflow.sol index 84b0f3f42..40c064e9e 100644 --- a/test/libsolidity/smtCheckerTests/overflow/signed_guard_sum_overflow.sol +++ b/test/libsolidity/smtCheckerTests/overflow/signed_guard_sum_overflow.sol @@ -8,4 +8,5 @@ contract C { } // ---- // Warning 3944: (111-116): CHC: Underflow (resulting value less than -57896044618658097711785492504343953926634992332820282019728792003956564819968) happens here. +// Warning 4984: (111-116): CHC: Overflow (resulting value larger than 0x80 * 2**248 - 1) happens here. // Warning 3944: (133-138): CHC: Underflow (resulting value less than -57896044618658097711785492504343953926634992332820282019728792003956564819968) happens here. diff --git a/test/libsolidity/smtCheckerTests/overflow/unsigned_guard_sum_overflow.sol b/test/libsolidity/smtCheckerTests/overflow/unsigned_guard_sum_overflow.sol index 68b782eca..b6bc4d996 100644 --- a/test/libsolidity/smtCheckerTests/overflow/unsigned_guard_sum_overflow.sol +++ b/test/libsolidity/smtCheckerTests/overflow/unsigned_guard_sum_overflow.sol @@ -6,3 +6,5 @@ contract C { return x + y; } } +// ---- +// Warning 4984: (114-119): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/special/many.sol b/test/libsolidity/smtCheckerTests/special/many.sol index 5b16533dc..013775110 100644 --- a/test/libsolidity/smtCheckerTests/special/many.sol +++ b/test/libsolidity/smtCheckerTests/special/many.sol @@ -15,12 +15,12 @@ contract C } } // ---- -// Warning 4984: (311-316): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. // Warning 6328: (79-115): CHC: Assertion violation happens here. // Warning 6328: (119-161): CHC: Assertion violation happens here. // Warning 6328: (165-204): CHC: Assertion violation happens here. // Warning 6328: (208-240): CHC: Assertion violation happens here. // Warning 6328: (244-275): CHC: Assertion violation happens here. +// Warning 4984: (311-316): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. // Warning 6328: (304-332): CHC: Assertion violation happens here. // Warning 6328: (336-364): CHC: Assertion violation happens here. // Warning 6328: (368-391): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/function_type_external_address.sol b/test/libsolidity/smtCheckerTests/types/function_type_external_address.sol index c7b405c50..286ee451b 100644 --- a/test/libsolidity/smtCheckerTests/types/function_type_external_address.sol +++ b/test/libsolidity/smtCheckerTests/types/function_type_external_address.sol @@ -7,4 +7,3 @@ contract C { } // ---- // Warning 7650: (128-137): Assertion checker does not yet support this expression. -// Warning 4661: (141-155): BMC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_state_var_array_pop_1.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_state_var_array_pop_1.sol index 423e2e46c..e849e8e8f 100644 --- a/test/libsolidity/smtCheckerTests/types/struct/struct_state_var_array_pop_1.sol +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_state_var_array_pop_1.sol @@ -21,5 +21,5 @@ contract C { } } // ---- -// Warning 2529: (121-130): CHC: Empty array "pop" detected here. +// Warning 2529: (121-130): CHC: Empty array "pop" happens here. // Warning 6328: (230-254): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_state_var_array_pop_2.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_state_var_array_pop_2.sol index 161460c31..a624f8cc2 100644 --- a/test/libsolidity/smtCheckerTests/types/struct/struct_state_var_array_pop_2.sol +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_state_var_array_pop_2.sol @@ -18,5 +18,5 @@ contract C { } } // ---- -// Warning 2529: (133-142): CHC: Empty array "pop" detected here. +// Warning 2529: (133-142): CHC: Empty array "pop" happens here. // Warning 6328: (189-213): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/tuple_array_pop_1.sol b/test/libsolidity/smtCheckerTests/types/tuple_array_pop_1.sol index c7e061e19..bb850422b 100644 --- a/test/libsolidity/smtCheckerTests/types/tuple_array_pop_1.sol +++ b/test/libsolidity/smtCheckerTests/types/tuple_array_pop_1.sol @@ -4,4 +4,4 @@ contract C { function f() public { (a).pop();} } // ---- -// Warning 2529: (78-87): CHC: Empty array "pop" detected here. +// Warning 2529: (78-87): CHC: Empty array "pop" happens here. diff --git a/test/libsolidity/smtCheckerTests/types/tuple_array_pop_2.sol b/test/libsolidity/smtCheckerTests/types/tuple_array_pop_2.sol index c8c066c15..19a1f4965 100644 --- a/test/libsolidity/smtCheckerTests/types/tuple_array_pop_2.sol +++ b/test/libsolidity/smtCheckerTests/types/tuple_array_pop_2.sol @@ -4,4 +4,4 @@ contract C { function f() public { (((((a))))).pop();} } // ---- -// Warning 2529: (78-95): CHC: Empty array "pop" detected here. +// Warning 2529: (78-95): CHC: Empty array "pop" happens here. diff --git a/test/libsolidity/smtCheckerTests/types/tuple_declarations_function_2.sol b/test/libsolidity/smtCheckerTests/types/tuple_declarations_function_2.sol index 0781b012b..a36209646 100644 --- a/test/libsolidity/smtCheckerTests/types/tuple_declarations_function_2.sol +++ b/test/libsolidity/smtCheckerTests/types/tuple_declarations_function_2.sol @@ -15,4 +15,3 @@ contract C } } // ---- -// Warning 4984: (152-157): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. diff --git a/test/libsolidity/syntaxTests/abiEncoder/conflicting_settings.sol b/test/libsolidity/syntaxTests/abiEncoder/conflicting_settings.sol new file mode 100644 index 000000000..29488de12 --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/conflicting_settings.sol @@ -0,0 +1,4 @@ +pragma experimental ABIEncoderV2; +pragma abicoder v1; +// ---- +// SyntaxError 3845: (34-53): ABI coder has already been selected for this source unit. diff --git a/test/libsolidity/syntaxTests/abiEncoder/conflicting_settings_reverse.sol b/test/libsolidity/syntaxTests/abiEncoder/conflicting_settings_reverse.sol new file mode 100644 index 000000000..855378e9e --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/conflicting_settings_reverse.sol @@ -0,0 +1,4 @@ +pragma abicoder v1; +pragma experimental ABIEncoderV2; +// ---- +// SyntaxError 8273: (20-53): ABI coder v1 has already been selected through "pragma abicoder v1". diff --git a/test/libsolidity/syntaxTests/abiEncoder/invalid_pragma_value.sol b/test/libsolidity/syntaxTests/abiEncoder/invalid_pragma_value.sol new file mode 100644 index 000000000..cbfa03b3f --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/invalid_pragma_value.sol @@ -0,0 +1,3 @@ +pragma abicoder something; +// ---- +// SyntaxError 2745: (0-26): Expected either "pragma abicoder v1" or "pragma abicoder v2". diff --git a/test/libsolidity/syntaxTests/abiEncoder/same_setting_twice.sol b/test/libsolidity/syntaxTests/abiEncoder/same_setting_twice.sol new file mode 100644 index 000000000..0303bcb14 --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/same_setting_twice.sol @@ -0,0 +1,4 @@ +pragma experimental ABIEncoderV2; +pragma abicoder v2; +// ---- +// SyntaxError 3845: (34-53): ABI coder has already been selected for this source unit. diff --git a/test/libsolidity/syntaxTests/abiEncoder/select_v1.sol b/test/libsolidity/syntaxTests/abiEncoder/select_v1.sol new file mode 100644 index 000000000..ecae09ad6 --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/select_v1.sol @@ -0,0 +1 @@ +pragma abicoder v1; \ No newline at end of file diff --git a/test/libsolidity/syntaxTests/abiEncoder/selected_twice.sol b/test/libsolidity/syntaxTests/abiEncoder/selected_twice.sol new file mode 100644 index 000000000..424c2c7f2 --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/selected_twice.sol @@ -0,0 +1,4 @@ +pragma abicoder v1; +pragma abicoder v1; +// ---- +// SyntaxError 3845: (20-39): ABI coder has already been selected for this source unit. diff --git a/test/libsolidity/syntaxTests/abiEncoder/selected_twice_v2.sol b/test/libsolidity/syntaxTests/abiEncoder/selected_twice_v2.sol new file mode 100644 index 000000000..a0d0cf2d8 --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/selected_twice_v2.sol @@ -0,0 +1,2 @@ +pragma abicoder v2; +pragma experimental ABIEncoderV2; \ No newline at end of file diff --git a/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_constructor_accepting_struct.sol b/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_constructor_accepting_struct.sol index 17dfee2c3..c7ecbfff7 100644 --- a/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_constructor_accepting_struct.sol +++ b/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_constructor_accepting_struct.sol @@ -17,4 +17,4 @@ contract Test { } } // ---- -// TypeError 2443: (B:71-80): The type of this parameter, struct C.Item, is only supported in ABIEncoderV2. Use "pragma experimental ABIEncoderV2;" to enable the feature. +// TypeError 2443: (B:71-80): The type of this parameter, struct C.Item, is only supported in ABI coder v2. Use "pragma abicoder v2;" to enable the feature. diff --git a/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_contract_function_accepting_struct_via_named_argument.sol b/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_contract_function_accepting_struct_via_named_argument.sol index bf8663071..220fc1b29 100644 --- a/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_contract_function_accepting_struct_via_named_argument.sol +++ b/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_contract_function_accepting_struct_via_named_argument.sol @@ -17,4 +17,4 @@ contract Test { } } // ---- -// TypeError 2443: (B:90-100): The type of this parameter, struct C.Item, is only supported in ABIEncoderV2. Use "pragma experimental ABIEncoderV2;" to enable the feature. +// TypeError 2443: (B:90-100): The type of this parameter, struct C.Item, is only supported in ABI coder v2. Use "pragma abicoder v2;" to enable the feature. diff --git a/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_contract_function_pointer_accepting_struct.sol b/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_contract_function_pointer_accepting_struct.sol index db6180ff6..be9517f40 100644 --- a/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_contract_function_pointer_accepting_struct.sol +++ b/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_contract_function_pointer_accepting_struct.sol @@ -19,4 +19,4 @@ contract Test { } } // ---- -// TypeError 2443: (B:146-155): The type of this parameter, struct C.Item, is only supported in ABIEncoderV2. Use "pragma experimental ABIEncoderV2;" to enable the feature. +// TypeError 2443: (B:146-155): The type of this parameter, struct C.Item, is only supported in ABI coder v2. Use "pragma abicoder v2;" to enable the feature. diff --git a/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_contract_function_returning_dynamic_string_array.sol b/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_contract_function_returning_dynamic_string_array.sol index 11cdbaefb..24254e5f4 100644 --- a/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_contract_function_returning_dynamic_string_array.sol +++ b/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_contract_function_returning_dynamic_string_array.sol @@ -13,4 +13,4 @@ contract D { } } // ---- -// TypeError 2428: (B:65-76): The type of return parameter 1, string[], is only supported in ABIEncoderV2. Use "pragma experimental ABIEncoderV2;" to enable the feature. +// TypeError 2428: (B:65-76): The type of return parameter 1, string[], is only supported in ABI coder v2. Use "pragma abicoder v2;" to enable the feature. diff --git a/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_contract_function_returning_struct.sol b/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_contract_function_returning_struct.sol index 123073cb0..d62452ab8 100644 --- a/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_contract_function_returning_struct.sol +++ b/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_contract_function_returning_struct.sol @@ -17,4 +17,4 @@ contract Test { } } // ---- -// TypeError 2428: (B:70-83): The type of return parameter 1, struct C.Item, is only supported in ABIEncoderV2. Use "pragma experimental ABIEncoderV2;" to enable the feature. +// TypeError 2428: (B:70-83): The type of return parameter 1, struct C.Item, is only supported in ABI coder v2. Use "pragma abicoder v2;" to enable the feature. diff --git a/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_contract_function_returning_struct_with_dynamic_array.sol b/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_contract_function_returning_struct_with_dynamic_array.sol index 35faaaf15..881ebd954 100644 --- a/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_contract_function_returning_struct_with_dynamic_array.sol +++ b/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_contract_function_returning_struct_with_dynamic_array.sol @@ -17,4 +17,4 @@ contract Test { } } // ---- -// TypeError 2428: (B:70-83): The type of return parameter 1, struct C.Item, is only supported in ABIEncoderV2. Use "pragma experimental ABIEncoderV2;" to enable the feature. +// TypeError 2428: (B:70-83): The type of return parameter 1, struct C.Item, is only supported in ABI coder v2. Use "pragma abicoder v2;" to enable the feature. diff --git a/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_event_accepting_struct.sol b/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_event_accepting_struct.sol index 4a02a2fa1..87498d206 100644 --- a/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_event_accepting_struct.sol +++ b/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_event_accepting_struct.sol @@ -16,4 +16,4 @@ contract Test { } } // ---- -// TypeError 2443: (B:74-84): The type of this parameter, struct L.Item, is only supported in ABIEncoderV2. Use "pragma experimental ABIEncoderV2;" to enable the feature. +// TypeError 2443: (B:74-84): The type of this parameter, struct L.Item, is only supported in ABI coder v2. Use "pragma abicoder v2;" to enable the feature. diff --git a/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_library_bound_function_returning_struct.sol b/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_library_bound_function_returning_struct.sol index eeaa6ac58..7804240ad 100644 --- a/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_library_bound_function_returning_struct.sol +++ b/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_library_bound_function_returning_struct.sol @@ -19,4 +19,4 @@ contract D { } } // ---- -// TypeError 2428: (B:86-97): The type of return parameter 1, struct L.Item, is only supported in ABIEncoderV2. Use "pragma experimental ABIEncoderV2;" to enable the feature. +// TypeError 2428: (B:86-97): The type of return parameter 1, struct L.Item, is only supported in ABI coder v2. Use "pragma abicoder v2;" to enable the feature. diff --git a/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_library_function_returning_struct.sol b/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_library_function_returning_struct.sol index 983ce189f..86be448f7 100644 --- a/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_library_function_returning_struct.sol +++ b/test/libsolidity/syntaxTests/abiEncoder/v1_call_to_v2_library_function_returning_struct.sol @@ -17,4 +17,4 @@ contract Test { } } // ---- -// TypeError 2428: (B:70-77): The type of return parameter 1, struct L.Item, is only supported in ABIEncoderV2. Use "pragma experimental ABIEncoderV2;" to enable the feature. +// TypeError 2428: (B:70-77): The type of return parameter 1, struct L.Item, is only supported in ABI coder v2. Use "pragma abicoder v2;" to enable the feature. diff --git a/test/libsolidity/syntaxTests/abiEncoder/v1_inheritance_from_contract_defining_v2_function_accepting_struct.sol b/test/libsolidity/syntaxTests/abiEncoder/v1_inheritance_from_contract_defining_v2_function_accepting_struct.sol index 23535eafc..3665e22f6 100644 --- a/test/libsolidity/syntaxTests/abiEncoder/v1_inheritance_from_contract_defining_v2_function_accepting_struct.sol +++ b/test/libsolidity/syntaxTests/abiEncoder/v1_inheritance_from_contract_defining_v2_function_accepting_struct.sol @@ -13,4 +13,4 @@ import "A"; contract D is C {} // ---- -// TypeError 6594: (B:13-31): Contract "D" does not use ABIEncoderV2 but wants to inherit from a contract which uses types that require it. Use "pragma experimental ABIEncoderV2;" for the inheriting contract as well to enable the feature. +// TypeError 6594: (B:13-31): Contract "D" does not use ABI coder v2 but wants to inherit from a contract which uses types that require it. Use "pragma abicoder v2;" for the inheriting contract as well to enable the feature. diff --git a/test/libsolidity/syntaxTests/abiEncoder/v1_inheritance_from_contract_defining_v2_function_returning_struct.sol b/test/libsolidity/syntaxTests/abiEncoder/v1_inheritance_from_contract_defining_v2_function_returning_struct.sol index ba568504e..febb3d3d7 100644 --- a/test/libsolidity/syntaxTests/abiEncoder/v1_inheritance_from_contract_defining_v2_function_returning_struct.sol +++ b/test/libsolidity/syntaxTests/abiEncoder/v1_inheritance_from_contract_defining_v2_function_returning_struct.sol @@ -13,4 +13,4 @@ import "A"; contract D is C {} // ---- -// TypeError 6594: (B:13-31): Contract "D" does not use ABIEncoderV2 but wants to inherit from a contract which uses types that require it. Use "pragma experimental ABIEncoderV2;" for the inheriting contract as well to enable the feature. +// TypeError 6594: (B:13-31): Contract "D" does not use ABI coder v2 but wants to inherit from a contract which uses types that require it. Use "pragma abicoder v2;" for the inheriting contract as well to enable the feature. diff --git a/test/libsolidity/syntaxTests/abiEncoder/v2_v1_v1_modifier_sandwich.sol b/test/libsolidity/syntaxTests/abiEncoder/v2_v1_v1_modifier_sandwich.sol index a90b3385f..ea64c5c6f 100644 --- a/test/libsolidity/syntaxTests/abiEncoder/v2_v1_v1_modifier_sandwich.sol +++ b/test/libsolidity/syntaxTests/abiEncoder/v2_v1_v1_modifier_sandwich.sol @@ -27,4 +27,4 @@ contract C is B { {} } // ---- -// TypeError 2428: (B:60-73): The type of return parameter 1, struct Data, is only supported in ABIEncoderV2. Use "pragma experimental ABIEncoderV2;" to enable the feature. +// TypeError 2428: (B:60-73): The type of return parameter 1, struct Data, is only supported in ABI coder v2. Use "pragma abicoder v2;" to enable the feature. diff --git a/test/libsolidity/syntaxTests/abiEncoder/v2_v1_v2_modifier_sandwich.sol b/test/libsolidity/syntaxTests/abiEncoder/v2_v1_v2_modifier_sandwich.sol index 01c0d0840..df1c4ed3c 100644 --- a/test/libsolidity/syntaxTests/abiEncoder/v2_v1_v2_modifier_sandwich.sol +++ b/test/libsolidity/syntaxTests/abiEncoder/v2_v1_v2_modifier_sandwich.sol @@ -29,4 +29,4 @@ contract C is B { {} } // ---- -// TypeError 2428: (B:60-73): The type of return parameter 1, struct Data, is only supported in ABIEncoderV2. Use "pragma experimental ABIEncoderV2;" to enable the feature. +// TypeError 2428: (B:60-73): The type of return parameter 1, struct Data, is only supported in ABI coder v2. Use "pragma abicoder v2;" to enable the feature. diff --git a/test/libsolidity/syntaxTests/array/calldata_multi_dynamic_V1.sol b/test/libsolidity/syntaxTests/array/calldata_multi_dynamic_V1.sol index c6dab54cf..00bd4208c 100644 --- a/test/libsolidity/syntaxTests/array/calldata_multi_dynamic_V1.sol +++ b/test/libsolidity/syntaxTests/array/calldata_multi_dynamic_V1.sol @@ -3,5 +3,5 @@ contract Test { function g(uint[][1] calldata) external { } } // ---- -// TypeError 4957: (31-48): This type is only supported in ABIEncoderV2. Use "pragma experimental ABIEncoderV2;" to enable the feature. -// TypeError 4957: (78-96): This type is only supported in ABIEncoderV2. Use "pragma experimental ABIEncoderV2;" to enable the feature. +// TypeError 4957: (31-48): This type is only supported in ABI coder v2. Use "pragma abicoder v2;" to enable the feature. +// TypeError 4957: (78-96): This type is only supported in ABI coder v2. Use "pragma abicoder v2;" to enable the feature. diff --git a/test/libsolidity/syntaxTests/constructor/nonabiv2_type.sol b/test/libsolidity/syntaxTests/constructor/nonabiv2_type.sol index 13b0d02af..3487c67f3 100644 --- a/test/libsolidity/syntaxTests/constructor/nonabiv2_type.sol +++ b/test/libsolidity/syntaxTests/constructor/nonabiv2_type.sol @@ -2,4 +2,4 @@ contract C { constructor(uint[][][] memory t) {} } // ---- -// TypeError 4957: (26-45): This type is only supported in ABIEncoderV2. Use "pragma experimental ABIEncoderV2;" to enable the feature. Alternatively, make the contract abstract and supply the constructor arguments from a derived contract. +// TypeError 4957: (26-45): This type is only supported in ABI coder v2. Use "pragma abicoder v2;" to enable the feature. Alternatively, make the contract abstract and supply the constructor arguments from a derived contract. diff --git a/test/libsolidity/syntaxTests/events/event_nested_array.sol b/test/libsolidity/syntaxTests/events/event_nested_array.sol index 6d76a6dcd..09ae580f6 100644 --- a/test/libsolidity/syntaxTests/events/event_nested_array.sol +++ b/test/libsolidity/syntaxTests/events/event_nested_array.sol @@ -2,4 +2,4 @@ contract c { event E(uint[][]); } // ---- -// TypeError 3061: (25-33): This type is only supported in ABIEncoderV2. Use "pragma experimental ABIEncoderV2;" to enable the feature. +// TypeError 3061: (25-33): This type is only supported in ABI coder v2. Use "pragma abicoder v2;" to enable the feature. diff --git a/test/libsolidity/syntaxTests/events/event_nested_array_in_struct.sol b/test/libsolidity/syntaxTests/events/event_nested_array_in_struct.sol index 4e6f10d2a..b06f4990f 100644 --- a/test/libsolidity/syntaxTests/events/event_nested_array_in_struct.sol +++ b/test/libsolidity/syntaxTests/events/event_nested_array_in_struct.sol @@ -3,4 +3,4 @@ contract c { event E(S); } // ---- -// TypeError 3061: (61-62): This type is only supported in ABIEncoderV2. Use "pragma experimental ABIEncoderV2;" to enable the feature. +// TypeError 3061: (61-62): This type is only supported in ABI coder v2. Use "pragma abicoder v2;" to enable the feature. diff --git a/test/libsolidity/syntaxTests/events/event_struct.sol b/test/libsolidity/syntaxTests/events/event_struct.sol index 52a01c5e9..fad75f5a5 100644 --- a/test/libsolidity/syntaxTests/events/event_struct.sol +++ b/test/libsolidity/syntaxTests/events/event_struct.sol @@ -3,4 +3,4 @@ contract c { event E(S); } // ---- -// TypeError 3061: (51-52): This type is only supported in ABIEncoderV2. Use "pragma experimental ABIEncoderV2;" to enable the feature. +// TypeError 3061: (51-52): This type is only supported in ABI coder v2. Use "pragma abicoder v2;" to enable the feature. diff --git a/test/libsolidity/syntaxTests/events/event_struct_indexed.sol b/test/libsolidity/syntaxTests/events/event_struct_indexed.sol index 19676b5cc..1425ca9b9 100644 --- a/test/libsolidity/syntaxTests/events/event_struct_indexed.sol +++ b/test/libsolidity/syntaxTests/events/event_struct_indexed.sol @@ -3,4 +3,4 @@ contract c { event E(S indexed); } // ---- -// TypeError 3061: (51-60): This type is only supported in ABIEncoderV2. Use "pragma experimental ABIEncoderV2;" to enable the feature. +// TypeError 3061: (51-60): This type is only supported in ABI coder v2. Use "pragma abicoder v2;" to enable the feature. diff --git a/test/libsolidity/syntaxTests/getter/nested_structs.sol b/test/libsolidity/syntaxTests/getter/nested_structs.sol index 457ddb87d..6e901b438 100644 --- a/test/libsolidity/syntaxTests/getter/nested_structs.sol +++ b/test/libsolidity/syntaxTests/getter/nested_structs.sol @@ -8,4 +8,4 @@ contract C { mapping(uint256 => X) public m; } // ---- -// TypeError 2763: (88-118): The following types are only supported for getters in ABIEncoderV2: struct C.Y memory. Either remove "public" or use "pragma experimental ABIEncoderV2;" to enable the feature. +// TypeError 2763: (88-118): The following types are only supported for getters in ABI coder v2: struct C.Y memory. Either remove "public" or use "pragma abicoder v2;" to enable the feature. diff --git a/test/libsolidity/syntaxTests/imports/inheritance_abi_encoder_mismatch_1.sol b/test/libsolidity/syntaxTests/imports/inheritance_abi_encoder_mismatch_1.sol index 214de78d1..6e90f7d49 100644 --- a/test/libsolidity/syntaxTests/imports/inheritance_abi_encoder_mismatch_1.sol +++ b/test/libsolidity/syntaxTests/imports/inheritance_abi_encoder_mismatch_1.sol @@ -16,4 +16,4 @@ contract B is A { } import "./B.sol"; contract C is B { } // ---- -// TypeError 6594: (C.sol:18-37): Contract "C" does not use ABIEncoderV2 but wants to inherit from a contract which uses types that require it. Use "pragma experimental ABIEncoderV2;" for the inheriting contract as well to enable the feature. +// TypeError 6594: (C.sol:18-37): Contract "C" does not use ABI coder v2 but wants to inherit from a contract which uses types that require it. Use "pragma abicoder v2;" for the inheriting contract as well to enable the feature. diff --git a/test/libsolidity/syntaxTests/imports/inheritance_abi_encoder_mismatch_2.sol b/test/libsolidity/syntaxTests/imports/inheritance_abi_encoder_mismatch_2.sol index 07b9cdefe..7e5cfc7fd 100644 --- a/test/libsolidity/syntaxTests/imports/inheritance_abi_encoder_mismatch_2.sol +++ b/test/libsolidity/syntaxTests/imports/inheritance_abi_encoder_mismatch_2.sol @@ -14,4 +14,4 @@ contract B is A { } import "./B.sol"; contract C is B { } // ---- -// TypeError 6594: (B.sol:18-37): Contract "B" does not use ABIEncoderV2 but wants to inherit from a contract which uses types that require it. Use "pragma experimental ABIEncoderV2;" for the inheriting contract as well to enable the feature. +// TypeError 6594: (B.sol:18-37): Contract "B" does not use ABI coder v2 but wants to inherit from a contract which uses types that require it. Use "pragma abicoder v2;" for the inheriting contract as well to enable the feature. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/045_returning_multi_dimensional_arrays.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/045_returning_multi_dimensional_arrays.sol index bc92882a2..a0a2e0408 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/045_returning_multi_dimensional_arrays.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/045_returning_multi_dimensional_arrays.sol @@ -2,4 +2,4 @@ contract C { function f() public pure returns (string[][] memory) {} } // ---- -// TypeError 4957: (51-68): This type is only supported in ABIEncoderV2. Use "pragma experimental ABIEncoderV2;" to enable the feature. +// TypeError 4957: (51-68): This type is only supported in ABI coder v2. Use "pragma abicoder v2;" to enable the feature. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/046_returning_multi_dimensional_static_arrays.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/046_returning_multi_dimensional_static_arrays.sol index d0e6ec0b6..a643aec01 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/046_returning_multi_dimensional_static_arrays.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/046_returning_multi_dimensional_static_arrays.sol @@ -2,4 +2,4 @@ contract C { function f() public pure returns (uint[][2] memory) {} } // ---- -// TypeError 4957: (51-67): This type is only supported in ABIEncoderV2. Use "pragma experimental ABIEncoderV2;" to enable the feature. +// TypeError 4957: (51-67): This type is only supported in ABI coder v2. Use "pragma abicoder v2;" to enable the feature. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/048_returning_arrays_in_structs_arrays.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/048_returning_arrays_in_structs_arrays.sol index 7670da2b0..46e495217 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/048_returning_arrays_in_structs_arrays.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/048_returning_arrays_in_structs_arrays.sol @@ -3,4 +3,4 @@ contract C { function f() public pure returns (S memory x) {} } // ---- -// TypeError 4957: (80-90): This type is only supported in ABIEncoderV2. Use "pragma experimental ABIEncoderV2;" to enable the feature. +// TypeError 4957: (80-90): This type is only supported in ABI coder v2. Use "pragma abicoder v2;" to enable the feature. diff --git a/test/stopAfterParseTests.sh b/test/stopAfterParseTests.sh index 807ff314d..8320aeb75 100755 --- a/test/stopAfterParseTests.sh +++ b/test/stopAfterParseTests.sh @@ -1,6 +1,12 @@ -#! /usr/bin/env bash +#!/usr/bin/env bash -REPO_ROOT=$(readlink -f "$(dirname "$0")"/..) +set -e + +READLINK=readlink +if [[ "$OSTYPE" == "darwin"* ]]; then + READLINK=greadlink +fi +REPO_ROOT=$(${READLINK} -f "$(dirname "$0")"/..) SOLIDITY_BUILD_DIR=${SOLIDITY_BUILD_DIR:-${REPO_ROOT}/build} SOLC=${SOLIDITY_BUILD_DIR}/solc/solc SPLITSOURCES=${REPO_ROOT}/scripts/splitSources.py @@ -11,15 +17,18 @@ cd "$FILETMP" || exit 1 function testFile() { + set +e ALLOUTPUT=$($SOLC --combined-json ast,compact-format --pretty-json "$@" --stop-after parsing 2>&1) - if test $? -ne 0; then + local RESULT=$? + set -e + if test ${RESULT} -ne 0; then # solc returned failure. Compilation errors and unimplemented features # are okay, everything else is a failed test (segfault) if ! echo "$ALLOUTPUT" | grep -e "Unimplemented feature:" -e "Error:" -q; then - echo -n "Test failed on "; + echo -n "Test failed on " echo "$@" echo "$ALLOUTPUT" - return 1; + return 1 fi else echo -n . @@ -29,8 +38,10 @@ function testFile() } while read -r file; do + set +e OUTPUT=$($SPLITSOURCES "$file") RETURN_CODE=$? + set -e FAILED=0 if [ $RETURN_CODE -eq 0 ] @@ -38,8 +49,7 @@ while read -r file; do # shellcheck disable=SC2086 testFile $OUTPUT FAILED=$? - - rm "${FILETMP:?}/"* -r + rm -r "${FILETMP:?}"/* elif [ $RETURN_CODE -eq 1 ] then testFile "$file"