diff options
206 files changed, 1921 insertions, 1733 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index ed51e5a7..b22ade23 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,7 @@ configure_project(TESTS) add_subdirectory(libdevcore) add_subdirectory(liblangutil) add_subdirectory(libevmasm) +add_subdirectory(libyul) add_subdirectory(libsolidity) add_subdirectory(libsolc) diff --git a/Changelog.md b/Changelog.md index 449798a4..ff26882d 100644 --- a/Changelog.md +++ b/Changelog.md @@ -6,12 +6,14 @@ Language Features: Compiler Features: * Build System: LLL is not built anymore by default. Must configure it with CMake as `-DLLL=ON`. * Code generator: Do not perform redundant double cleanup on unsigned integers when loading from calldata. + * SMTChecker: SMTLib2 queries and responses passed via standard JSON compiler interface. * SMTChecker: Support ``msg``, ``tx`` and ``block`` member variables. * SMTChecker: Support ``gasleft()`` and ``blockhash()`` functions. * SMTChecker: Support internal bound function calls. Bugfixes: + * Assembly output: Do not mix in/out jump annotations with arguments. Build System: * Emscripten: Upgrade to Emscripten SDK 1.37.21 and boost 1.67. @@ -62,5 +62,6 @@ if you want to help. [@chriseth](https://github.com/chriseth) ## License -Solidity is licensed under [GNU General Public License v3.0](https://github.com/ethereum/solidity/blob/develop/LICENSE.txt) +Solidity is licensed under [GNU General Public License v3.0](LICENSE.txt) +Some third-party code has its [own licensing terms](cmake/templates/license.h.in). diff --git a/cmake/templates/license.h.in b/cmake/templates/license.h.in index 4f22d8f4..31e2e17d 100644 --- a/cmake/templates/license.h.in +++ b/cmake/templates/license.h.in @@ -67,7 +67,7 @@ jsoncpp: license you like. scanner/token: - The libsolidity/parsing/{scanner,token}.{h,cpp} files are dervied from + The liblangutil/{CharStream,Scanner,Token}.{h,cpp} files are dervied from code originating from the V8 project licensed under the following terms: Copyright 2006-2012, the V8 project authors. All rights reserved. diff --git a/docs/installing-solidity.rst b/docs/installing-solidity.rst index f8de0e8d..2797d8b0 100644 --- a/docs/installing-solidity.rst +++ b/docs/installing-solidity.rst @@ -115,7 +115,7 @@ Arch Linux also has packages, albeit limited to the latest development version: pacman -S solidity -We distribute the Solidity compiler through Homebrow +We distribute the Solidity compiler through Homebrew as a build-from-source version. Pre-built bottles are currently not supported. diff --git a/docs/introduction-to-smart-contracts.rst b/docs/introduction-to-smart-contracts.rst index 9245300b..34ef012e 100644 --- a/docs/introduction-to-smart-contracts.rst +++ b/docs/introduction-to-smart-contracts.rst @@ -400,7 +400,7 @@ within a word). At the time of expansion, the cost in gas must be paid. Memory i costly the larger it grows (it scales quadratically). The EVM is not a register machine but a stack machine, so all -computations are performed on an data area called the **stack**. It has a maximum size of +computations are performed on a data area called the **stack**. It has a maximum size of 1024 elements and contains words of 256 bits. Access to the stack is limited to the top end in the following way: It is possible to copy one of diff --git a/docs/types.rst b/docs/types.rst index b84d3222..5a578072 100644 --- a/docs/types.rst +++ b/docs/types.rst @@ -273,7 +273,7 @@ Example:: when the call returns. The regular way to interact with other contracts is to call a function on a contract object (``x.f()``). -:: note:: +.. note:: Previous versions of Solidity allowed these functions to receive arbitrary arguments and would also handle a first argument of type ``bytes4`` differently. These edge cases were removed in version 0.5.0. diff --git a/libdevcore/JSON.cpp b/libdevcore/JSON.cpp index 6317cc89..086fae50 100644 --- a/libdevcore/JSON.cpp +++ b/libdevcore/JSON.cpp @@ -21,6 +21,8 @@ #include "JSON.h" +#include "CommonIO.h" + #include <sstream> #include <map> #include <memory> @@ -111,4 +113,10 @@ bool jsonParse(string const& _input, Json::Value& _json, string *_errs /* = null return parse(readerBuilder, _input, _json, _errs); } +bool jsonParseFile(string const& _fileName, Json::Value& _json, string *_errs /* = nullptr */) +{ + return jsonParse(readFileAsString(_fileName), _json, _errs); +} + + } // namespace dev diff --git a/libdevcore/JSON.h b/libdevcore/JSON.h index 1ce822cd..ecb93467 100644 --- a/libdevcore/JSON.h +++ b/libdevcore/JSON.h @@ -48,4 +48,11 @@ bool jsonParseStrict(std::string const& _input, Json::Value& _json, std::string* /// \return \c true if the document was successfully parsed, \c false if an error occurred. bool jsonParse(std::string const& _input, Json::Value& _json, std::string* _errs = nullptr); +/// Parse a JSON string (@a _input) and writes resulting JSON object to (@a _json) +/// \param _input file containing JSON input +/// \param _json [out] resulting JSON object +/// \param _errs [out] Formatted error messages +/// \return \c true if the document was successfully parsed, \c false if an error occurred. +bool jsonParseFile(std::string const& _fileName, Json::Value& _json, std::string* _errs = nullptr); + } diff --git a/libevmasm/AssemblyItem.cpp b/libevmasm/AssemblyItem.cpp index a3a4d6b6..52f246d1 100644 --- a/libevmasm/AssemblyItem.cpp +++ b/libevmasm/AssemblyItem.cpp @@ -117,6 +117,8 @@ int AssemblyItem::returnValues() const bool AssemblyItem::canBeFunctional() const { + if (m_jumpType != JumpType::Ordinary) + return false; switch (m_type) { case Operation: diff --git a/liblangutil/Token.h b/liblangutil/Token.h index 0b7d9f71..d997b138 100644 --- a/liblangutil/Token.h +++ b/liblangutil/Token.h @@ -56,7 +56,7 @@ namespace langutil // TOKEN_LIST takes a list of 3 macros M, all of which satisfy the // same signature M(name, string, precedence), where name is the // symbolic token name, string is the corresponding syntactic symbol -// (or NULL, for literals), and precedence is the precedence (or 0). +// (or nullptr, for literals), and precedence is the precedence (or 0). // The parameters are invoked for token categories as follows: // // T: Non-keyword tokens @@ -211,17 +211,17 @@ namespace langutil T(BytesM, "bytesM", 0) \ T(FixedMxN, "fixedMxN", 0) \ T(UFixedMxN, "ufixedMxN", 0) \ - T(TypesEnd, NULL, 0) /* used as type enum end marker */ \ + T(TypesEnd, nullptr, 0) /* used as type enum end marker */ \ \ /* Literals */ \ K(TrueLiteral, "true", 0) \ K(FalseLiteral, "false", 0) \ - T(Number, NULL, 0) \ - T(StringLiteral, NULL, 0) \ - T(CommentLiteral, NULL, 0) \ + T(Number, nullptr, 0) \ + T(StringLiteral, nullptr, 0) \ + T(CommentLiteral, nullptr, 0) \ \ /* Identifiers (not keywords or future reserved words). */ \ - T(Identifier, NULL, 0) \ + T(Identifier, nullptr, 0) \ \ /* Keywords reserved for future use. */ \ K(Abstract, "abstract", 0) \ @@ -267,7 +267,7 @@ namespace langutil T(IllegalHex, "ILLEGAL_HEX", 0) \ \ /* Scanner-internal use only. */ \ - T(Whitespace, NULL, 0) + T(Whitespace, nullptr, 0) // All token values. // attention! msvc issue: @@ -329,7 +329,7 @@ namespace TokenTraits char const* name(Token tok); // @returns a string corresponding to the JS token string - // (.e., "<" for the token LT) or NULL if the token doesn't + // (.e., "<" for the token LT) or nullptr if the token doesn't // have a (unique) string (e.g. an IDENTIFIER). char const* toString(Token tok); diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index c57fca16..c40087f0 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -1,6 +1,6 @@ # Until we have a clear separation, libyul has to be included here -file(GLOB_RECURSE sources "*.cpp" "../libyul/*.cpp") -file(GLOB_RECURSE headers "*.h" "../libyul/*.h") +file(GLOB_RECURSE sources "*.cpp") +file(GLOB_RECURSE headers "*.h") find_package(Z3 QUIET) if (${Z3_FOUND}) @@ -26,7 +26,7 @@ if (NOT (${Z3_FOUND} OR ${CVC4_FOUND})) endif() add_library(solidity ${sources} ${headers}) -target_link_libraries(solidity PUBLIC evmasm langutil devcore ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY}) +target_link_libraries(solidity PUBLIC yul evmasm langutil devcore ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY}) if (${Z3_FOUND}) target_link_libraries(solidity PUBLIC ${Z3_LIBRARY}) diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index 7ac3ceff..c4931d98 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -23,12 +23,12 @@ #include <libsolidity/analysis/ReferencesResolver.h> #include <libsolidity/ast/AST.h> #include <libsolidity/analysis/NameAndTypeResolver.h> -#include <liblangutil/Exceptions.h> #include <libsolidity/analysis/ConstantEvaluator.h> -#include <libsolidity/inlineasm/AsmAnalysis.h> -#include <libsolidity/inlineasm/AsmAnalysisInfo.h> -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmAnalysis.h> +#include <libyul/AsmAnalysisInfo.h> +#include <libyul/AsmData.h> #include <liblangutil/ErrorReporter.h> +#include <liblangutil/Exceptions.h> #include <libdevcore/StringUtils.h> @@ -273,7 +273,7 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly) ErrorList errors; ErrorReporter errorsIgnored(errors); yul::ExternalIdentifierAccess::Resolver resolver = - [&](assembly::Identifier const& _identifier, yul::IdentifierContext, bool _crossesFunctionBoundary) { + [&](yul::Identifier const& _identifier, yul::IdentifierContext, bool _crossesFunctionBoundary) { auto declarations = m_resolver.nameFromCurrentScope(_identifier.name.str()); bool isSlot = boost::algorithm::ends_with(_identifier.name.str(), "_slot"); bool isOffset = boost::algorithm::ends_with(_identifier.name.str(), "_offset"); @@ -314,9 +314,9 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly) // Will be re-generated later with correct information // We use the latest EVM version because we will re-run it anyway. - assembly::AsmAnalysisInfo analysisInfo; + yul::AsmAnalysisInfo analysisInfo; boost::optional<Error::Type> errorTypeForLoose = Error::Type::SyntaxError; - assembly::AsmAnalyzer(analysisInfo, errorsIgnored, EVMVersion(), errorTypeForLoose, assembly::AsmFlavour::Loose, resolver).analyze(_inlineAssembly.operations()); + yul::AsmAnalyzer(analysisInfo, errorsIgnored, EVMVersion(), errorTypeForLoose, yul::AsmFlavour::Loose, resolver).analyze(_inlineAssembly.operations()); return false; } diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 7a41f94e..a6c23ada 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -27,9 +27,9 @@ #include <boost/algorithm/string/join.hpp> #include <boost/range/adaptor/reversed.hpp> #include <libsolidity/ast/AST.h> -#include <libsolidity/inlineasm/AsmAnalysis.h> -#include <libsolidity/inlineasm/AsmAnalysisInfo.h> -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmAnalysis.h> +#include <libyul/AsmAnalysisInfo.h> +#include <libyul/AsmData.h> #include <liblangutil/ErrorReporter.h> #include <libdevcore/Algorithms.h> @@ -954,7 +954,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) // External references have already been resolved in a prior stage and stored in the annotation. // We run the resolve step again regardless. yul::ExternalIdentifierAccess::Resolver identifierAccess = [&]( - assembly::Identifier const& _identifier, + yul::Identifier const& _identifier, yul::IdentifierContext _context, bool ) @@ -1039,13 +1039,13 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) return size_t(1); }; solAssert(!_inlineAssembly.annotation().analysisInfo, ""); - _inlineAssembly.annotation().analysisInfo = make_shared<assembly::AsmAnalysisInfo>(); - assembly::AsmAnalyzer analyzer( + _inlineAssembly.annotation().analysisInfo = make_shared<yul::AsmAnalysisInfo>(); + yul::AsmAnalyzer analyzer( *_inlineAssembly.annotation().analysisInfo, m_errorReporter, m_evmVersion, Error::Type::SyntaxError, - assembly::AsmFlavour::Loose, + yul::AsmFlavour::Loose, identifierAccess ); if (!analyzer.analyze(_inlineAssembly.operations())) diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp index 3fb4c026..1112d682 100644 --- a/libsolidity/analysis/ViewPureChecker.cpp +++ b/libsolidity/analysis/ViewPureChecker.cpp @@ -19,8 +19,8 @@ #include <libevmasm/SemanticInformation.h> -#include <libsolidity/inlineasm/AsmData.h> #include <libsolidity/ast/ExperimentalFeatures.h> +#include <libyul/AsmData.h> #include <liblangutil/ErrorReporter.h> @@ -40,48 +40,48 @@ public: explicit AssemblyViewPureChecker(std::function<void(StateMutability, SourceLocation const&)> _reportMutability): m_reportMutability(_reportMutability) {} - void operator()(assembly::Label const&) { } - void operator()(assembly::Instruction const& _instruction) + void operator()(yul::Label const&) { } + void operator()(yul::Instruction const& _instruction) { checkInstruction(_instruction.location, _instruction.instruction); } - void operator()(assembly::Literal const&) {} - void operator()(assembly::Identifier const&) {} - void operator()(assembly::FunctionalInstruction const& _instr) + void operator()(yul::Literal const&) {} + void operator()(yul::Identifier const&) {} + void operator()(yul::FunctionalInstruction const& _instr) { checkInstruction(_instr.location, _instr.instruction); for (auto const& arg: _instr.arguments) boost::apply_visitor(*this, arg); } - void operator()(assembly::ExpressionStatement const& _expr) + void operator()(yul::ExpressionStatement const& _expr) { boost::apply_visitor(*this, _expr.expression); } - void operator()(assembly::StackAssignment const&) {} - void operator()(assembly::Assignment const& _assignment) + void operator()(yul::StackAssignment const&) {} + void operator()(yul::Assignment const& _assignment) { boost::apply_visitor(*this, *_assignment.value); } - void operator()(assembly::VariableDeclaration const& _varDecl) + void operator()(yul::VariableDeclaration const& _varDecl) { if (_varDecl.value) boost::apply_visitor(*this, *_varDecl.value); } - void operator()(assembly::FunctionDefinition const& _funDef) + void operator()(yul::FunctionDefinition const& _funDef) { (*this)(_funDef.body); } - void operator()(assembly::FunctionCall const& _funCall) + void operator()(yul::FunctionCall const& _funCall) { for (auto const& arg: _funCall.arguments) boost::apply_visitor(*this, arg); } - void operator()(assembly::If const& _if) + void operator()(yul::If const& _if) { boost::apply_visitor(*this, *_if.condition); (*this)(_if.body); } - void operator()(assembly::Switch const& _switch) + void operator()(yul::Switch const& _switch) { boost::apply_visitor(*this, *_switch.expression); for (auto const& _case: _switch.cases) @@ -91,14 +91,14 @@ public: (*this)(_case.body); } } - void operator()(assembly::ForLoop const& _for) + void operator()(yul::ForLoop const& _for) { (*this)(_for.pre); boost::apply_visitor(*this, *_for.condition); (*this)(_for.body); (*this)(_for.post); } - void operator()(assembly::Block const& _block) + void operator()(yul::Block const& _block) { for (auto const& s: _block.statements) boost::apply_visitor(*this, s); diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index d23562ad..2f418b09 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -41,6 +41,12 @@ #include <vector> #include <memory> +namespace yul +{ +// Forward-declaration to <yul/AsmData.h> +struct Block; +} + namespace dev { namespace solidity @@ -1028,12 +1034,6 @@ public: StatementAnnotation& annotation() const override; }; -namespace assembly -{ -// Forward-declaration to AsmData.h -struct Block; -} - /** * Inline assembly. */ @@ -1043,18 +1043,18 @@ public: InlineAssembly( SourceLocation const& _location, ASTPointer<ASTString> const& _docString, - std::shared_ptr<assembly::Block> const& _operations + std::shared_ptr<yul::Block> const& _operations ): Statement(_location, _docString), m_operations(_operations) {} void accept(ASTVisitor& _visitor) override; void accept(ASTConstVisitor& _visitor) const override; - assembly::Block const& operations() const { return *m_operations; } + yul::Block const& operations() const { return *m_operations; } InlineAssemblyAnnotation& annotation() const override; private: - std::shared_ptr<assembly::Block> m_operations; + std::shared_ptr<yul::Block> m_operations; }; /** diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index e0b3f492..e9cc905e 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -30,6 +30,12 @@ #include <vector> #include <set> +namespace yul +{ + struct AsmAnalysisInfo; + struct Identifier; +} + namespace dev { namespace solidity @@ -120,12 +126,6 @@ struct StatementAnnotation: ASTAnnotation, DocumentedAnnotation { }; -namespace assembly -{ - struct AsmAnalysisInfo; - struct Identifier; -} - struct InlineAssemblyAnnotation: StatementAnnotation { struct ExternalIdentifierInfo @@ -137,9 +137,9 @@ struct InlineAssemblyAnnotation: StatementAnnotation }; /// Mapping containing resolved references to external identifiers and their value size - std::map<assembly::Identifier const*, ExternalIdentifierInfo> externalReferences; + std::map<yul::Identifier const*, ExternalIdentifierInfo> externalReferences; /// Information generated during analysis phase. - std::shared_ptr<assembly::AsmAnalysisInfo> analysisInfo; + std::shared_ptr<yul::AsmAnalysisInfo> analysisInfo; }; struct ReturnAnnotation: StatementAnnotation diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index 6b9f7227..b9054692 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -23,8 +23,8 @@ #include <boost/algorithm/string/join.hpp> #include <libdevcore/UTF8.h> #include <libsolidity/ast/AST.h> -#include <libsolidity/inlineasm/AsmData.h> -#include <libsolidity/inlineasm/AsmPrinter.h> +#include <libyul/AsmData.h> +#include <libyul/AsmPrinter.h> using namespace std; using namespace langutil; @@ -172,7 +172,7 @@ void ASTJsonConverter::appendExpressionAttributes( _attributes += exprAttributes; } -Json::Value ASTJsonConverter::inlineAssemblyIdentifierToJson(pair<assembly::Identifier const* ,InlineAssemblyAnnotation::ExternalIdentifierInfo> _info) const +Json::Value ASTJsonConverter::inlineAssemblyIdentifierToJson(pair<yul::Identifier const* ,InlineAssemblyAnnotation::ExternalIdentifierInfo> _info) const { Json::Value tuple(Json::objectValue); tuple["src"] = sourceLocationToString(_info.first->location); @@ -465,7 +465,7 @@ bool ASTJsonConverter::visit(InlineAssembly const& _node) } } setJsonNode(_node, "InlineAssembly", { - make_pair("operations", Json::Value(assembly::AsmPrinter()(_node.operations()))), + make_pair("operations", Json::Value(yul::AsmPrinter()(_node.operations()))), make_pair("externalReferences", std::move(externalReferences)) }); return false; diff --git a/libsolidity/ast/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h index dec3ac96..ef0a217a 100644 --- a/libsolidity/ast/ASTJsonConverter.h +++ b/libsolidity/ast/ASTJsonConverter.h @@ -135,7 +135,7 @@ private: { return _node ? toJson(*_node) : Json::nullValue; } - Json::Value inlineAssemblyIdentifierToJson(std::pair<assembly::Identifier const* , InlineAssemblyAnnotation::ExternalIdentifierInfo> _info) const; + Json::Value inlineAssemblyIdentifierToJson(std::pair<yul::Identifier const* , InlineAssemblyAnnotation::ExternalIdentifierInfo> _info) const; static std::string location(VariableDeclaration::Location _location); static std::string contractKind(ContractDefinition::ContractKind _kind); static std::string functionCallKind(FunctionCallKind _kind); diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index eb33f688..b4fad94f 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -25,15 +25,14 @@ #include <libsolidity/ast/AST.h> #include <libsolidity/codegen/Compiler.h> #include <libsolidity/interface/Version.h> -#include <liblangutil/ErrorReporter.h> -#include <liblangutil/Scanner.h> #include <libsolidity/interface/SourceReferenceFormatter.h> -#include <liblangutil/Scanner.h> -#include <libsolidity/inlineasm/AsmParser.h> -#include <libsolidity/inlineasm/AsmCodeGen.h> -#include <libsolidity/inlineasm/AsmAnalysis.h> -#include <libsolidity/inlineasm/AsmAnalysisInfo.h> +#include <libyul/AsmParser.h> +#include <libyul/AsmCodeGen.h> +#include <libyul/AsmAnalysis.h> +#include <libyul/AsmAnalysisInfo.h> #include <libyul/YulString.h> +#include <liblangutil/ErrorReporter.h> +#include <liblangutil/Scanner.h> #include <boost/algorithm/string/replace.hpp> @@ -43,7 +42,7 @@ // Change to "define" to output all intermediate code #undef SOL_OUTPUT_ASM #ifdef SOL_OUTPUT_ASM -#include <libsolidity/inlineasm/AsmPrinter.h> +#include <libyul/AsmPrinter.h> #endif @@ -324,7 +323,7 @@ void CompilerContext::appendInlineAssembly( yul::ExternalIdentifierAccess identifierAccess; identifierAccess.resolve = [&]( - assembly::Identifier const& _identifier, + yul::Identifier const& _identifier, yul::IdentifierContext, bool ) @@ -333,7 +332,7 @@ void CompilerContext::appendInlineAssembly( return it == _localVariables.end() ? size_t(-1) : 1; }; identifierAccess.generateCode = [&]( - assembly::Identifier const& _identifier, + yul::Identifier const& _identifier, yul::IdentifierContext _context, yul::AbstractAssembly& _assembly ) @@ -362,19 +361,19 @@ void CompilerContext::appendInlineAssembly( ErrorList errors; ErrorReporter errorReporter(errors); auto scanner = make_shared<langutil::Scanner>(langutil::CharStream(_assembly), "--CODEGEN--"); - auto parserResult = assembly::Parser(errorReporter, assembly::AsmFlavour::Strict).parse(scanner, false); + auto parserResult = yul::Parser(errorReporter, yul::AsmFlavour::Strict).parse(scanner, false); #ifdef SOL_OUTPUT_ASM - cout << assembly::AsmPrinter()(*parserResult) << endl; + cout << yul::AsmPrinter()(*parserResult) << endl; #endif - assembly::AsmAnalysisInfo analysisInfo; + yul::AsmAnalysisInfo analysisInfo; bool analyzerResult = false; if (parserResult) - analyzerResult = assembly::AsmAnalyzer( + analyzerResult = yul::AsmAnalyzer( analysisInfo, errorReporter, m_evmVersion, boost::none, - assembly::AsmFlavour::Strict, + yul::AsmFlavour::Strict, identifierAccess.resolve ).analyze(*parserResult); if (!parserResult || !errorReporter.errors().empty() || !analyzerResult) @@ -396,7 +395,7 @@ void CompilerContext::appendInlineAssembly( } solAssert(errorReporter.errors().empty(), "Failed to analyze inline assembly block."); - assembly::CodeGenerator::assemble(*parserResult, analysisInfo, *m_asm, identifierAccess, _system); + yul::CodeGenerator::assemble(*parserResult, analysisInfo, *m_asm, identifierAccess, _system); // Reset the source location to the one of the node (instead of the CODEGEN source location) updateSourceLocation(); diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 7a1dcd70..157d5fa7 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -21,11 +21,11 @@ */ #include <libsolidity/codegen/ContractCompiler.h> -#include <libsolidity/inlineasm/AsmCodeGen.h> -#include <libsolidity/ast/AST.h> -#include <liblangutil/ErrorReporter.h> #include <libsolidity/codegen/ExpressionCompiler.h> #include <libsolidity/codegen/CompilerUtils.h> +#include <libsolidity/ast/AST.h> +#include <libyul/AsmCodeGen.h> +#include <liblangutil/ErrorReporter.h> #include <libevmasm/Instruction.h> #include <libevmasm/Assembly.h> @@ -496,14 +496,14 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) { unsigned startStackHeight = m_context.stackHeight(); yul::ExternalIdentifierAccess identifierAccess; - identifierAccess.resolve = [&](assembly::Identifier const& _identifier, yul::IdentifierContext, bool) + identifierAccess.resolve = [&](yul::Identifier const& _identifier, yul::IdentifierContext, bool) { auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier); if (ref == _inlineAssembly.annotation().externalReferences.end()) return size_t(-1); return ref->second.valueSize; }; - identifierAccess.generateCode = [&](assembly::Identifier const& _identifier, yul::IdentifierContext _context, yul::AbstractAssembly& _assembly) + identifierAccess.generateCode = [&](yul::Identifier const& _identifier, yul::IdentifierContext _context, yul::AbstractAssembly& _assembly) { auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier); solAssert(ref != _inlineAssembly.annotation().externalReferences.end(), ""); @@ -615,7 +615,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) } }; solAssert(_inlineAssembly.annotation().analysisInfo, ""); - assembly::CodeGenerator::assemble( + yul::CodeGenerator::assemble( _inlineAssembly.operations(), *_inlineAssembly.annotation().analysisInfo, m_context.nonConstAssembly(), diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 57b513d2..b0d17286 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -529,6 +529,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) { bool shortcutTaken = false; if (auto identifier = dynamic_cast<Identifier const*>(&_functionCall.expression())) + { + solAssert(!function.bound(), ""); if (auto functionDef = dynamic_cast<FunctionDefinition const*>(identifier->annotation().referencedDeclaration)) { // Do not directly visit the identifier, because this way, we can avoid @@ -537,6 +539,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) utils().pushCombinedFunctionEntryLabel(m_context.resolveVirtualFunction(*functionDef), false); shortcutTaken = true; } + } if (!shortcutTaken) _functionCall.expression().accept(*this); diff --git a/libsolidity/formal/CVC4Interface.cpp b/libsolidity/formal/CVC4Interface.cpp index 8952665f..de5e4430 100644 --- a/libsolidity/formal/CVC4Interface.cpp +++ b/libsolidity/formal/CVC4Interface.cpp @@ -33,8 +33,7 @@ CVC4Interface::CVC4Interface(): void CVC4Interface::reset() { - m_constants.clear(); - m_functions.clear(); + m_variables.clear(); m_solver.reset(); m_solver.setOption("produce-models", true); m_solver.setTimeLimit(queryTimeout); @@ -50,25 +49,10 @@ void CVC4Interface::pop() m_solver.pop(); } -void CVC4Interface::declareFunction(string _name, vector<SortPointer> const& _domain, Sort const& _codomain) +void CVC4Interface::declareVariable(string const& _name, Sort const& _sort) { - if (!m_functions.count(_name)) - { - CVC4::Type fType = m_context.mkFunctionType(cvc4Sort(_domain), cvc4Sort(_codomain)); - m_functions.insert({_name, m_context.mkVar(_name.c_str(), fType)}); - } -} - -void CVC4Interface::declareInteger(string _name) -{ - if (!m_constants.count(_name)) - m_constants.insert({_name, m_context.mkVar(_name.c_str(), m_context.integerType())}); -} - -void CVC4Interface::declareBool(string _name) -{ - if (!m_constants.count(_name)) - m_constants.insert({_name, m_context.mkVar(_name.c_str(), m_context.booleanType())}); + if (!m_variables.count(_name)) + m_variables.insert({_name, m_context.mkVar(_name.c_str(), cvc4Sort(_sort))}); } void CVC4Interface::addAssertion(Expression const& _expr) @@ -129,20 +113,19 @@ pair<CheckResult, vector<string>> CVC4Interface::check(vector<Expression> const& CVC4::Expr CVC4Interface::toCVC4Expr(Expression const& _expr) { - if (_expr.arguments.empty() && m_constants.count(_expr.name)) - return m_constants.at(_expr.name); + // Variable + if (_expr.arguments.empty() && m_variables.count(_expr.name)) + return m_variables.at(_expr.name); + vector<CVC4::Expr> arguments; for (auto const& arg: _expr.arguments) arguments.push_back(toCVC4Expr(arg)); string const& n = _expr.name; - if (m_functions.count(n)) - return m_context.mkExpr(CVC4::kind::APPLY_UF, m_functions[n], arguments); - else if (m_constants.count(n)) - { - solAssert(arguments.empty(), ""); - return m_constants.at(n); - } + // Function application + if (!arguments.empty() && m_variables.count(_expr.name)) + return m_context.mkExpr(CVC4::kind::APPLY_UF, m_variables.at(n), arguments); + // Literal else if (arguments.empty()) { if (n == "true") @@ -181,6 +164,10 @@ CVC4::Expr CVC4Interface::toCVC4Expr(Expression const& _expr) return m_context.mkExpr(CVC4::kind::MULT, arguments[0], arguments[1]); else if (n == "/") return m_context.mkExpr(CVC4::kind::INTS_DIVISION_TOTAL, arguments[0], arguments[1]); + else if (n == "select") + return m_context.mkExpr(CVC4::kind::SELECT, arguments[0], arguments[1]); + else if (n == "store") + return m_context.mkExpr(CVC4::kind::STORE, arguments[0], arguments[1], arguments[2]); // Cannot reach here. solAssert(false, ""); return arguments[0]; @@ -194,6 +181,16 @@ CVC4::Type CVC4Interface::cvc4Sort(Sort const& _sort) return m_context.booleanType(); case Kind::Int: return m_context.integerType(); + case Kind::Function: + { + FunctionSort const& fSort = dynamic_cast<FunctionSort const&>(_sort); + return m_context.mkFunctionType(cvc4Sort(fSort.domain), cvc4Sort(*fSort.codomain)); + } + case Kind::Array: + { + auto const& arraySort = dynamic_cast<ArraySort const&>(_sort); + return m_context.mkArrayType(cvc4Sort(*arraySort.domain), cvc4Sort(*arraySort.range)); + } default: break; } diff --git a/libsolidity/formal/CVC4Interface.h b/libsolidity/formal/CVC4Interface.h index f354c790..bbe23855 100644 --- a/libsolidity/formal/CVC4Interface.h +++ b/libsolidity/formal/CVC4Interface.h @@ -51,9 +51,7 @@ public: void push() override; void pop() override; - void declareFunction(std::string _name, std::vector<SortPointer> const& _domain, Sort const& _codomain) override; - void declareInteger(std::string _name) override; - void declareBool(std::string _name) override; + void declareVariable(std::string const&, Sort const&) override; void addAssertion(Expression const& _expr) override; std::pair<CheckResult, std::vector<std::string>> check(std::vector<Expression> const& _expressionsToEvaluate) override; @@ -65,8 +63,7 @@ private: CVC4::ExprManager m_context; CVC4::SmtEngine m_solver; - std::map<std::string, CVC4::Expr> m_constants; - std::map<std::string, CVC4::Expr> m_functions; + std::map<std::string, CVC4::Expr> m_variables; }; } diff --git a/libsolidity/formal/SMTChecker.cpp b/libsolidity/formal/SMTChecker.cpp index 7e75df87..5b7807f7 100644 --- a/libsolidity/formal/SMTChecker.cpp +++ b/libsolidity/formal/SMTChecker.cpp @@ -32,10 +32,19 @@ using namespace dev; using namespace langutil; using namespace dev::solidity; -SMTChecker::SMTChecker(ErrorReporter& _errorReporter, ReadCallback::Callback const& _readFileCallback): - m_interface(make_shared<smt::SMTPortfolio>(_readFileCallback)), +SMTChecker::SMTChecker(ErrorReporter& _errorReporter, map<h256, string> const& _smtlib2Responses): + m_interface(make_shared<smt::SMTPortfolio>(_smtlib2Responses)), m_errorReporter(_errorReporter) { +#if defined (HAVE_Z3) || defined (HAVE_CVC4) + if (!_smtlib2Responses.empty()) + m_errorReporter.warning( + "SMT-LIB2 query responses were given in the auxiliary input, " + "but this Solidity binary uses an SMT solver (Z3/CVC4) directly." + "These responses will be ignored." + "Consider disabling Z3/CVC4 at compilation time in order to use SMT-LIB2 responses." + ); +#endif } void SMTChecker::analyze(SourceUnit const& _source, shared_ptr<Scanner> const& _scanner) @@ -409,7 +418,7 @@ void SMTChecker::visitGasLeft(FunctionCall const& _funCall) auto const& symbolicVar = m_specialVariables.at(gasLeft); unsigned index = symbolicVar->index(); // We set the current value to unknown anyway to add type constraints. - symbolicVar->setUnknownValue(); + setUnknownValue(*symbolicVar); if (index > 0) m_interface->addAssertion(symbolicVar->currentValue() <= symbolicVar->valueAtIndex(index - 1)); } @@ -417,10 +426,15 @@ void SMTChecker::visitGasLeft(FunctionCall const& _funCall) void SMTChecker::visitBlockHash(FunctionCall const& _funCall) { string blockHash = "blockhash"; - defineUninterpretedFunction(blockHash, {make_shared<smt::Sort>(smt::Kind::Int)}, smt::Kind::Int); auto const& arguments = _funCall.arguments(); solAssert(arguments.size() == 1, ""); - defineExpr(_funCall, m_uninterpretedFunctions.at(blockHash)({expr(*arguments[0])})); + smt::SortPointer paramSort = smtSort(*arguments.at(0)->annotation().type); + smt::SortPointer returnSort = smtSort(*_funCall.annotation().type); + defineUninterpretedFunction( + blockHash, + make_shared<smt::FunctionSort>(vector<smt::SortPointer>{paramSort}, returnSort) + ); + defineExpr(_funCall, m_uninterpretedFunctions.at(blockHash)({expr(*arguments.at(0))})); m_uninterpretedTerms.push_back(&_funCall); } @@ -592,7 +606,7 @@ void SMTChecker::defineSpecialVariable(string const& _name, Expression const& _e { auto result = newSymbolicVariable(*_expr.annotation().type, _name, *m_interface); m_specialVariables.emplace(_name, result.second); - result.second->setUnknownValue(); + setUnknownValue(*result.second); if (result.first) m_errorReporter.warning( _expr.location(), @@ -606,10 +620,10 @@ void SMTChecker::defineSpecialVariable(string const& _name, Expression const& _e defineExpr(_expr, m_specialVariables.at(_name)->currentValue()); } -void SMTChecker::defineUninterpretedFunction(string const& _name, vector<smt::SortPointer> const& _domain, smt::Sort const& _codomain) +void SMTChecker::defineUninterpretedFunction(string const& _name, smt::SortPointer _sort) { if (!m_uninterpretedFunctions.count(_name)) - m_uninterpretedFunctions.emplace(_name, m_interface->newFunction(_name, _domain, _codomain)); + m_uninterpretedFunctions.emplace(_name, m_interface->newVariable(_name, _sort)); } void SMTChecker::arithmeticOperation(BinaryOperation const& _op) @@ -1066,13 +1080,23 @@ smt::Expression SMTChecker::newValue(VariableDeclaration const& _decl) void SMTChecker::setZeroValue(VariableDeclaration const& _decl) { solAssert(knownVariable(_decl), ""); - m_variables.at(&_decl)->setZeroValue(); + setZeroValue(*m_variables.at(&_decl)); +} + +void SMTChecker::setZeroValue(SymbolicVariable& _variable) +{ + smt::setSymbolicZeroValue(_variable, *m_interface); } void SMTChecker::setUnknownValue(VariableDeclaration const& _decl) { solAssert(knownVariable(_decl), ""); - m_variables.at(&_decl)->setUnknownValue(); + setUnknownValue(*m_variables.at(&_decl)); +} + +void SMTChecker::setUnknownValue(SymbolicVariable& _variable) +{ + smt::setSymbolicUnknownValue(_variable, *m_interface); } smt::Expression SMTChecker::expr(Expression const& _e) diff --git a/libsolidity/formal/SMTChecker.h b/libsolidity/formal/SMTChecker.h index d7f86cbc..34724848 100644 --- a/libsolidity/formal/SMTChecker.h +++ b/libsolidity/formal/SMTChecker.h @@ -47,10 +47,15 @@ class VariableUsage; class SMTChecker: private ASTConstVisitor { public: - SMTChecker(langutil::ErrorReporter& _errorReporter, ReadCallback::Callback const& _readCallback); + SMTChecker(langutil::ErrorReporter& _errorReporter, std::map<h256, std::string> const& _smtlib2Responses); void analyze(SourceUnit const& _sources, std::shared_ptr<langutil::Scanner> const& _scanner); + /// This is used if the SMT solver is not directly linked into this binary. + /// @returns a list of inputs to the SMT solver that were not part of the argument to + /// the constructor. + std::vector<std::string> unhandledQueries() { return m_interface->unhandledQueries(); } + private: // TODO: Check that we do not have concurrent reads and writes to a variable, // because the order of expression evaluation is undefined @@ -88,7 +93,7 @@ private: void inlineFunctionCall(FunctionCall const&); void defineSpecialVariable(std::string const& _name, Expression const& _expr, bool _increaseIndex = false); - void defineUninterpretedFunction(std::string const& _name, std::vector<smt::SortPointer> const& _domain, smt::Sort const& _codomain); + void defineUninterpretedFunction(std::string const& _name, smt::SortPointer _sort); /// Division expression in the given type. Requires special treatment because /// of rounding for signed division. @@ -157,8 +162,10 @@ private: /// Sets the value of the declaration to zero. void setZeroValue(VariableDeclaration const& _decl); + void setZeroValue(SymbolicVariable& _variable); /// Resets the variable to an unknown value (in its range). void setUnknownValue(VariableDeclaration const& decl); + void setUnknownValue(SymbolicVariable& _variable); /// Returns the expression corresponding to the AST node. Throws if the expression does not exist. smt::Expression expr(Expression const& _e); diff --git a/libsolidity/formal/SMTLib2Interface.cpp b/libsolidity/formal/SMTLib2Interface.cpp index 7a6b558b..3cfa01b1 100644 --- a/libsolidity/formal/SMTLib2Interface.cpp +++ b/libsolidity/formal/SMTLib2Interface.cpp @@ -20,6 +20,8 @@ #include <liblangutil/Exceptions.h> #include <libsolidity/interface/ReadFile.h> +#include <libdevcore/Keccak256.h> + #include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/join.hpp> #include <boost/filesystem/operations.hpp> @@ -37,8 +39,8 @@ using namespace dev; using namespace dev::solidity; using namespace dev::solidity::smt; -SMTLib2Interface::SMTLib2Interface(ReadCallback::Callback const& _queryCallback): - m_queryCallback(_queryCallback) +SMTLib2Interface::SMTLib2Interface(map<h256, string> const& _queryResponses): + m_queryResponses(_queryResponses) { reset(); } @@ -47,8 +49,7 @@ void SMTLib2Interface::reset() { m_accumulatedOutput.clear(); m_accumulatedOutput.emplace_back(); - m_constants.clear(); - m_functions.clear(); + m_variables.clear(); write("(set-option :produce-models true)"); write("(set-logic QF_UFLIA)"); } @@ -64,45 +65,39 @@ void SMTLib2Interface::pop() m_accumulatedOutput.pop_back(); } -void SMTLib2Interface::declareFunction(string _name, vector<SortPointer> const& _domain, Sort const& _codomain) +void SMTLib2Interface::declareVariable(string const& _name, Sort const& _sort) { + if (_sort.kind == Kind::Function) + declareFunction(_name, _sort); + else if (!m_variables.count(_name)) + { + m_variables.insert(_name); + write("(declare-fun |" + _name + "| () " + toSmtLibSort(_sort) + ')'); + } +} + +void SMTLib2Interface::declareFunction(string const& _name, Sort const& _sort) +{ + solAssert(_sort.kind == smt::Kind::Function, ""); // TODO Use domain and codomain as key as well - string domain(""); - for (auto const& sort: _domain) - domain += toSmtLibSort(*sort) + ' '; - if (!m_functions.count(_name)) + if (!m_variables.count(_name)) { - m_functions.insert(_name); + FunctionSort fSort = dynamic_cast<FunctionSort const&>(_sort); + string domain = toSmtLibSort(fSort.domain); + string codomain = toSmtLibSort(*fSort.codomain); + m_variables.insert(_name); write( "(declare-fun |" + _name + - "| (" + + "| " + domain + - ") " + - (_codomain.kind == Kind::Int ? "Int" : "Bool") + + " " + + codomain + ")" ); } } -void SMTLib2Interface::declareInteger(string _name) -{ - if (!m_constants.count(_name)) - { - m_constants.insert(_name); - write("(declare-const |" + _name + "| Int)"); - } -} - -void SMTLib2Interface::declareBool(string _name) -{ - if (!m_constants.count(_name)) - { - m_constants.insert(_name); - write("(declare-const |" + _name + "| Bool)"); - } -} - void SMTLib2Interface::addAssertion(Expression const& _expr) { write("(assert " + toSExpr(_expr) + ")"); @@ -151,11 +146,25 @@ string SMTLib2Interface::toSmtLibSort(Sort const& _sort) return "Int"; case Kind::Bool: return "Bool"; + case Kind::Array: + { + auto const& arraySort = dynamic_cast<ArraySort const&>(_sort); + return "(Array " + toSmtLibSort(*arraySort.domain) + ' ' + toSmtLibSort(*arraySort.range) + ')'; + } default: solAssert(false, "Invalid SMT sort"); } } +string SMTLib2Interface::toSmtLibSort(vector<SortPointer> const& _sorts) +{ + string ssort("("); + for (auto const& sort: _sorts) + ssort += toSmtLibSort(*sort) + " "; + ssort += ")"; + return ssort; +} + void SMTLib2Interface::write(string _data) { solAssert(!m_accumulatedOutput.empty(), ""); @@ -205,11 +214,12 @@ vector<string> SMTLib2Interface::parseValues(string::const_iterator _start, stri string SMTLib2Interface::querySolver(string const& _input) { - if (!m_queryCallback) - BOOST_THROW_EXCEPTION(SolverError() << errinfo_comment("No SMT solver available.")); - - ReadCallback::Result queryResult = m_queryCallback(_input); - if (!queryResult.success) - BOOST_THROW_EXCEPTION(SolverError() << errinfo_comment(queryResult.responseOrErrorMessage)); - return queryResult.responseOrErrorMessage; + h256 inputHash = dev::keccak256(_input); + if (m_queryResponses.count(inputHash)) + return m_queryResponses.at(inputHash); + else + { + m_unhandledQueries.push_back(_input); + return "unknown\n"; + } } diff --git a/libsolidity/formal/SMTLib2Interface.h b/libsolidity/formal/SMTLib2Interface.h index f3c58d6b..55fc4096 100644 --- a/libsolidity/formal/SMTLib2Interface.h +++ b/libsolidity/formal/SMTLib2Interface.h @@ -22,6 +22,8 @@ #include <liblangutil/Exceptions.h> #include <libsolidity/interface/ReadFile.h> +#include <libdevcore/FixedHash.h> + #include <libdevcore/Common.h> #include <boost/noncopyable.hpp> @@ -42,23 +44,26 @@ namespace smt class SMTLib2Interface: public SolverInterface, public boost::noncopyable { public: - explicit SMTLib2Interface(ReadCallback::Callback const& _queryCallback); + explicit SMTLib2Interface(std::map<h256, std::string> const& _queryResponses); void reset() override; void push() override; void pop() override; - void declareFunction(std::string _name, std::vector<SortPointer> const& _domain, Sort const& _codomain) override; - void declareInteger(std::string _name) override; - void declareBool(std::string _name) override; + void declareVariable(std::string const&, Sort const&) override; void addAssertion(Expression const& _expr) override; std::pair<CheckResult, std::vector<std::string>> check(std::vector<Expression> const& _expressionsToEvaluate) override; + std::vector<std::string> unhandledQueries() override { return m_unhandledQueries; } + private: + void declareFunction(std::string const&, Sort const&); + std::string toSExpr(Expression const& _expr); std::string toSmtLibSort(Sort const& _sort); + std::string toSmtLibSort(std::vector<SortPointer> const& _sort); void write(std::string _data); @@ -68,10 +73,11 @@ private: /// Communicates with the solver via the callback. Throws SMTSolverError on error. std::string querySolver(std::string const& _input); - ReadCallback::Callback m_queryCallback; std::vector<std::string> m_accumulatedOutput; - std::set<std::string> m_constants; - std::set<std::string> m_functions; + std::set<std::string> m_variables; + + std::map<h256, std::string> const& m_queryResponses; + std::vector<std::string> m_unhandledQueries; }; } diff --git a/libsolidity/formal/SMTPortfolio.cpp b/libsolidity/formal/SMTPortfolio.cpp index e01a5acc..2a109b89 100644 --- a/libsolidity/formal/SMTPortfolio.cpp +++ b/libsolidity/formal/SMTPortfolio.cpp @@ -23,27 +23,22 @@ #ifdef HAVE_CVC4 #include <libsolidity/formal/CVC4Interface.h> #endif -#if !defined (HAVE_Z3) && !defined (HAVE_CVC4) #include <libsolidity/formal/SMTLib2Interface.h> -#endif using namespace std; using namespace dev; using namespace dev::solidity; using namespace dev::solidity::smt; -SMTPortfolio::SMTPortfolio(ReadCallback::Callback const& _readCallback) +SMTPortfolio::SMTPortfolio(map<h256, string> const& _smtlib2Responses) { + m_solvers.emplace_back(make_shared<smt::SMTLib2Interface>(_smtlib2Responses)); #ifdef HAVE_Z3 m_solvers.emplace_back(make_shared<smt::Z3Interface>()); #endif #ifdef HAVE_CVC4 m_solvers.emplace_back(make_shared<smt::CVC4Interface>()); #endif -#if !defined (HAVE_Z3) && !defined (HAVE_CVC4) - m_solvers.emplace_back(make_shared<smt::SMTLib2Interface>(_readCallback)), -#endif - (void)_readCallback; } void SMTPortfolio::reset() @@ -64,22 +59,10 @@ void SMTPortfolio::pop() s->pop(); } -void SMTPortfolio::declareFunction(string _name, vector<SortPointer> const& _domain, Sort const& _codomain) -{ - for (auto s : m_solvers) - s->declareFunction(_name, _domain, _codomain); -} - -void SMTPortfolio::declareInteger(string _name) -{ - for (auto s : m_solvers) - s->declareInteger(_name); -} - -void SMTPortfolio::declareBool(string _name) +void SMTPortfolio::declareVariable(string const& _name, Sort const& _sort) { for (auto s : m_solvers) - s->declareBool(_name); + s->declareVariable(_name, _sort); } void SMTPortfolio::addAssertion(Expression const& _expr) diff --git a/libsolidity/formal/SMTPortfolio.h b/libsolidity/formal/SMTPortfolio.h index 712fb545..7f5ba37e 100644 --- a/libsolidity/formal/SMTPortfolio.h +++ b/libsolidity/formal/SMTPortfolio.h @@ -22,8 +22,11 @@ #include <libsolidity/interface/ReadFile.h> +#include <libdevcore/FixedHash.h> + #include <boost/noncopyable.hpp> +#include <map> #include <vector> namespace dev @@ -42,20 +45,19 @@ namespace smt class SMTPortfolio: public SolverInterface, public boost::noncopyable { public: - SMTPortfolio(ReadCallback::Callback const& _readCallback); + SMTPortfolio(std::map<h256, std::string> const& _smtlib2Responses); void reset() override; void push() override; void pop() override; - void declareFunction(std::string _name, std::vector<SortPointer> const& _domain, Sort const& _codomain) override; - void declareInteger(std::string _name) override; - void declareBool(std::string _name) override; + void declareVariable(std::string const&, Sort const&) override; void addAssertion(Expression const& _expr) override; std::pair<CheckResult, std::vector<std::string>> check(std::vector<Expression> const& _expressionsToEvaluate) override; + std::vector<std::string> unhandledQueries() override { return m_solvers.at(0)->unhandledQueries(); } private: static bool solverAnswered(CheckResult result); diff --git a/libsolidity/formal/SolverInterface.h b/libsolidity/formal/SolverInterface.h index df036190..cc8214de 100644 --- a/libsolidity/formal/SolverInterface.h +++ b/libsolidity/formal/SolverInterface.h @@ -45,7 +45,9 @@ enum class CheckResult enum class Kind { Int, - Bool + Bool, + Function, + Array }; struct Sort @@ -53,11 +55,46 @@ struct Sort Sort(Kind _kind): kind(_kind) {} virtual ~Sort() = default; - Kind const kind; bool operator==(Sort const& _other) const { return kind == _other.kind; } + + Kind const kind; }; using SortPointer = std::shared_ptr<Sort>; +struct FunctionSort: public Sort +{ + FunctionSort(std::vector<SortPointer> _domain, SortPointer _codomain): + Sort(Kind::Function), domain(std::move(_domain)), codomain(std::move(_codomain)) {} + bool operator==(FunctionSort const& _other) const + { + if (!std::equal( + domain.begin(), + domain.end(), + _other.domain.begin(), + [&](SortPointer _a, SortPointer _b) { return *_a == *_b; } + )) + return false; + return Sort::operator==(_other) && *codomain == *_other.codomain; + } + + std::vector<SortPointer> domain; + SortPointer codomain; +}; + +struct ArraySort: public Sort +{ + /// _domain is the sort of the indices + /// _range is the sort of the values + ArraySort(SortPointer _domain, SortPointer _range): + Sort(Kind::Array), domain(std::move(_domain)), range(std::move(_range)) {} + bool operator==(ArraySort const& _other) const + { + return Sort::operator==(_other) && *domain == *_other.domain && *range == *_other.range; + } + + SortPointer domain; + SortPointer range; +}; /// C++ representation of an SMTLIB2 expression. class Expression @@ -89,7 +126,9 @@ public: {"+", 2}, {"-", 2}, {"*", 2}, - {"/", 2} + {"/", 2}, + {"select", 2}, + {"store", 3} }; return operatorsArity.count(name) && operatorsArity.at(name) == arguments.size(); } @@ -107,6 +146,36 @@ public: return !std::move(_a) || std::move(_b); } + /// select is the SMT representation of an array index access. + static Expression select(Expression _array, Expression _index) + { + solAssert(_array.sort->kind == Kind::Array, ""); + auto const& arraySort = dynamic_cast<ArraySort const*>(_array.sort.get()); + solAssert(arraySort, ""); + solAssert(*arraySort->domain == *_index.sort, ""); + return Expression( + "select", + std::vector<Expression>{std::move(_array), std::move(_index)}, + arraySort->range + ); + } + + /// store is the SMT representation of an assignment to array index. + /// The function is pure and returns the modified array. + static Expression store(Expression _array, Expression _index, Expression _element) + { + solAssert(_array.sort->kind == Kind::Array, ""); + auto const& arraySort = dynamic_cast<ArraySort const*>(_array.sort.get()); + solAssert(arraySort, ""); + solAssert(*arraySort->domain == *_index.sort, ""); + solAssert(*arraySort->range == *_element.sort, ""); + return Expression( + "store", + std::vector<Expression>{std::move(_array), std::move(_index), std::move(_element)}, + _array.sort + ); + } + friend Expression operator!(Expression _a) { return Expression("not", std::move(_a), Kind::Bool); @@ -162,10 +231,12 @@ public: Expression operator()(std::vector<Expression> _arguments) const { solAssert( - arguments.empty(), + sort->kind == Kind::Function, "Attempted function application to non-function." ); - return Expression(name, std::move(_arguments), sort); + auto fSort = dynamic_cast<FunctionSort const*>(sort.get()); + solAssert(fSort, ""); + return Expression(name, std::move(_arguments), fSort->codomain); } std::string name; @@ -198,26 +269,12 @@ public: virtual void push() = 0; virtual void pop() = 0; - virtual void declareFunction(std::string _name, std::vector<SortPointer> const& _domain, Sort const& _codomain) = 0; - Expression newFunction(std::string _name, std::vector<SortPointer> const& _domain, Sort const& _codomain) + virtual void declareVariable(std::string const& _name, Sort const& _sort) = 0; + Expression newVariable(std::string _name, SortPointer _sort) { - declareFunction(_name, _domain, _codomain); // Subclasses should do something here - return Expression(std::move(_name), {}, _codomain.kind); - } - virtual void declareInteger(std::string _name) = 0; - Expression newInteger(std::string _name) - { - // Subclasses should do something here - declareInteger(_name); - return Expression(std::move(_name), {}, Kind::Int); - } - virtual void declareBool(std::string _name) = 0; - Expression newBool(std::string _name) - { - // Subclasses should do something here - declareBool(_name); - return Expression(std::move(_name), {}, Kind::Bool); + declareVariable(_name, *_sort); + return Expression(std::move(_name), {}, std::move(_sort)); } virtual void addAssertion(Expression const& _expr) = 0; @@ -227,6 +284,9 @@ public: virtual std::pair<CheckResult, std::vector<std::string>> check(std::vector<Expression> const& _expressionsToEvaluate) = 0; + /// @returns a list of queries that the system was not able to respond to. + virtual std::vector<std::string> unhandledQueries() { return {}; } + protected: // SMT query timeout in milliseconds. static int const queryTimeout = 10000; diff --git a/libsolidity/formal/SymbolicTypes.cpp b/libsolidity/formal/SymbolicTypes.cpp index a3b6e3a8..c297c807 100644 --- a/libsolidity/formal/SymbolicTypes.cpp +++ b/libsolidity/formal/SymbolicTypes.cpp @@ -32,10 +32,33 @@ smt::SortPointer dev::solidity::smtSort(Type const& _type) return make_shared<smt::Sort>(smt::Kind::Int); case smt::Kind::Bool: return make_shared<smt::Sort>(smt::Kind::Bool); + case smt::Kind::Function: + { + auto fType = dynamic_cast<FunctionType const*>(&_type); + solAssert(fType, ""); + vector<smt::SortPointer> parameterSorts = smtSort(fType->parameterTypes()); + auto returnTypes = fType->returnParameterTypes(); + // TODO remove this when we support tuples. + solAssert(returnTypes.size() == 1, ""); + smt::SortPointer returnSort = smtSort(*returnTypes.at(0)); + return make_shared<smt::FunctionSort>(parameterSorts, returnSort); + } + case smt::Kind::Array: + { + solUnimplementedAssert(false, "Invalid type"); + } } solAssert(false, "Invalid type"); } +vector<smt::SortPointer> dev::solidity::smtSort(vector<TypePointer> const& _types) +{ + vector<smt::SortPointer> sorts; + for (auto const& type: _types) + sorts.push_back(smtSort(*type)); + return sorts; +} + smt::Kind dev::solidity::smtKind(Type::Category _category) { if (isNumber(_category)) @@ -146,3 +169,32 @@ smt::Expression dev::solidity::maxValue(IntegerType const& _type) { return smt::Expression(_type.maxValue()); } + +void dev::solidity::smt::setSymbolicZeroValue(SymbolicVariable const& _variable, smt::SolverInterface& _interface) +{ + setSymbolicZeroValue(_variable.currentValue(), _variable.type(), _interface); +} + +void dev::solidity::smt::setSymbolicZeroValue(smt::Expression _expr, TypePointer const& _type, smt::SolverInterface& _interface) +{ + if (isInteger(_type->category())) + _interface.addAssertion(_expr == 0); + else if (isBool(_type->category())) + _interface.addAssertion(_expr == smt::Expression(false)); +} + +void dev::solidity::smt::setSymbolicUnknownValue(SymbolicVariable const& _variable, smt::SolverInterface& _interface) +{ + setSymbolicUnknownValue(_variable.currentValue(), _variable.type(), _interface); +} + +void dev::solidity::smt::setSymbolicUnknownValue(smt::Expression _expr, TypePointer const& _type, smt::SolverInterface& _interface) +{ + if (isInteger(_type->category())) + { + auto intType = dynamic_cast<IntegerType const*>(_type.get()); + solAssert(intType, ""); + _interface.addAssertion(_expr >= minValue(*intType)); + _interface.addAssertion(_expr <= maxValue(*intType)); + } +} diff --git a/libsolidity/formal/SymbolicTypes.h b/libsolidity/formal/SymbolicTypes.h index c802c5b4..984653b3 100644 --- a/libsolidity/formal/SymbolicTypes.h +++ b/libsolidity/formal/SymbolicTypes.h @@ -30,6 +30,7 @@ namespace solidity /// Returns the SMT sort that models the Solidity type _type. smt::SortPointer smtSort(Type const& _type); +std::vector<smt::SortPointer> smtSort(std::vector<TypePointer> const& _types); /// Returns the SMT kind that models the Solidity type type category _category. smt::Kind smtKind(Type::Category _category); @@ -54,5 +55,15 @@ std::pair<bool, std::shared_ptr<SymbolicVariable>> newSymbolicVariable(Type cons smt::Expression minValue(IntegerType const& _type); smt::Expression maxValue(IntegerType const& _type); +namespace smt +{ + +void setSymbolicZeroValue(SymbolicVariable const& _variable, smt::SolverInterface& _interface); +void setSymbolicZeroValue(smt::Expression _expr, TypePointer const& _type, smt::SolverInterface& _interface); +void setSymbolicUnknownValue(SymbolicVariable const& _variable, smt::SolverInterface& _interface); +void setSymbolicUnknownValue(smt::Expression _expr, TypePointer const& _type, smt::SolverInterface& _interface); + +} + } } diff --git a/libsolidity/formal/SymbolicVariables.cpp b/libsolidity/formal/SymbolicVariables.cpp index 194c843e..efaeb97a 100644 --- a/libsolidity/formal/SymbolicVariables.cpp +++ b/libsolidity/formal/SymbolicVariables.cpp @@ -59,16 +59,7 @@ SymbolicBoolVariable::SymbolicBoolVariable( smt::Expression SymbolicBoolVariable::valueAtIndex(int _index) const { - return m_interface.newBool(uniqueSymbol(_index)); -} - -void SymbolicBoolVariable::setZeroValue() -{ - m_interface.addAssertion(currentValue() == smt::Expression(false)); -} - -void SymbolicBoolVariable::setUnknownValue() -{ + return m_interface.newVariable(uniqueSymbol(_index), make_shared<smt::Sort>(smt::Kind::Bool)); } SymbolicIntVariable::SymbolicIntVariable( @@ -83,20 +74,7 @@ SymbolicIntVariable::SymbolicIntVariable( smt::Expression SymbolicIntVariable::valueAtIndex(int _index) const { - return m_interface.newInteger(uniqueSymbol(_index)); -} - -void SymbolicIntVariable::setZeroValue() -{ - m_interface.addAssertion(currentValue() == 0); -} - -void SymbolicIntVariable::setUnknownValue() -{ - auto intType = dynamic_cast<IntegerType const*>(m_type.get()); - solAssert(intType, ""); - m_interface.addAssertion(currentValue() >= minValue(*intType)); - m_interface.addAssertion(currentValue() <= maxValue(*intType)); + return m_interface.newVariable(uniqueSymbol(_index), make_shared<smt::Sort>(smt::Kind::Int)); } SymbolicAddressVariable::SymbolicAddressVariable( diff --git a/libsolidity/formal/SymbolicVariables.h b/libsolidity/formal/SymbolicVariables.h index 13b944a5..fcf32760 100644 --- a/libsolidity/formal/SymbolicVariables.h +++ b/libsolidity/formal/SymbolicVariables.h @@ -64,20 +64,15 @@ public: unsigned index() const { return m_ssa->index(); } unsigned& index() { return m_ssa->index(); } - /// Sets the var to the default value of its type. - /// Inherited types must implement. - virtual void setZeroValue() = 0; - /// The unknown value is the full range of valid values. - /// It is sub-type dependent, but not mandatory. - virtual void setUnknownValue() {} + TypePointer const& type() const { return m_type; } protected: std::string uniqueSymbol(unsigned _index) const; - TypePointer m_type = nullptr; + TypePointer m_type; std::string m_uniqueName; smt::SolverInterface& m_interface; - std::shared_ptr<SSAVariable> m_ssa = nullptr; + std::shared_ptr<SSAVariable> m_ssa; }; /** @@ -92,11 +87,6 @@ public: smt::SolverInterface& _interface ); - /// Sets the var to false. - void setZeroValue(); - /// Does nothing since the SMT solver already knows the valid values for Bool. - void setUnknownValue(); - protected: smt::Expression valueAtIndex(int _index) const; }; @@ -113,11 +103,6 @@ public: smt::SolverInterface& _interface ); - /// Sets the var to 0. - void setZeroValue(); - /// Sets the variable to the full valid value range. - void setUnknownValue(); - protected: smt::Expression valueAtIndex(int _index) const; }; diff --git a/libsolidity/formal/Z3Interface.cpp b/libsolidity/formal/Z3Interface.cpp index ac6fbd54..cb01dc61 100644 --- a/libsolidity/formal/Z3Interface.cpp +++ b/libsolidity/formal/Z3Interface.cpp @@ -51,22 +51,22 @@ void Z3Interface::pop() m_solver.pop(); } -void Z3Interface::declareFunction(string _name, vector<SortPointer> const& _domain, Sort const& _codomain) +void Z3Interface::declareVariable(string const& _name, Sort const& _sort) { - if (!m_functions.count(_name)) - m_functions.insert({_name, m_context.function(_name.c_str(), z3Sort(_domain), z3Sort(_codomain))}); + if (_sort.kind == Kind::Function) + declareFunction(_name, _sort); + else if (!m_constants.count(_name)) + m_constants.insert({_name, m_context.constant(_name.c_str(), z3Sort(_sort))}); } -void Z3Interface::declareInteger(string _name) +void Z3Interface::declareFunction(string const& _name, Sort const& _sort) { - if (!m_constants.count(_name)) - m_constants.insert({_name, m_context.int_const(_name.c_str())}); -} - -void Z3Interface::declareBool(string _name) -{ - if (!m_constants.count(_name)) - m_constants.insert({_name, m_context.bool_const(_name.c_str())}); + solAssert(_sort.kind == smt::Kind::Function, ""); + if (!m_functions.count(_name)) + { + FunctionSort fSort = dynamic_cast<FunctionSort const&>(_sort); + m_functions.insert({_name, m_context.function(_name.c_str(), z3Sort(fSort.domain), z3Sort(*fSort.codomain))}); + } } void Z3Interface::addAssertion(Expression const& _expr) @@ -163,6 +163,10 @@ z3::expr Z3Interface::toZ3Expr(Expression const& _expr) return arguments[0] * arguments[1]; else if (n == "/") return arguments[0] / arguments[1]; + else if (n == "select") + return z3::select(arguments[0], arguments[1]); + else if (n == "store") + return z3::store(arguments[0], arguments[1], arguments[2]); // Cannot reach here. solAssert(false, ""); return arguments[0]; @@ -176,6 +180,11 @@ z3::sort Z3Interface::z3Sort(Sort const& _sort) return m_context.bool_sort(); case Kind::Int: return m_context.int_sort(); + case Kind::Array: + { + auto const& arraySort = dynamic_cast<ArraySort const&>(_sort); + return m_context.array_sort(z3Sort(*arraySort.domain), z3Sort(*arraySort.range)); + } default: break; } diff --git a/libsolidity/formal/Z3Interface.h b/libsolidity/formal/Z3Interface.h index 8c1fcf61..86e1badd 100644 --- a/libsolidity/formal/Z3Interface.h +++ b/libsolidity/formal/Z3Interface.h @@ -40,14 +40,14 @@ public: void push() override; void pop() override; - void declareFunction(std::string _name, std::vector<SortPointer> const& _domain, Sort const& _codomain) override; - void declareInteger(std::string _name) override; - void declareBool(std::string _name) override; + void declareVariable(std::string const& _name, Sort const& _sort) override; void addAssertion(Expression const& _expr) override; std::pair<CheckResult, std::vector<std::string>> check(std::vector<Expression> const& _expressionsToEvaluate) override; private: + void declareFunction(std::string const& _name, Sort const& _sort); + z3::expr toZ3Expr(Expression const& _expr); z3::sort z3Sort(smt::Sort const& _sort); z3::sort_vector z3Sort(std::vector<smt::SortPointer> const& _sorts); diff --git a/libsolidity/inlineasm/AsmPrinter.h b/libsolidity/inlineasm/AsmPrinter.h deleted file mode 100644 index 72048975..00000000 --- a/libsolidity/inlineasm/AsmPrinter.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - This file is part of solidity. - - solidity is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - solidity is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with solidity. If not, see <http://www.gnu.org/licenses/>. -*/ -/** - * @author Christian <c@ethdev.com> - * @date 2017 - * Converts a parsed assembly into its textual form. - */ - -#pragma once - -#include <libsolidity/inlineasm/AsmDataForward.h> - -#include <libyul/YulString.h> - -#include <boost/variant.hpp> - -namespace dev -{ -namespace solidity -{ -namespace assembly -{ - -class AsmPrinter: public boost::static_visitor<std::string> -{ -public: - explicit AsmPrinter(bool _yul = false): m_yul(_yul) {} - - std::string operator()(assembly::Instruction const& _instruction); - std::string operator()(assembly::Literal const& _literal); - std::string operator()(assembly::Identifier const& _identifier); - std::string operator()(assembly::FunctionalInstruction const& _functionalInstruction); - std::string operator()(assembly::ExpressionStatement const& _expr); - std::string operator()(assembly::Label const& _label); - std::string operator()(assembly::StackAssignment const& _assignment); - std::string operator()(assembly::Assignment const& _assignment); - std::string operator()(assembly::VariableDeclaration const& _variableDeclaration); - std::string operator()(assembly::FunctionDefinition const& _functionDefinition); - std::string operator()(assembly::FunctionCall const& _functionCall); - std::string operator()(assembly::If const& _if); - std::string operator()(assembly::Switch const& _switch); - std::string operator()(assembly::ForLoop const& _forLoop); - std::string operator()(assembly::Block const& _block); - -private: - std::string formatTypedName(TypedName _variable) const; - std::string appendTypeName(yul::YulString _type) const; - - bool m_yul = false; -}; - -} -} -} diff --git a/libsolidity/interface/AssemblyStack.cpp b/libsolidity/interface/AssemblyStack.cpp index 5b6b1113..31959d93 100644 --- a/libsolidity/interface/AssemblyStack.cpp +++ b/libsolidity/interface/AssemblyStack.cpp @@ -23,17 +23,16 @@ #include <libsolidity/interface/AssemblyStack.h> #include <liblangutil/Scanner.h> -#include <libsolidity/inlineasm/AsmPrinter.h> -#include <libsolidity/inlineasm/AsmParser.h> -#include <libsolidity/inlineasm/AsmAnalysis.h> -#include <libsolidity/inlineasm/AsmAnalysisInfo.h> -#include <libsolidity/inlineasm/AsmCodeGen.h> - -#include <libevmasm/Assembly.h> - +#include <libyul/AsmPrinter.h> +#include <libyul/AsmParser.h> +#include <libyul/AsmAnalysis.h> +#include <libyul/AsmAnalysisInfo.h> +#include <libyul/AsmCodeGen.h> #include <libyul/backends/evm/EVMCodeTransform.h> #include <libyul/backends/evm/EVMAssembly.h> +#include <libevmasm/Assembly.h> + using namespace std; using namespace dev; using namespace langutil; @@ -41,19 +40,19 @@ using namespace dev::solidity; namespace { -assembly::AsmFlavour languageToAsmFlavour(AssemblyStack::Language _language) +yul::AsmFlavour languageToAsmFlavour(AssemblyStack::Language _language) { switch (_language) { case AssemblyStack::Language::Assembly: - return assembly::AsmFlavour::Loose; + return yul::AsmFlavour::Loose; case AssemblyStack::Language::StrictAssembly: - return assembly::AsmFlavour::Strict; + return yul::AsmFlavour::Strict; case AssemblyStack::Language::Yul: - return assembly::AsmFlavour::Yul; + return yul::AsmFlavour::Yul; } solAssert(false, ""); - return assembly::AsmFlavour::Yul; + return yul::AsmFlavour::Yul; } } @@ -70,7 +69,7 @@ bool AssemblyStack::parseAndAnalyze(std::string const& _sourceName, std::string m_errors.clear(); m_analysisSuccessful = false; m_scanner = make_shared<Scanner>(CharStream(_source), _sourceName); - m_parserResult = assembly::Parser(m_errorReporter, languageToAsmFlavour(m_language)).parse(m_scanner, false); + m_parserResult = yul::Parser(m_errorReporter, languageToAsmFlavour(m_language)).parse(m_scanner, false); if (!m_errorReporter.errors().empty()) return false; solAssert(m_parserResult, ""); @@ -78,21 +77,21 @@ bool AssemblyStack::parseAndAnalyze(std::string const& _sourceName, std::string return analyzeParsed(); } -bool AssemblyStack::analyze(assembly::Block const& _block, Scanner const* _scanner) +bool AssemblyStack::analyze(yul::Block const& _block, Scanner const* _scanner) { m_errors.clear(); m_analysisSuccessful = false; if (_scanner) m_scanner = make_shared<Scanner>(*_scanner); - m_parserResult = make_shared<assembly::Block>(_block); + m_parserResult = make_shared<yul::Block>(_block); return analyzeParsed(); } bool AssemblyStack::analyzeParsed() { - m_analysisInfo = make_shared<assembly::AsmAnalysisInfo>(); - assembly::AsmAnalyzer analyzer(*m_analysisInfo, m_errorReporter, m_evmVersion, boost::none, languageToAsmFlavour(m_language)); + m_analysisInfo = make_shared<yul::AsmAnalysisInfo>(); + yul::AsmAnalyzer analyzer(*m_analysisInfo, m_errorReporter, m_evmVersion, boost::none, languageToAsmFlavour(m_language)); m_analysisSuccessful = analyzer.analyze(*m_parserResult); return m_analysisSuccessful; } @@ -109,7 +108,7 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const { MachineAssemblyObject object; eth::Assembly assembly; - assembly::CodeGenerator::assemble(*m_parserResult, *m_analysisInfo, assembly); + yul::CodeGenerator::assemble(*m_parserResult, *m_analysisInfo, assembly); object.bytecode = make_shared<eth::LinkerObject>(assembly.assemble()); object.assembly = assembly.assemblyString(); return object; @@ -133,5 +132,5 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const string AssemblyStack::print() const { solAssert(m_parserResult, ""); - return assembly::AsmPrinter(m_language == Language::Yul)(*m_parserResult); + return yul::AsmPrinter(m_language == Language::Yul)(*m_parserResult); } diff --git a/libsolidity/interface/AssemblyStack.h b/libsolidity/interface/AssemblyStack.h index d6ee33cf..03b811db 100644 --- a/libsolidity/interface/AssemblyStack.h +++ b/libsolidity/interface/AssemblyStack.h @@ -34,16 +34,17 @@ namespace langutil class Scanner; } -namespace dev -{ -namespace solidity -{ -namespace assembly +namespace yul { struct AsmAnalysisInfo; struct Block; } +namespace dev +{ +namespace solidity +{ + struct MachineAssemblyObject { std::shared_ptr<eth::LinkerObject> bytecode; @@ -73,7 +74,7 @@ public: /// Runs analysis step on the supplied block, returns false if input cannot be assembled. /// Multiple calls overwrite the previous state. - bool analyze(assembly::Block const& _block, langutil::Scanner const* _scanner = nullptr); + bool analyze(yul::Block const& _block, langutil::Scanner const* _scanner = nullptr); /// Run the assembly step (should only be called after parseAndAnalyze). MachineAssemblyObject assemble(Machine _machine) const; @@ -93,8 +94,8 @@ private: std::shared_ptr<langutil::Scanner> m_scanner; bool m_analysisSuccessful = false; - std::shared_ptr<assembly::Block> m_parserResult; - std::shared_ptr<assembly::AsmAnalysisInfo> m_analysisInfo; + std::shared_ptr<yul::Block> m_parserResult; + std::shared_ptr<yul::AsmAnalysisInfo> m_analysisInfo; langutil::ErrorList m_errors; langutil::ErrorReporter m_errorReporter; }; diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index a5674705..de4a7ec2 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -27,7 +27,6 @@ #include <libsolidity/interface/Version.h> #include <libsolidity/analysis/SemVerHandler.h> #include <libsolidity/ast/AST.h> -#include <liblangutil/Scanner.h> #include <libsolidity/parsing/Parser.h> #include <libsolidity/analysis/ControlFlowAnalyzer.h> #include <libsolidity/analysis/ControlFlowGraph.h> @@ -45,10 +44,12 @@ #include <libsolidity/interface/Natspec.h> #include <libsolidity/interface/GasEstimator.h> -#include <libevmasm/Exceptions.h> - #include <libyul/YulString.h> +#include <liblangutil/Scanner.h> + +#include <libevmasm/Exceptions.h> + #include <libdevcore/SwarmHash.h> #include <libdevcore/JSON.h> @@ -107,6 +108,8 @@ void CompilerStack::reset(bool _keepSources) m_stackState = Empty; m_sources.clear(); } + m_smtlib2Responses.clear(); + m_unhandledSMTLib2Queries.clear(); m_libraries.clear(); m_evmVersion = EVMVersion(); m_optimize = false; @@ -283,9 +286,10 @@ bool CompilerStack::analyze() if (noErrors) { - SMTChecker smtChecker(m_errorReporter, m_smtQuery); + SMTChecker smtChecker(m_errorReporter, m_smtlib2Responses); for (Source const* source: m_sourceOrder) smtChecker.analyze(*source->ast, source->scanner); + m_unhandledSMTLib2Queries += smtChecker.unhandledQueries(); } } catch(FatalError const&) diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index 8c50266e..2c7add3b 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -153,6 +153,9 @@ public: /// @returns true if a source object by the name already existed and was replaced. bool addSource(std::string const& _name, std::string const& _content, bool _isLibrary = false); + /// Adds a response to an SMTLib2 query (identified by the hash of the query input). + void addSMTLib2Response(h256 const& _hash, std::string const& _response) { m_smtlib2Responses[_hash] = _response; } + /// Parses all source units that were added /// @returns false on error. bool parse(); @@ -188,6 +191,10 @@ public: /// start line, start column, end line, end column std::tuple<int, int, int, int> positionFromSourceLocation(langutil::SourceLocation const& _sourceLocation) const; + /// @returns a list of unhandled queries to the SMT solver (has to be supplied in a second run + /// by calling @a addSMTLib2Response). + std::vector<std::string> const& unhandledSMTLib2Queries() const { return m_unhandledSMTLib2Queries; } + /// @returns a list of the contract names in the sources. std::vector<std::string> contractNames() const; @@ -334,7 +341,6 @@ private: ) const; ReadCallback::Callback m_readFile; - ReadCallback::Callback m_smtQuery; bool m_optimize = false; unsigned m_optimizeRuns = 200; EVMVersion m_evmVersion; @@ -344,6 +350,8 @@ private: /// "context:prefix=target" std::vector<Remapping> m_remappings; std::map<std::string const, Source> m_sources; + std::vector<std::string> m_unhandledSMTLib2Queries; + std::map<h256, std::string> m_smtlib2Responses; std::shared_ptr<GlobalContext> m_globalContext; std::vector<Source const*> m_sourceOrder; /// This is updated during compilation. diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 291a1071..bf33b789 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -319,6 +319,27 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) return formatFatalError("JSONError", "Invalid input source specified."); } + Json::Value const& auxInputs = _input["auxiliaryInput"]; + if (!!auxInputs) + { + Json::Value const& smtlib2Responses = auxInputs["smtlib2responses"]; + if (!!smtlib2Responses) + for (auto const& hashString: smtlib2Responses.getMemberNames()) + { + h256 hash; + try + { + hash = h256(hashString); + } + catch (dev::BadHexCharacter const&) + { + return formatFatalError("JSONError", "Invalid hex encoding of SMTLib2 auxiliary input."); + } + + m_compilerStack.addSMTLib2Response(hash, smtlib2Responses[hashString].asString()); + } + } + Json::Value const& settings = _input.get("settings", Json::Value()); if (settings.isMember("evmVersion")) @@ -518,6 +539,10 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) if (errors.size() > 0) output["errors"] = errors; + if (!m_compilerStack.unhandledSMTLib2Queries().empty()) + for (string const& query: m_compilerStack.unhandledSMTLib2Queries()) + output["auxiliaryInputRequested"]["smtlib2queries"]["0x" + keccak256(query).hex()] = query; + output["sources"] = Json::objectValue; unsigned sourceIndex = 0; for (string const& sourceName: analysisSuccess ? m_compilerStack.sourceNames() : vector<string>()) diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index de5293b4..ffe2be83 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -22,11 +22,11 @@ #include <cctype> #include <vector> -#include <liblangutil/SourceLocation.h> #include <libsolidity/parsing/Parser.h> -#include <liblangutil/Scanner.h> -#include <libsolidity/inlineasm/AsmParser.h> +#include <libyul/AsmParser.h> +#include <liblangutil/SourceLocation.h> #include <liblangutil/ErrorReporter.h> +#include <liblangutil/Scanner.h> using namespace std; using namespace langutil; @@ -1012,8 +1012,8 @@ ASTPointer<InlineAssembly> Parser::parseInlineAssembly(ASTPointer<ASTString> con m_scanner->next(); } - assembly::Parser asmParser(m_errorReporter); - shared_ptr<assembly::Block> block = asmParser.parse(m_scanner, true); + yul::Parser asmParser(m_errorReporter); + shared_ptr<yul::Block> block = asmParser.parse(m_scanner, true); nodeFactory.markEndPosition(); return nodeFactory.createNode<InlineAssembly>(_docString, block); } diff --git a/libyul/ASTDataForward.h b/libyul/ASTDataForward.h deleted file mode 100644 index 8c49e68f..00000000 --- a/libyul/ASTDataForward.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - This file is part of solidity. - - solidity is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - solidity is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with solidity. If not, see <http://www.gnu.org/licenses/>. -*/ -/** - * @date 2017 - * Pull in some identifiers from the solidity::assembly namespace. - */ - -#pragma once - -#include <libsolidity/inlineasm/AsmDataForward.h> - -namespace dev -{ -namespace yul -{ - -using Instruction = solidity::assembly::Instruction; -using Literal = solidity::assembly::Literal; -using Label = solidity::assembly::Label; -using StackAssignment = solidity::assembly::StackAssignment; -using Identifier = solidity::assembly::Identifier; -using Assignment = solidity::assembly::Assignment; -using VariableDeclaration = solidity::assembly::VariableDeclaration; -using FunctionalInstruction = solidity::assembly::FunctionalInstruction; -using FunctionDefinition = solidity::assembly::FunctionDefinition; -using FunctionCall = solidity::assembly::FunctionCall; -using If = solidity::assembly::If; -using Case = solidity::assembly::Case; -using Switch = solidity::assembly::Switch; -using ForLoop = solidity::assembly::ForLoop; -using ExpressionStatement = solidity::assembly::ExpressionStatement; -using Block = solidity::assembly::Block; - -using TypedName = solidity::assembly::TypedName; -class YulString; - -using Expression = boost::variant<FunctionalInstruction, FunctionCall, Identifier, Literal>; -using Statement = boost::variant<ExpressionStatement, Instruction, Label, StackAssignment, Assignment, VariableDeclaration, FunctionDefinition, If, Switch, ForLoop, Block>; - -} -} diff --git a/libsolidity/inlineasm/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index fb96f73c..d3f6de84 100644 --- a/libsolidity/inlineasm/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -18,12 +18,12 @@ * Analyzer part of inline assembly. */ -#include <libsolidity/inlineasm/AsmAnalysis.h> +#include <libyul/AsmAnalysis.h> -#include <libsolidity/inlineasm/AsmData.h> -#include <libsolidity/inlineasm/AsmScopeFiller.h> -#include <libsolidity/inlineasm/AsmScope.h> -#include <libsolidity/inlineasm/AsmAnalysisInfo.h> +#include <libyul/AsmData.h> +#include <libyul/AsmScopeFiller.h> +#include <libyul/AsmScope.h> +#include <libyul/AsmAnalysisInfo.h> #include <liblangutil/ErrorReporter.h> @@ -36,8 +36,9 @@ using namespace std; using namespace dev; using namespace langutil; +using namespace yul; +using namespace dev; using namespace dev::solidity; -using namespace dev::solidity::assembly; namespace { @@ -65,7 +66,7 @@ bool AsmAnalyzer::operator()(Label const& _label) return true; } -bool AsmAnalyzer::operator()(assembly::Instruction const& _instruction) +bool AsmAnalyzer::operator()(yul::Instruction const& _instruction) { checkLooseFeature( _instruction.location, @@ -78,11 +79,11 @@ bool AsmAnalyzer::operator()(assembly::Instruction const& _instruction) return true; } -bool AsmAnalyzer::operator()(assembly::Literal const& _literal) +bool AsmAnalyzer::operator()(Literal const& _literal) { expectValidType(_literal.type.str(), _literal.location); ++m_stackHeight; - if (_literal.kind == assembly::LiteralKind::String && _literal.value.str().size() > 32) + if (_literal.kind == LiteralKind::String && _literal.value.str().size() > 32) { m_errorReporter.typeError( _literal.location, @@ -90,7 +91,7 @@ bool AsmAnalyzer::operator()(assembly::Literal const& _literal) ); return false; } - else if (_literal.kind == assembly::LiteralKind::Number && bigint(_literal.value.str()) > u256(-1)) + else if (_literal.kind == LiteralKind::Number && bigint(_literal.value.str()) > u256(-1)) { m_errorReporter.typeError( _literal.location, @@ -98,7 +99,7 @@ bool AsmAnalyzer::operator()(assembly::Literal const& _literal) ); return false; } - else if (_literal.kind == assembly::LiteralKind::Boolean) + else if (_literal.kind == LiteralKind::Boolean) { solAssert(m_flavour == AsmFlavour::Yul, ""); solAssert(_literal.value == YulString{string("true")} || _literal.value == YulString{string("false")}, ""); @@ -107,7 +108,7 @@ bool AsmAnalyzer::operator()(assembly::Literal const& _literal) return true; } -bool AsmAnalyzer::operator()(assembly::Identifier const& _identifier) +bool AsmAnalyzer::operator()(Identifier const& _identifier) { solAssert(!_identifier.name.empty(), ""); size_t numErrorsBefore = m_errorReporter.errors().size(); @@ -177,7 +178,7 @@ bool AsmAnalyzer::operator()(FunctionalInstruction const& _instr) return success; } -bool AsmAnalyzer::operator()(assembly::ExpressionStatement const& _statement) +bool AsmAnalyzer::operator()(ExpressionStatement const& _statement) { int initialStackHeight = m_stackHeight; bool success = boost::apply_visitor(*this, _statement.expression); @@ -198,7 +199,7 @@ bool AsmAnalyzer::operator()(assembly::ExpressionStatement const& _statement) return success; } -bool AsmAnalyzer::operator()(assembly::StackAssignment const& _assignment) +bool AsmAnalyzer::operator()(StackAssignment const& _assignment) { checkLooseFeature( _assignment.location, @@ -209,7 +210,7 @@ bool AsmAnalyzer::operator()(assembly::StackAssignment const& _assignment) return success; } -bool AsmAnalyzer::operator()(assembly::Assignment const& _assignment) +bool AsmAnalyzer::operator()(Assignment const& _assignment) { solAssert(_assignment.value, ""); int const expectedItems = _assignment.variableNames.size(); @@ -235,7 +236,7 @@ bool AsmAnalyzer::operator()(assembly::Assignment const& _assignment) return success; } -bool AsmAnalyzer::operator()(assembly::VariableDeclaration const& _varDecl) +bool AsmAnalyzer::operator()(VariableDeclaration const& _varDecl) { bool success = true; int const numVariables = _varDecl.variables.size(); @@ -261,7 +262,7 @@ bool AsmAnalyzer::operator()(assembly::VariableDeclaration const& _varDecl) return success; } -bool AsmAnalyzer::operator()(assembly::FunctionDefinition const& _funDef) +bool AsmAnalyzer::operator()(FunctionDefinition const& _funDef) { solAssert(!_funDef.name.empty(), ""); Block const* virtualBlock = m_info.virtualBlocks.at(&_funDef).get(); @@ -283,7 +284,7 @@ bool AsmAnalyzer::operator()(assembly::FunctionDefinition const& _funDef) return success; } -bool AsmAnalyzer::operator()(assembly::FunctionCall const& _funCall) +bool AsmAnalyzer::operator()(FunctionCall const& _funCall) { solAssert(!_funCall.functionName.name.empty(), ""); bool success = true; @@ -397,7 +398,7 @@ bool AsmAnalyzer::operator()(Switch const& _switch) return success; } -bool AsmAnalyzer::operator()(assembly::ForLoop const& _for) +bool AsmAnalyzer::operator()(ForLoop const& _for) { solAssert(_for.condition, ""); @@ -486,7 +487,7 @@ bool AsmAnalyzer::expectDeposit(int _deposit, int _oldHeight, SourceLocation con return true; } -bool AsmAnalyzer::checkAssignment(assembly::Identifier const& _variable, size_t _valueSize) +bool AsmAnalyzer::checkAssignment(Identifier const& _variable, size_t _valueSize) { solAssert(!_variable.name.empty(), ""); bool success = true; diff --git a/libsolidity/inlineasm/AsmAnalysis.h b/libyul/AsmAnalysis.h index 194f736e..34e32eb0 100644 --- a/libsolidity/inlineasm/AsmAnalysis.h +++ b/libyul/AsmAnalysis.h @@ -23,11 +23,11 @@ #include <liblangutil/Exceptions.h> #include <liblangutil/EVMVersion.h> -#include <libsolidity/inlineasm/AsmScope.h> +#include <libyul/AsmScope.h> #include <libyul/backends/evm/AbstractAssembly.h> -#include <libsolidity/inlineasm/AsmDataForward.h> +#include <libyul/AsmDataForward.h> #include <boost/variant.hpp> #include <boost/optional.hpp> @@ -41,11 +41,7 @@ class ErrorReporter; struct SourceLocation; } -namespace dev -{ -namespace solidity -{ -namespace assembly +namespace yul { struct AsmAnalysisInfo; @@ -61,10 +57,10 @@ public: explicit AsmAnalyzer( AsmAnalysisInfo& _analysisInfo, langutil::ErrorReporter& _errorReporter, - EVMVersion _evmVersion, + dev::solidity::EVMVersion _evmVersion, boost::optional<langutil::Error::Type> _errorTypeForLoose, AsmFlavour _flavour = AsmFlavour::Loose, - yul::ExternalIdentifierAccess::Resolver const& _resolver = yul::ExternalIdentifierAccess::Resolver() + ExternalIdentifierAccess::Resolver const& _resolver = ExternalIdentifierAccess::Resolver() ): m_resolver(_resolver), m_info(_analysisInfo), @@ -74,23 +70,23 @@ public: m_errorTypeForLoose(_errorTypeForLoose) {} - bool analyze(assembly::Block const& _block); - - bool operator()(assembly::Instruction const&); - bool operator()(assembly::Literal const& _literal); - bool operator()(assembly::Identifier const&); - bool operator()(assembly::FunctionalInstruction const& _functionalInstruction); - bool operator()(assembly::Label const& _label); - bool operator()(assembly::ExpressionStatement const&); - bool operator()(assembly::StackAssignment const&); - bool operator()(assembly::Assignment const& _assignment); - bool operator()(assembly::VariableDeclaration const& _variableDeclaration); - bool operator()(assembly::FunctionDefinition const& _functionDefinition); - bool operator()(assembly::FunctionCall const& _functionCall); - bool operator()(assembly::If const& _if); - bool operator()(assembly::Switch const& _switch); - bool operator()(assembly::ForLoop const& _forLoop); - bool operator()(assembly::Block const& _block); + bool analyze(Block const& _block); + + bool operator()(Instruction const&); + bool operator()(Literal const& _literal); + bool operator()(Identifier const&); + bool operator()(FunctionalInstruction const& _functionalInstruction); + bool operator()(Label const& _label); + bool operator()(ExpressionStatement const&); + bool operator()(StackAssignment const&); + bool operator()(Assignment const& _assignment); + bool operator()(VariableDeclaration const& _variableDeclaration); + bool operator()(FunctionDefinition const& _functionDefinition); + bool operator()(FunctionCall const& _functionCall); + bool operator()(If const& _if); + bool operator()(Switch const& _switch); + bool operator()(ForLoop const& _forLoop); + bool operator()(Block const& _block); private: /// Visits the statement and expects it to deposit one item onto the stack. @@ -99,11 +95,11 @@ private: /// Verifies that a variable to be assigned to exists and has the same size /// as the value, @a _valueSize, unless that is equal to -1. - bool checkAssignment(assembly::Identifier const& _assignment, size_t _valueSize = size_t(-1)); + bool checkAssignment(Identifier const& _assignment, size_t _valueSize = size_t(-1)); - Scope& scope(assembly::Block const* _block); + Scope& scope(Block const* _block); void expectValidType(std::string const& type, langutil::SourceLocation const& _location); - void warnOnInstructions(solidity::Instruction _instr, langutil::SourceLocation const& _location); + void warnOnInstructions(dev::solidity::Instruction _instr, langutil::SourceLocation const& _location); /// Depending on @a m_flavour and @a m_errorTypeForLoose, throws an internal compiler /// exception (if the flavour is not Loose), reports an error/warning @@ -118,11 +114,9 @@ private: std::set<Scope::Variable const*> m_activeVariables; AsmAnalysisInfo& m_info; langutil::ErrorReporter& m_errorReporter; - EVMVersion m_evmVersion; + dev::solidity::EVMVersion m_evmVersion; AsmFlavour m_flavour = AsmFlavour::Loose; boost::optional<langutil::Error::Type> m_errorTypeForLoose; }; } -} -} diff --git a/libsolidity/inlineasm/AsmAnalysisInfo.cpp b/libyul/AsmAnalysisInfo.cpp index 22318b12..450c0f8f 100644 --- a/libsolidity/inlineasm/AsmAnalysisInfo.cpp +++ b/libyul/AsmAnalysisInfo.cpp @@ -18,9 +18,9 @@ * Information generated during analyzer part of inline assembly. */ -#include <libsolidity/inlineasm/AsmAnalysisInfo.h> +#include <libyul/AsmAnalysisInfo.h> -#include <libsolidity/inlineasm/AsmScope.h> +#include <libyul/AsmScope.h> #include <ostream> diff --git a/libsolidity/inlineasm/AsmAnalysisInfo.h b/libyul/AsmAnalysisInfo.h index bd3b28c4..08a35ade 100644 --- a/libsolidity/inlineasm/AsmAnalysisInfo.h +++ b/libyul/AsmAnalysisInfo.h @@ -20,7 +20,7 @@ #pragma once -#include <libsolidity/inlineasm/AsmDataForward.h> +#include <libyul/AsmDataForward.h> #include <boost/variant.hpp> @@ -28,11 +28,7 @@ #include <memory> #include <vector> -namespace dev -{ -namespace solidity -{ -namespace assembly +namespace yul { struct Scope; @@ -40,13 +36,11 @@ struct Scope; struct AsmAnalysisInfo { using StackHeightInfo = std::map<void const*, int>; - using Scopes = std::map<assembly::Block const*, std::shared_ptr<Scope>>; + using Scopes = std::map<Block const*, std::shared_ptr<Scope>>; Scopes scopes; StackHeightInfo stackHeightInfo; /// Virtual blocks which will be used for scopes for function arguments and return values. - std::map<FunctionDefinition const*, std::shared_ptr<assembly::Block const>> virtualBlocks; + std::map<FunctionDefinition const*, std::shared_ptr<Block const>> virtualBlocks; }; } -} -} diff --git a/libsolidity/inlineasm/AsmCodeGen.cpp b/libyul/AsmCodeGen.cpp index 2800cc7b..23bf395d 100644 --- a/libsolidity/inlineasm/AsmCodeGen.cpp +++ b/libyul/AsmCodeGen.cpp @@ -20,20 +20,21 @@ * Code-generating part of inline assembly. */ -#include <libsolidity/inlineasm/AsmCodeGen.h> +#include <libyul/AsmCodeGen.h> -#include <libsolidity/inlineasm/AsmParser.h> -#include <libsolidity/inlineasm/AsmData.h> -#include <libsolidity/inlineasm/AsmScope.h> -#include <libsolidity/inlineasm/AsmAnalysis.h> -#include <libsolidity/inlineasm/AsmAnalysisInfo.h> +#include <libyul/AsmParser.h> +#include <libyul/AsmData.h> +#include <libyul/AsmScope.h> +#include <libyul/AsmAnalysis.h> +#include <libyul/AsmAnalysisInfo.h> + +#include <libyul/backends/evm/AbstractAssembly.h> +#include <libyul/backends/evm/EVMCodeTransform.h> #include <libevmasm/Assembly.h> -#include <liblangutil/SourceLocation.h> #include <libevmasm/Instruction.h> -#include <libyul/backends/evm/AbstractAssembly.h> -#include <libyul/backends/evm/EVMCodeTransform.h> +#include <liblangutil/SourceLocation.h> #include <libdevcore/CommonIO.h> @@ -47,10 +48,10 @@ using namespace std; using namespace dev; using namespace langutil; +using namespace yul; using namespace dev::solidity; -using namespace dev::solidity::assembly; -class EthAssemblyAdapter: public yul::AbstractAssembly +class EthAssemblyAdapter: public AbstractAssembly { public: explicit EthAssemblyAdapter(eth::Assembly& _assembly): @@ -142,16 +143,16 @@ private: eth::Assembly& m_assembly; }; -void assembly::CodeGenerator::assemble( +void CodeGenerator::assemble( Block const& _parsedData, AsmAnalysisInfo& _analysisInfo, eth::Assembly& _assembly, - yul::ExternalIdentifierAccess const& _identifierAccess, + ExternalIdentifierAccess const& _identifierAccess, bool _useNamedLabelsForFunctions ) { EthAssemblyAdapter assemblyAdapter(_assembly); - yul::CodeTransform( + CodeTransform( assemblyAdapter, _analysisInfo, false, diff --git a/libsolidity/inlineasm/AsmCodeGen.h b/libyul/AsmCodeGen.h index bbc31397..fd5ac0a1 100644 --- a/libsolidity/inlineasm/AsmCodeGen.h +++ b/libyul/AsmCodeGen.h @@ -22,7 +22,7 @@ #pragma once -#include <libsolidity/inlineasm/AsmAnalysis.h> +#include <libyul/AsmAnalysis.h> #include <functional> @@ -32,9 +32,9 @@ namespace eth { class Assembly; } -namespace solidity -{ -namespace assembly +} + +namespace yul { struct Block; @@ -45,12 +45,10 @@ public: static void assemble( Block const& _parsedData, AsmAnalysisInfo& _analysisInfo, - eth::Assembly& _assembly, + dev::eth::Assembly& _assembly, yul::ExternalIdentifierAccess const& _identifierAccess = yul::ExternalIdentifierAccess(), bool _useNamedLabelsForFunctions = false ); }; } -} -} diff --git a/libsolidity/inlineasm/AsmData.h b/libyul/AsmData.h index 23a9db75..86c373a4 100644 --- a/libsolidity/inlineasm/AsmData.h +++ b/libyul/AsmData.h @@ -22,34 +22,28 @@ #pragma once -#include <libsolidity/inlineasm/AsmDataForward.h> +#include <libyul/AsmDataForward.h> +#include <libyul/YulString.h> #include <libevmasm/Instruction.h> #include <liblangutil/SourceLocation.h> -#include <libyul/YulString.h> - #include <boost/variant.hpp> #include <boost/noncopyable.hpp> #include <map> #include <memory> -namespace dev -{ -namespace solidity -{ -namespace assembly +namespace yul { -using YulString = dev::yul::YulString; using Type = YulString; struct TypedName { langutil::SourceLocation location; YulString name; Type type; }; using TypedNameList = std::vector<TypedName>; /// Direct EVM instruction (except PUSHi and JUMPDEST) -struct Instruction { langutil::SourceLocation location; solidity::Instruction instruction; }; +struct Instruction { langutil::SourceLocation location; dev::solidity::Instruction instruction; }; /// Literal number or string (up to 32 bytes) enum class LiteralKind { Number, Boolean, String }; struct Literal { langutil::SourceLocation location; LiteralKind kind; YulString value; Type type; }; @@ -67,7 +61,7 @@ struct StackAssignment { langutil::SourceLocation location; Identifier variableN /// the same amount of items as the number of variables. struct Assignment { langutil::SourceLocation location; std::vector<Identifier> variableNames; std::shared_ptr<Expression> value; }; /// Functional instruction, e.g. "mul(mload(20:u256), add(2:u256, x))" -struct FunctionalInstruction { langutil::SourceLocation location; solidity::Instruction instruction; std::vector<Expression> arguments; }; +struct FunctionalInstruction { langutil::SourceLocation location; dev::solidity::Instruction instruction; std::vector<Expression> arguments; }; struct FunctionCall { langutil::SourceLocation location; Identifier functionName; std::vector<Expression> arguments; }; /// Statement that contains only a single expression struct ExpressionStatement { langutil::SourceLocation location; Expression expression; }; @@ -100,5 +94,3 @@ template <class T> inline langutil::SourceLocation locationOf(T const& _node) } } -} -} diff --git a/libsolidity/inlineasm/AsmDataForward.h b/libyul/AsmDataForward.h index 69cf8f1d..046c8248 100644 --- a/libsolidity/inlineasm/AsmDataForward.h +++ b/libyul/AsmDataForward.h @@ -24,11 +24,7 @@ #include <boost/variant.hpp> -namespace dev -{ -namespace solidity -{ -namespace assembly +namespace yul { struct Instruction; @@ -61,5 +57,3 @@ enum class AsmFlavour }; } -} -} diff --git a/libsolidity/inlineasm/AsmParser.cpp b/libyul/AsmParser.cpp index b11f70e0..2ce94f85 100644 --- a/libsolidity/inlineasm/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -20,7 +20,7 @@ * Solidity inline assembly parser. */ -#include <libsolidity/inlineasm/AsmParser.h> +#include <libyul/AsmParser.h> #include <liblangutil/Scanner.h> #include <liblangutil/ErrorReporter.h> @@ -32,10 +32,10 @@ using namespace std; using namespace dev; using namespace langutil; +using namespace yul; using namespace dev::solidity; -using namespace dev::solidity::assembly; -shared_ptr<assembly::Block> Parser::parse(std::shared_ptr<Scanner> const& _scanner, bool _reuseScanner) +shared_ptr<Block> Parser::parse(std::shared_ptr<Scanner> const& _scanner, bool _reuseScanner) { m_recursionDepth = 0; try @@ -54,10 +54,10 @@ shared_ptr<assembly::Block> Parser::parse(std::shared_ptr<Scanner> const& _scann return nullptr; } -assembly::Block Parser::parseBlock() +Block Parser::parseBlock() { RecursionGuard recursionGuard(*this); - assembly::Block block = createWithLocation<Block>(); + Block block = createWithLocation<Block>(); expectToken(Token::LBrace); while (currentToken() != Token::RBrace) block.statements.emplace_back(parseStatement()); @@ -66,7 +66,7 @@ assembly::Block Parser::parseBlock() return block; } -assembly::Statement Parser::parseStatement() +Statement Parser::parseStatement() { RecursionGuard recursionGuard(*this); switch (currentToken()) @@ -79,7 +79,7 @@ assembly::Statement Parser::parseStatement() return parseBlock(); case Token::If: { - assembly::If _if = createWithLocation<assembly::If>(); + If _if = createWithLocation<If>(); m_scanner->next(); _if.condition = make_shared<Expression>(parseExpression()); _if.body = parseBlock(); @@ -87,7 +87,7 @@ assembly::Statement Parser::parseStatement() } case Token::Switch: { - assembly::Switch _switch = createWithLocation<assembly::Switch>(); + Switch _switch = createWithLocation<Switch>(); m_scanner->next(); _switch.expression = make_shared<Expression>(parseExpression()); while (m_scanner->currentToken() == Token::Case) @@ -109,7 +109,7 @@ assembly::Statement Parser::parseStatement() { if (m_flavour != AsmFlavour::Loose) break; - assembly::StackAssignment assignment = createWithLocation<assembly::StackAssignment>(); + StackAssignment assignment = createWithLocation<StackAssignment>(); advance(); expectToken(Token::Colon); assignment.variableName.location = location(); @@ -139,9 +139,9 @@ assembly::Statement Parser::parseStatement() { // if a comma follows, a multiple assignment is assumed - if (elementary.type() != typeid(assembly::Identifier)) + if (elementary.type() != typeid(Identifier)) fatalParserError("Label name / variable name must precede \",\" (multiple assignment)."); - assembly::Identifier const& identifier = boost::get<assembly::Identifier>(elementary); + Identifier const& identifier = boost::get<Identifier>(elementary); Assignment assignment = createWithLocation<Assignment>(identifier.location); assignment.variableNames.emplace_back(identifier); @@ -150,9 +150,9 @@ assembly::Statement Parser::parseStatement() { expectToken(Token::Comma); elementary = parseElementaryOperation(); - if (elementary.type() != typeid(assembly::Identifier)) + if (elementary.type() != typeid(Identifier)) fatalParserError("Variable name expected in multiple assignment."); - assignment.variableNames.emplace_back(boost::get<assembly::Identifier>(elementary)); + assignment.variableNames.emplace_back(boost::get<Identifier>(elementary)); } while (currentToken() == Token::Comma); @@ -165,15 +165,15 @@ assembly::Statement Parser::parseStatement() } case Token::Colon: { - if (elementary.type() != typeid(assembly::Identifier)) + if (elementary.type() != typeid(Identifier)) fatalParserError("Label name / variable name must precede \":\"."); - assembly::Identifier const& identifier = boost::get<assembly::Identifier>(elementary); + Identifier const& identifier = boost::get<Identifier>(elementary); advance(); // identifier:=: should be parsed as identifier: =: (i.e. a label), // while identifier:= (being followed by a non-colon) as identifier := (assignment). if (currentToken() == Token::Assign && peekNextToken() != Token::Colon) { - assembly::Assignment assignment = createWithLocation<assembly::Assignment>(identifier.location); + Assignment assignment = createWithLocation<Assignment>(identifier.location); if (m_flavour != AsmFlavour::Yul && instructions().count(identifier.name.str())) fatalParserError("Cannot use instruction names for identifier names."); advance(); @@ -197,36 +197,36 @@ assembly::Statement Parser::parseStatement() fatalParserError("Call or assignment expected."); break; } - if (elementary.type() == typeid(assembly::Identifier)) + if (elementary.type() == typeid(Identifier)) { - Expression expr = boost::get<assembly::Identifier>(elementary); + Expression expr = boost::get<Identifier>(elementary); return ExpressionStatement{locationOf(expr), expr}; } - else if (elementary.type() == typeid(assembly::Literal)) + else if (elementary.type() == typeid(Literal)) { - Expression expr = boost::get<assembly::Literal>(elementary); + Expression expr = boost::get<Literal>(elementary); return ExpressionStatement{locationOf(expr), expr}; } else { - solAssert(elementary.type() == typeid(assembly::Instruction), "Invalid elementary operation."); - return boost::get<assembly::Instruction>(elementary); + solAssert(elementary.type() == typeid(Instruction), "Invalid elementary operation."); + return boost::get<Instruction>(elementary); } } -assembly::Case Parser::parseCase() +Case Parser::parseCase() { RecursionGuard recursionGuard(*this); - assembly::Case _case = createWithLocation<assembly::Case>(); + Case _case = createWithLocation<Case>(); if (m_scanner->currentToken() == Token::Default) m_scanner->next(); else if (m_scanner->currentToken() == Token::Case) { m_scanner->next(); ElementaryOperation literal = parseElementaryOperation(); - if (literal.type() != typeid(assembly::Literal)) + if (literal.type() != typeid(Literal)) fatalParserError("Literal expected."); - _case.value = make_shared<Literal>(boost::get<assembly::Literal>(std::move(literal))); + _case.value = make_shared<Literal>(boost::get<Literal>(std::move(literal))); } else fatalParserError("Case or default case expected."); @@ -235,7 +235,7 @@ assembly::Case Parser::parseCase() return _case; } -assembly::ForLoop Parser::parseForLoop() +ForLoop Parser::parseForLoop() { RecursionGuard recursionGuard(*this); ForLoop forLoop = createWithLocation<ForLoop>(); @@ -248,7 +248,7 @@ assembly::ForLoop Parser::parseForLoop() return forLoop; } -assembly::Expression Parser::parseExpression() +Expression Parser::parseExpression() { RecursionGuard recursionGuard(*this); // In strict mode, this might parse a plain Instruction, but @@ -293,12 +293,12 @@ assembly::Expression Parser::parseExpression() Instruction& instr = boost::get<Instruction>(operation); return FunctionalInstruction{std::move(instr.location), instr.instruction, {}}; } - else if (operation.type() == typeid(assembly::Identifier)) - return boost::get<assembly::Identifier>(operation); + else if (operation.type() == typeid(Identifier)) + return boost::get<Identifier>(operation); else { - solAssert(operation.type() == typeid(assembly::Literal), ""); - return boost::get<assembly::Literal>(operation); + solAssert(operation.type() == typeid(Literal), ""); + return boost::get<Literal>(operation); } } @@ -420,7 +420,7 @@ Parser::ElementaryOperation Parser::parseElementaryOperation() return ret; } -assembly::VariableDeclaration Parser::parseVariableDeclaration() +VariableDeclaration Parser::parseVariableDeclaration() { RecursionGuard recursionGuard(*this); VariableDeclaration varDecl = createWithLocation<VariableDeclaration>(); @@ -445,7 +445,7 @@ assembly::VariableDeclaration Parser::parseVariableDeclaration() return varDecl; } -assembly::FunctionDefinition Parser::parseFunctionDefinition() +FunctionDefinition Parser::parseFunctionDefinition() { RecursionGuard recursionGuard(*this); FunctionDefinition funDef = createWithLocation<FunctionDefinition>(); @@ -477,7 +477,7 @@ assembly::FunctionDefinition Parser::parseFunctionDefinition() return funDef; } -assembly::Expression Parser::parseCall(Parser::ElementaryOperation&& _initialOp) +Expression Parser::parseCall(Parser::ElementaryOperation&& _initialOp) { RecursionGuard recursionGuard(*this); if (_initialOp.type() == typeid(Instruction)) diff --git a/libsolidity/inlineasm/AsmParser.h b/libyul/AsmParser.h index 9e13799a..cea3b667 100644 --- a/libsolidity/inlineasm/AsmParser.h +++ b/libyul/AsmParser.h @@ -24,16 +24,12 @@ #include <memory> #include <vector> -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> #include <liblangutil/SourceLocation.h> #include <liblangutil/Scanner.h> #include <liblangutil/ParserBase.h> -namespace dev -{ -namespace solidity -{ -namespace assembly +namespace yul { class Parser: public langutil::ParserBase @@ -48,7 +44,7 @@ public: std::shared_ptr<Block> parse(std::shared_ptr<langutil::Scanner> const& _scanner, bool _reuseScanner); protected: - using ElementaryOperation = boost::variant<assembly::Instruction, assembly::Literal, assembly::Identifier>; + using ElementaryOperation = boost::variant<Instruction, Literal, Identifier>; /// Creates an inline assembly node with the given source location. template <class T> T createWithLocation(langutil::SourceLocation const& _loc = {}) const @@ -71,7 +67,7 @@ protected: Case parseCase(); ForLoop parseForLoop(); /// Parses a functional expression that has to push exactly one stack element - assembly::Expression parseExpression(); + Expression parseExpression(); static std::map<std::string, dev::solidity::Instruction> const& instructions(); static std::map<dev::solidity::Instruction, std::string> const& instructionNames(); /// Parses an elementary operation, i.e. a literal, identifier or instruction. @@ -80,7 +76,7 @@ protected: ElementaryOperation parseElementaryOperation(); VariableDeclaration parseVariableDeclaration(); FunctionDefinition parseFunctionDefinition(); - assembly::Expression parseCall(ElementaryOperation&& _initialOp); + Expression parseCall(ElementaryOperation&& _initialOp); TypedName parseTypedName(); std::string expectAsmIdentifier(); @@ -91,5 +87,3 @@ private: }; } -} -} diff --git a/libsolidity/inlineasm/AsmPrinter.cpp b/libyul/AsmPrinter.cpp index 7151fcfa..eaaba9f3 100644 --- a/libsolidity/inlineasm/AsmPrinter.cpp +++ b/libyul/AsmPrinter.cpp @@ -20,8 +20,8 @@ * Converts a parsed assembly into its textual form. */ -#include <libsolidity/inlineasm/AsmPrinter.h> -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmPrinter.h> +#include <libyul/AsmData.h> #include <liblangutil/Exceptions.h> #include <libdevcore/CommonData.h> @@ -35,19 +35,19 @@ using namespace std; using namespace dev; +using namespace yul; using namespace dev::solidity; -using namespace dev::solidity::assembly; //@TODO source locations -string AsmPrinter::operator()(assembly::Instruction const& _instruction) +string AsmPrinter::operator()(yul::Instruction const& _instruction) { solAssert(!m_yul, ""); solAssert(isValidInstruction(_instruction.instruction), "Invalid instruction"); return boost::to_lower_copy(instructionInfo(_instruction.instruction).name); } -string AsmPrinter::operator()(assembly::Literal const& _literal) +string AsmPrinter::operator()(Literal const& _literal) { switch (_literal.kind) { @@ -90,13 +90,13 @@ string AsmPrinter::operator()(assembly::Literal const& _literal) return "\"" + out + "\"" + appendTypeName(_literal.type); } -string AsmPrinter::operator()(assembly::Identifier const& _identifier) +string AsmPrinter::operator()(Identifier const& _identifier) { solAssert(!_identifier.name.empty(), "Invalid identifier."); return _identifier.name.str(); } -string AsmPrinter::operator()(assembly::FunctionalInstruction const& _functionalInstruction) +string AsmPrinter::operator()(FunctionalInstruction const& _functionalInstruction) { solAssert(!m_yul, ""); solAssert(isValidInstruction(_functionalInstruction.instruction), "Invalid instruction"); @@ -114,21 +114,21 @@ string AsmPrinter::operator()(ExpressionStatement const& _statement) return boost::apply_visitor(*this, _statement.expression); } -string AsmPrinter::operator()(assembly::Label const& _label) +string AsmPrinter::operator()(Label const& _label) { solAssert(!m_yul, ""); solAssert(!_label.name.empty(), "Invalid label."); return _label.name.str() + ":"; } -string AsmPrinter::operator()(assembly::StackAssignment const& _assignment) +string AsmPrinter::operator()(StackAssignment const& _assignment) { solAssert(!m_yul, ""); solAssert(!_assignment.variableName.name.empty(), "Invalid variable name."); return "=: " + (*this)(_assignment.variableName); } -string AsmPrinter::operator()(assembly::Assignment const& _assignment) +string AsmPrinter::operator()(Assignment const& _assignment) { solAssert(_assignment.variableNames.size() >= 1, ""); string variables = (*this)(_assignment.variableNames.front()); @@ -137,7 +137,7 @@ string AsmPrinter::operator()(assembly::Assignment const& _assignment) return variables + " := " + boost::apply_visitor(*this, *_assignment.value); } -string AsmPrinter::operator()(assembly::VariableDeclaration const& _variableDeclaration) +string AsmPrinter::operator()(VariableDeclaration const& _variableDeclaration) { string out = "let "; out += boost::algorithm::join( @@ -154,7 +154,7 @@ string AsmPrinter::operator()(assembly::VariableDeclaration const& _variableDecl return out; } -string AsmPrinter::operator()(assembly::FunctionDefinition const& _functionDefinition) +string AsmPrinter::operator()(FunctionDefinition const& _functionDefinition) { solAssert(!_functionDefinition.name.empty(), "Invalid function name."); string out = "function " + _functionDefinition.name.str() + "("; @@ -179,7 +179,7 @@ string AsmPrinter::operator()(assembly::FunctionDefinition const& _functionDefin return out + "\n" + (*this)(_functionDefinition.body); } -string AsmPrinter::operator()(assembly::FunctionCall const& _functionCall) +string AsmPrinter::operator()(FunctionCall const& _functionCall) { return (*this)(_functionCall.functionName) + "(" + @@ -210,7 +210,7 @@ string AsmPrinter::operator()(Switch const& _switch) return out; } -string AsmPrinter::operator()(assembly::ForLoop const& _forLoop) +string AsmPrinter::operator()(ForLoop const& _forLoop) { solAssert(_forLoop.condition, "Invalid for loop condition."); string out = "for "; diff --git a/libyul/AsmPrinter.h b/libyul/AsmPrinter.h new file mode 100644 index 00000000..61dfc18c --- /dev/null +++ b/libyul/AsmPrinter.h @@ -0,0 +1,62 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see <http://www.gnu.org/licenses/>. +*/ +/** + * @author Christian <c@ethdev.com> + * @date 2017 + * Converts a parsed assembly into its textual form. + */ + +#pragma once + +#include <libyul/AsmDataForward.h> + +#include <libyul/YulString.h> + +#include <boost/variant.hpp> + +namespace yul +{ + +class AsmPrinter: public boost::static_visitor<std::string> +{ +public: + explicit AsmPrinter(bool _yul = false): m_yul(_yul) {} + + std::string operator()(Instruction const& _instruction); + std::string operator()(Literal const& _literal); + std::string operator()(Identifier const& _identifier); + std::string operator()(FunctionalInstruction const& _functionalInstruction); + std::string operator()(ExpressionStatement const& _expr); + std::string operator()(Label const& _label); + std::string operator()(StackAssignment const& _assignment); + std::string operator()(Assignment const& _assignment); + std::string operator()(VariableDeclaration const& _variableDeclaration); + std::string operator()(FunctionDefinition const& _functionDefinition); + std::string operator()(FunctionCall const& _functionCall); + std::string operator()(If const& _if); + std::string operator()(Switch const& _switch); + std::string operator()(ForLoop const& _forLoop); + std::string operator()(Block const& _block); + +private: + std::string formatTypedName(TypedName _variable) const; + std::string appendTypeName(YulString _type) const; + + bool m_yul = false; +}; + +} diff --git a/libsolidity/inlineasm/AsmScope.cpp b/libyul/AsmScope.cpp index 10893b96..b71f2367 100644 --- a/libsolidity/inlineasm/AsmScope.cpp +++ b/libyul/AsmScope.cpp @@ -18,13 +18,13 @@ * Scopes for identifiers. */ -#include <libsolidity/inlineasm/AsmScope.h> +#include <libyul/AsmScope.h> using namespace std; using namespace dev; -using namespace dev::solidity::assembly; +using namespace yul; -bool Scope::registerLabel(yul::YulString _name) +bool Scope::registerLabel(YulString _name) { if (exists(_name)) return false; @@ -32,7 +32,7 @@ bool Scope::registerLabel(yul::YulString _name) return true; } -bool Scope::registerVariable(yul::YulString _name, YulType const& _type) +bool Scope::registerVariable(YulString _name, YulType const& _type) { if (exists(_name)) return false; @@ -42,7 +42,7 @@ bool Scope::registerVariable(yul::YulString _name, YulType const& _type) return true; } -bool Scope::registerFunction(yul::YulString _name, std::vector<YulType> const& _arguments, std::vector<YulType> const& _returns) +bool Scope::registerFunction(YulString _name, std::vector<YulType> const& _arguments, std::vector<YulType> const& _returns) { if (exists(_name)) return false; @@ -50,7 +50,7 @@ bool Scope::registerFunction(yul::YulString _name, std::vector<YulType> const& _ return true; } -Scope::Identifier* Scope::lookup(yul::YulString _name) +Scope::Identifier* Scope::lookup(YulString _name) { bool crossedFunctionBoundary = false; for (Scope* s = this; s; s = s->superScope) @@ -70,7 +70,7 @@ Scope::Identifier* Scope::lookup(yul::YulString _name) return nullptr; } -bool Scope::exists(yul::YulString _name) const +bool Scope::exists(YulString _name) const { if (identifiers.count(_name)) return true; diff --git a/libsolidity/inlineasm/AsmScope.h b/libyul/AsmScope.h index 12c05716..2a8ef49e 100644 --- a/libsolidity/inlineasm/AsmScope.h +++ b/libyul/AsmScope.h @@ -32,16 +32,12 @@ #include <functional> #include <memory> -namespace dev -{ -namespace solidity -{ -namespace assembly +namespace yul { struct Scope { - using YulType = yul::YulString; + using YulType = YulString; using LabelID = size_t; struct Variable { YulType type; }; @@ -53,13 +49,13 @@ struct Scope }; using Identifier = boost::variant<Variable, Label, Function>; - using Visitor = GenericVisitor<Variable const, Label const, Function const>; - using NonconstVisitor = GenericVisitor<Variable, Label, Function>; + using Visitor = dev::GenericVisitor<Variable const, Label const, Function const>; + using NonconstVisitor = dev::GenericVisitor<Variable, Label, Function>; - bool registerVariable(yul::YulString _name, YulType const& _type); - bool registerLabel(yul::YulString _name); + bool registerVariable(YulString _name, YulType const& _type); + bool registerLabel(YulString _name); bool registerFunction( - yul::YulString _name, + YulString _name, std::vector<YulType> const& _arguments, std::vector<YulType> const& _returns ); @@ -69,12 +65,12 @@ struct Scope /// will any lookups across assembly boundaries. /// The pointer will be invalidated if the scope is modified. /// @param _crossedFunction if true, we already crossed a function boundary during recursive lookup - Identifier* lookup(yul::YulString _name); + Identifier* lookup(YulString _name); /// Looks up the identifier in this and super scopes (will not find variables across function /// boundaries and generally stops at assembly boundaries) and calls the visitor, returns /// false if not found. template <class V> - bool lookup(yul::YulString _name, V const& _visitor) + bool lookup(YulString _name, V const& _visitor) { if (Identifier* id = lookup(_name)) { @@ -86,7 +82,7 @@ struct Scope } /// @returns true if the name exists in this scope or in super scopes (also searches /// across function and assembly boundaries). - bool exists(yul::YulString _name) const; + bool exists(YulString _name) const; /// @returns the number of variables directly registered inside the scope. size_t numberOfVariables() const; @@ -97,9 +93,7 @@ struct Scope /// If true, variables from the super scope are not visible here (other identifiers are), /// but they are still taken into account to prevent shadowing. bool functionScope = false; - std::map<yul::YulString, Identifier> identifiers; + std::map<YulString, Identifier> identifiers; }; } -} -} diff --git a/libsolidity/inlineasm/AsmScopeFiller.cpp b/libyul/AsmScopeFiller.cpp index 09934bd8..ee797d6a 100644 --- a/libsolidity/inlineasm/AsmScopeFiller.cpp +++ b/libyul/AsmScopeFiller.cpp @@ -18,11 +18,11 @@ * Module responsible for registering identifiers inside their scopes. */ -#include <libsolidity/inlineasm/AsmScopeFiller.h> +#include <libyul/AsmScopeFiller.h> -#include <libsolidity/inlineasm/AsmData.h> -#include <libsolidity/inlineasm/AsmScope.h> -#include <libsolidity/inlineasm/AsmAnalysisInfo.h> +#include <libyul/AsmData.h> +#include <libyul/AsmScope.h> +#include <libyul/AsmAnalysisInfo.h> #include <liblangutil/ErrorReporter.h> #include <liblangutil/Exceptions.h> @@ -37,8 +37,8 @@ using namespace std; using namespace dev; using namespace langutil; +using namespace yul; using namespace dev::solidity; -using namespace dev::solidity::assembly; ScopeFiller::ScopeFiller(AsmAnalysisInfo& _info, ErrorReporter& _errorReporter): m_info(_info), m_errorReporter(_errorReporter) @@ -65,7 +65,7 @@ bool ScopeFiller::operator()(Label const& _item) return true; } -bool ScopeFiller::operator()(assembly::VariableDeclaration const& _varDecl) +bool ScopeFiller::operator()(VariableDeclaration const& _varDecl) { for (auto const& variable: _varDecl.variables) if (!registerVariable(variable, _varDecl.location, *m_currentScope)) @@ -73,7 +73,7 @@ bool ScopeFiller::operator()(assembly::VariableDeclaration const& _varDecl) return true; } -bool ScopeFiller::operator()(assembly::FunctionDefinition const& _funDef) +bool ScopeFiller::operator()(FunctionDefinition const& _funDef) { bool success = true; vector<Scope::YulType> arguments; diff --git a/libsolidity/inlineasm/AsmScopeFiller.h b/libyul/AsmScopeFiller.h index 7454fd6c..e8fb88d5 100644 --- a/libsolidity/inlineasm/AsmScopeFiller.h +++ b/libyul/AsmScopeFiller.h @@ -20,7 +20,7 @@ #pragma once -#include <libsolidity/inlineasm/AsmDataForward.h> +#include <libyul/AsmDataForward.h> #include <boost/variant.hpp> @@ -33,11 +33,7 @@ class ErrorReporter; struct SourceLocation; } -namespace dev -{ -namespace solidity -{ -namespace assembly +namespace yul { struct TypedName; @@ -53,21 +49,21 @@ class ScopeFiller: public boost::static_visitor<bool> public: ScopeFiller(AsmAnalysisInfo& _info, langutil::ErrorReporter& _errorReporter); - bool operator()(assembly::Instruction const&) { return true; } - bool operator()(assembly::Literal const&) { return true; } - bool operator()(assembly::Identifier const&) { return true; } - bool operator()(assembly::FunctionalInstruction const&) { return true; } - bool operator()(assembly::ExpressionStatement const& _expr); - bool operator()(assembly::Label const& _label); - bool operator()(assembly::StackAssignment const&) { return true; } - bool operator()(assembly::Assignment const&) { return true; } - bool operator()(assembly::VariableDeclaration const& _variableDeclaration); - bool operator()(assembly::FunctionDefinition const& _functionDefinition); - bool operator()(assembly::FunctionCall const&) { return true; } - bool operator()(assembly::If const& _if); - bool operator()(assembly::Switch const& _switch); - bool operator()(assembly::ForLoop const& _forLoop); - bool operator()(assembly::Block const& _block); + bool operator()(Instruction const&) { return true; } + bool operator()(Literal const&) { return true; } + bool operator()(Identifier const&) { return true; } + bool operator()(FunctionalInstruction const&) { return true; } + bool operator()(ExpressionStatement const& _expr); + bool operator()(Label const& _label); + bool operator()(StackAssignment const&) { return true; } + bool operator()(Assignment const&) { return true; } + bool operator()(VariableDeclaration const& _variableDeclaration); + bool operator()(FunctionDefinition const& _functionDefinition); + bool operator()(FunctionCall const&) { return true; } + bool operator()(If const& _if); + bool operator()(Switch const& _switch); + bool operator()(ForLoop const& _forLoop); + bool operator()(Block const& _block); private: bool registerVariable( @@ -76,7 +72,7 @@ private: Scope& _scope ); - Scope& scope(assembly::Block const* _block); + Scope& scope(Block const* _block); Scope* m_currentScope = nullptr; AsmAnalysisInfo& m_info; @@ -84,5 +80,3 @@ private: }; } -} -} diff --git a/libyul/CMakeLists.txt b/libyul/CMakeLists.txt new file mode 100644 index 00000000..8fbea689 --- /dev/null +++ b/libyul/CMakeLists.txt @@ -0,0 +1,43 @@ +add_library(yul + AsmAnalysis.cpp + AsmAnalysisInfo.cpp + AsmCodeGen.cpp + AsmParser.cpp + AsmPrinter.cpp + AsmScope.cpp + AsmScopeFiller.cpp + backends/evm/EVMAssembly.cpp + backends/evm/EVMCodeTransform.cpp + optimiser/ASTCopier.cpp + optimiser/ASTWalker.cpp + optimiser/BlockFlattener.cpp + optimiser/CommonSubexpressionEliminator.cpp + optimiser/DataFlowAnalyzer.cpp + optimiser/Disambiguator.cpp + optimiser/ExpressionInliner.cpp + optimiser/ExpressionJoiner.cpp + optimiser/ExpressionSimplifier.cpp + optimiser/ExpressionSplitter.cpp + optimiser/ForLoopInitRewriter.cpp + optimiser/FullInliner.cpp + optimiser/FunctionGrouper.cpp + optimiser/FunctionHoister.cpp + optimiser/InlinableExpressionFunctionFinder.cpp + optimiser/MainFunction.cpp + optimiser/Metrics.cpp + optimiser/NameCollector.cpp + optimiser/NameDispenser.cpp + optimiser/RedundantAssignEliminator.cpp + optimiser/Rematerialiser.cpp + optimiser/SSATransform.cpp + optimiser/SSAValueTracker.cpp + optimiser/Semantics.cpp + optimiser/SimplificationRules.cpp + optimiser/Substitution.cpp + optimiser/Suite.cpp + optimiser/SyntacticalEquality.cpp + optimiser/UnusedPruner.cpp + optimiser/Utilities.cpp + optimiser/VarDeclPropagator.cpp +) +target_link_libraries(yul PUBLIC devcore) diff --git a/libyul/Exceptions.h b/libyul/Exceptions.h index 0c421dbf..e10e53ef 100644 --- a/libyul/Exceptions.h +++ b/libyul/Exceptions.h @@ -23,18 +23,15 @@ #include <libdevcore/Exceptions.h> #include <libdevcore/Assertions.h> -namespace dev -{ namespace yul { -struct YulException: virtual Exception {}; +struct YulException: virtual dev::Exception {}; struct OptimizerException: virtual YulException {}; struct YulAssertion: virtual YulException {}; /// Assertion that throws an YulAssertion containing the given description if it is not met. #define yulAssert(CONDITION, DESCRIPTION) \ - assertThrow(CONDITION, ::dev::yul::YulException, DESCRIPTION) + assertThrow(CONDITION, ::yul::YulException, DESCRIPTION) } -} diff --git a/libyul/YulString.h b/libyul/YulString.h index ad900a70..2179c23b 100644 --- a/libyul/YulString.h +++ b/libyul/YulString.h @@ -27,8 +27,6 @@ #include <vector> #include <string> -namespace dev -{ namespace yul { @@ -130,4 +128,3 @@ private: }; } -} diff --git a/libyul/backends/evm/AbstractAssembly.h b/libyul/backends/evm/AbstractAssembly.h index 5a1140cb..97b1d305 100644 --- a/libyul/backends/evm/AbstractAssembly.h +++ b/libyul/backends/evm/AbstractAssembly.h @@ -22,6 +22,7 @@ #pragma once +#include <libdevcore/Common.h> #include <libdevcore/CommonData.h> #include <functional> @@ -36,14 +37,13 @@ namespace dev namespace solidity { enum class Instruction: uint8_t; -namespace assembly -{ -struct Instruction; -struct Identifier; } } + namespace yul { +struct Instruction; +struct Identifier; /// /// Assembly class that abstracts both the libevmasm assembly and the new Yul assembly. @@ -61,9 +61,9 @@ public: /// at the beginning. virtual int stackHeight() const = 0; /// Append an EVM instruction. - virtual void appendInstruction(solidity::Instruction _instruction) = 0; + virtual void appendInstruction(dev::solidity::Instruction _instruction) = 0; /// Append a constant. - virtual void appendConstant(u256 const& _constant) = 0; + virtual void appendConstant(dev::u256 const& _constant) = 0; /// Append a label. virtual void appendLabel(LabelID _labelId) = 0; /// Append a label reference. @@ -106,18 +106,15 @@ enum class IdentifierContext { LValue, RValue }; /// to inline assembly (not used in standalone assembly mode). struct ExternalIdentifierAccess { - using Resolver = std::function<size_t(solidity::assembly::Identifier const&, IdentifierContext, bool /*_crossesFunctionBoundary*/)>; + using Resolver = std::function<size_t(Identifier const&, IdentifierContext, bool /*_crossesFunctionBoundary*/)>; /// Resolve an external reference given by the identifier in the given context. /// @returns the size of the value (number of stack slots) or size_t(-1) if not found. Resolver resolve; - using CodeGenerator = std::function<void(solidity::assembly::Identifier const&, IdentifierContext, yul::AbstractAssembly&)>; + using CodeGenerator = std::function<void(Identifier const&, IdentifierContext, yul::AbstractAssembly&)>; /// Generate code for retrieving the value (rvalue context) or storing the value (lvalue context) /// of an identifier. The code should be appended to the assembly. In rvalue context, the value is supposed /// to be put onto the stack, in lvalue context, the value is assumed to be at the top of the stack. CodeGenerator generateCode; }; - - -} } diff --git a/libyul/backends/evm/EVMAssembly.cpp b/libyul/backends/evm/EVMAssembly.cpp index 791b6226..99506317 100644 --- a/libyul/backends/evm/EVMAssembly.cpp +++ b/libyul/backends/evm/EVMAssembly.cpp @@ -27,7 +27,7 @@ using namespace std; using namespace dev; using namespace langutil; -using namespace dev::yul; +using namespace yul; namespace { diff --git a/libyul/backends/evm/EVMAssembly.h b/libyul/backends/evm/EVMAssembly.h index c9190634..d0a437cc 100644 --- a/libyul/backends/evm/EVMAssembly.h +++ b/libyul/backends/evm/EVMAssembly.h @@ -31,8 +31,6 @@ namespace langutil struct SourceLocation; } -namespace dev -{ namespace yul { @@ -48,9 +46,9 @@ public: /// at the beginning. int stackHeight() const override { return m_stackHeight; } /// Append an EVM instruction. - void appendInstruction(solidity::Instruction _instruction) override; + void appendInstruction(dev::solidity::Instruction _instruction) override; /// Append a constant. - void appendConstant(u256 const& _constant) override; + void appendConstant(dev::u256 const& _constant) override; /// Append a label. void appendLabel(LabelID _labelId) override; /// Append a label reference. @@ -81,17 +79,17 @@ public: void appendAssemblySize() override; /// Resolves references inside the bytecode and returns the linker object. - eth::LinkerObject finalize(); + dev::eth::LinkerObject finalize(); private: void setLabelToCurrentPosition(AbstractAssembly::LabelID _labelId); void appendLabelReferenceInternal(AbstractAssembly::LabelID _labelId); - void updateReference(size_t pos, size_t size, u256 value); + void updateReference(size_t pos, size_t size, dev::u256 value); bool m_evm15 = false; ///< if true, switch to evm1.5 mode LabelID m_nextLabelId = 0; int m_stackHeight = 0; - bytes m_bytecode; + dev::bytes m_bytecode; std::map<std::string, LabelID> m_namedLabels; std::map<LabelID, size_t> m_labelPositions; std::map<size_t, LabelID> m_labelReferences; @@ -99,4 +97,3 @@ private: }; } -} diff --git a/libyul/backends/evm/EVMCodeTransform.cpp b/libyul/backends/evm/EVMCodeTransform.cpp index 23e09756..12abd754 100644 --- a/libyul/backends/evm/EVMCodeTransform.cpp +++ b/libyul/backends/evm/EVMCodeTransform.cpp @@ -20,8 +20,8 @@ #include <libyul/backends/evm/EVMCodeTransform.h> -#include <libsolidity/inlineasm/AsmAnalysisInfo.h> -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmAnalysisInfo.h> +#include <libyul/AsmData.h> #include <liblangutil/Exceptions.h> @@ -29,11 +29,9 @@ using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; using namespace dev::solidity; -using Scope = dev::solidity::assembly::Scope; - void CodeTransform::operator()(VariableDeclaration const& _varDecl) { solAssert(m_scope, ""); @@ -147,7 +145,7 @@ void CodeTransform::operator()(FunctionalInstruction const& _instruction) solAssert(_instruction.arguments.size() == 1, ""); } m_assembly.setSourceLocation(_instruction.location); - auto label = labelFromIdentifier(boost::get<assembly::Identifier>(_instruction.arguments.at(0))); + auto label = labelFromIdentifier(boost::get<Identifier>(_instruction.arguments.at(0))); if (isJumpI) m_assembly.appendJumpToIf(label); else @@ -163,7 +161,7 @@ void CodeTransform::operator()(FunctionalInstruction const& _instruction) checkStackHeight(&_instruction); } -void CodeTransform::operator()(assembly::Identifier const& _identifier) +void CodeTransform::operator()(Identifier const& _identifier) { m_assembly.setSourceLocation(_identifier.location); // First search internals, then externals. @@ -197,12 +195,12 @@ void CodeTransform::operator()(assembly::Identifier const& _identifier) checkStackHeight(&_identifier); } -void CodeTransform::operator()(assembly::Literal const& _literal) +void CodeTransform::operator()(Literal const& _literal) { m_assembly.setSourceLocation(_literal.location); - if (_literal.kind == assembly::LiteralKind::Number) + if (_literal.kind == LiteralKind::Number) m_assembly.appendConstant(u256(_literal.value.str())); - else if (_literal.kind == assembly::LiteralKind::Boolean) + else if (_literal.kind == LiteralKind::Boolean) { if (_literal.value.str() == "true") m_assembly.appendConstant(u256(1)); @@ -217,7 +215,7 @@ void CodeTransform::operator()(assembly::Literal const& _literal) checkStackHeight(&_literal); } -void CodeTransform::operator()(assembly::Instruction const& _instruction) +void CodeTransform::operator()(yul::Instruction const& _instruction) { solAssert(!m_evm15 || _instruction.instruction != solidity::Instruction::JUMP, "Bare JUMP instruction used for EVM1.5"); solAssert(!m_evm15 || _instruction.instruction != solidity::Instruction::JUMPI, "Bare JUMPI instruction used for EVM1.5"); @@ -522,7 +520,7 @@ void CodeTransform::generateAssignment(Identifier const& _variableName) } } -int CodeTransform::variableHeightDiff(solidity::assembly::Scope::Variable const& _var, bool _forSwap) const +int CodeTransform::variableHeightDiff(Scope::Variable const& _var, bool _forSwap) const { solAssert(m_context->variableStackHeights.count(&_var), ""); int heightDiff = m_assembly.stackHeight() - m_context->variableStackHeights[&_var]; diff --git a/libyul/backends/evm/EVMCodeTransform.h b/libyul/backends/evm/EVMCodeTransform.h index c0de8ad6..d559f85a 100644 --- a/libyul/backends/evm/EVMCodeTransform.h +++ b/libyul/backends/evm/EVMCodeTransform.h @@ -20,25 +20,21 @@ #include <libyul/backends/evm/EVMAssembly.h> -#include <libyul/ASTDataForward.h> +#include <libyul/AsmDataForward.h> -#include <libsolidity/inlineasm/AsmScope.h> +#include <libyul/AsmScope.h> #include <boost/variant.hpp> #include <boost/optional.hpp> -namespace dev -{ -namespace solidity +namespace langutil { class ErrorReporter; -namespace assembly -{ -struct AsmAnalysisInfo; -} } + namespace yul { +struct AsmAnalysisInfo; class EVMAssembly; class CodeTransform: public boost::static_visitor<> @@ -47,8 +43,8 @@ public: /// Create the code transformer. /// @param _identifierAccess used to resolve identifiers external to the inline assembly CodeTransform( - yul::AbstractAssembly& _assembly, - solidity::assembly::AsmAnalysisInfo& _analysisInfo, + AbstractAssembly& _assembly, + AsmAnalysisInfo& _analysisInfo, bool _yul = false, bool _evm15 = false, ExternalIdentifierAccess const& _identifierAccess = ExternalIdentifierAccess(), @@ -69,15 +65,14 @@ public: protected: struct Context { - using Scope = solidity::assembly::Scope; std::map<Scope::Label const*, AbstractAssembly::LabelID> labelIDs; std::map<Scope::Function const*, AbstractAssembly::LabelID> functionEntryIDs; std::map<Scope::Variable const*, int> variableStackHeights; }; CodeTransform( - yul::AbstractAssembly& _assembly, - solidity::assembly::AsmAnalysisInfo& _analysisInfo, + AbstractAssembly& _assembly, + AsmAnalysisInfo& _analysisInfo, bool _yul, bool _evm15, ExternalIdentifierAccess const& _identifierAccess, @@ -116,8 +111,8 @@ private: AbstractAssembly::LabelID labelFromIdentifier(Identifier const& _identifier); /// @returns the label ID corresponding to the given label, allocating a new one if /// necessary. - AbstractAssembly::LabelID labelID(solidity::assembly::Scope::Label const& _label); - AbstractAssembly::LabelID functionEntryID(YulString _name, solidity::assembly::Scope::Function const& _function); + AbstractAssembly::LabelID labelID(Scope::Label const& _label); + AbstractAssembly::LabelID functionEntryID(YulString _name, Scope::Function const& _function); /// Generates code for an expression that is supposed to return a single value. void visitExpression(Expression const& _expression); @@ -133,15 +128,15 @@ private: /// Determines the stack height difference to the given variables. Throws /// if it is not yet in scope or the height difference is too large. Returns /// the (positive) stack height difference otherwise. - int variableHeightDiff(solidity::assembly::Scope::Variable const& _var, bool _forSwap) const; + int variableHeightDiff(Scope::Variable const& _var, bool _forSwap) const; void expectDeposit(int _deposit, int _oldHeight) const; void checkStackHeight(void const* _astElement) const; - yul::AbstractAssembly& m_assembly; - solidity::assembly::AsmAnalysisInfo& m_info; - solidity::assembly::Scope* m_scope = nullptr; + AbstractAssembly& m_assembly; + AsmAnalysisInfo& m_info; + Scope* m_scope = nullptr; bool m_yul = false; bool m_evm15 = false; bool m_useNamedLabelsForFunctions = false; @@ -155,4 +150,3 @@ private: }; } -} diff --git a/libyul/optimiser/ASTCopier.cpp b/libyul/optimiser/ASTCopier.cpp index d0c8dd45..f18b0e6b 100644 --- a/libyul/optimiser/ASTCopier.cpp +++ b/libyul/optimiser/ASTCopier.cpp @@ -22,13 +22,13 @@ #include <libyul/Exceptions.h> -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> #include <libdevcore/Common.h> using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; Statement ASTCopier::operator()(Instruction const&) { diff --git a/libyul/optimiser/ASTCopier.h b/libyul/optimiser/ASTCopier.h index 95e58a56..4d2f18ae 100644 --- a/libyul/optimiser/ASTCopier.h +++ b/libyul/optimiser/ASTCopier.h @@ -20,7 +20,7 @@ #pragma once -#include <libyul/ASTDataForward.h> +#include <libyul/AsmDataForward.h> #include <libyul/YulString.h> @@ -31,8 +31,6 @@ #include <set> #include <memory> -namespace dev -{ namespace yul { @@ -123,4 +121,3 @@ std::vector<T> ASTCopier::translateVector(std::vector<T> const& _values) } -} diff --git a/libyul/optimiser/ASTWalker.cpp b/libyul/optimiser/ASTWalker.cpp index e29dda6b..0d568007 100644 --- a/libyul/optimiser/ASTWalker.cpp +++ b/libyul/optimiser/ASTWalker.cpp @@ -20,13 +20,13 @@ #include <libyul/optimiser/ASTWalker.h> -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> #include <boost/range/adaptor/reversed.hpp> using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; using namespace dev::solidity; diff --git a/libyul/optimiser/ASTWalker.h b/libyul/optimiser/ASTWalker.h index 38cb85ea..b59b405e 100644 --- a/libyul/optimiser/ASTWalker.h +++ b/libyul/optimiser/ASTWalker.h @@ -20,7 +20,7 @@ #pragma once -#include <libyul/ASTDataForward.h> +#include <libyul/AsmDataForward.h> #include <libyul/Exceptions.h> #include <libyul/YulString.h> @@ -32,8 +32,6 @@ #include <set> #include <map> -namespace dev -{ namespace yul { @@ -120,4 +118,3 @@ protected: }; } -} diff --git a/libyul/optimiser/BlockFlattener.cpp b/libyul/optimiser/BlockFlattener.cpp index 04f3ad7f..e6f08524 100644 --- a/libyul/optimiser/BlockFlattener.cpp +++ b/libyul/optimiser/BlockFlattener.cpp @@ -15,14 +15,14 @@ along with solidity. If not, see <http://www.gnu.org/licenses/>. */ #include <libyul/optimiser/BlockFlattener.h> -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> #include <libdevcore/Visitor.h> #include <libdevcore/CommonData.h> #include <functional> using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; void BlockFlattener::operator()(Block& _block) { diff --git a/libyul/optimiser/BlockFlattener.h b/libyul/optimiser/BlockFlattener.h index 88c49dda..b732422d 100644 --- a/libyul/optimiser/BlockFlattener.h +++ b/libyul/optimiser/BlockFlattener.h @@ -18,8 +18,6 @@ #include <libyul/optimiser/ASTWalker.h> -namespace dev -{ namespace yul { @@ -31,4 +29,3 @@ public: }; } -} diff --git a/libyul/optimiser/CommonSubexpressionEliminator.cpp b/libyul/optimiser/CommonSubexpressionEliminator.cpp index 64605362..9b851333 100644 --- a/libyul/optimiser/CommonSubexpressionEliminator.cpp +++ b/libyul/optimiser/CommonSubexpressionEliminator.cpp @@ -24,12 +24,11 @@ #include <libyul/optimiser/Metrics.h> #include <libyul/optimiser/SyntacticalEquality.h> #include <libyul/Exceptions.h> - -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; void CommonSubexpressionEliminator::visit(Expression& _e) { diff --git a/libyul/optimiser/CommonSubexpressionEliminator.h b/libyul/optimiser/CommonSubexpressionEliminator.h index 16b39f5b..ac1ebe3a 100644 --- a/libyul/optimiser/CommonSubexpressionEliminator.h +++ b/libyul/optimiser/CommonSubexpressionEliminator.h @@ -23,8 +23,6 @@ #include <libyul/optimiser/DataFlowAnalyzer.h> -namespace dev -{ namespace yul { @@ -42,4 +40,3 @@ protected: }; } -} diff --git a/libyul/optimiser/DataFlowAnalyzer.cpp b/libyul/optimiser/DataFlowAnalyzer.cpp index 134777d0..64c67b38 100644 --- a/libyul/optimiser/DataFlowAnalyzer.cpp +++ b/libyul/optimiser/DataFlowAnalyzer.cpp @@ -25,8 +25,7 @@ #include <libyul/optimiser/NameCollector.h> #include <libyul/optimiser/Semantics.h> #include <libyul/Exceptions.h> - -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> #include <libdevcore/CommonData.h> @@ -34,7 +33,7 @@ using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; void DataFlowAnalyzer::operator()(Assignment& _assignment) { diff --git a/libyul/optimiser/DataFlowAnalyzer.h b/libyul/optimiser/DataFlowAnalyzer.h index a946529a..cd134d48 100644 --- a/libyul/optimiser/DataFlowAnalyzer.h +++ b/libyul/optimiser/DataFlowAnalyzer.h @@ -23,14 +23,11 @@ #pragma once #include <libyul/optimiser/ASTWalker.h> - #include <libyul/YulString.h> #include <map> #include <set> -namespace dev -{ namespace yul { @@ -88,4 +85,3 @@ protected: }; } -} diff --git a/libyul/optimiser/Disambiguator.cpp b/libyul/optimiser/Disambiguator.cpp index 4303f412..fda5895b 100644 --- a/libyul/optimiser/Disambiguator.cpp +++ b/libyul/optimiser/Disambiguator.cpp @@ -21,17 +21,14 @@ #include <libyul/optimiser/Disambiguator.h> #include <libyul/Exceptions.h> - -#include <libsolidity/inlineasm/AsmData.h> -#include <libsolidity/inlineasm/AsmScope.h> +#include <libyul/AsmData.h> +#include <libyul/AsmScope.h> using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; using namespace dev::solidity; -using Scope = dev::solidity::assembly::Scope; - YulString Disambiguator::translateIdentifier(YulString _originalName) { if ((m_externallyUsedIdentifiers.count(_originalName))) diff --git a/libyul/optimiser/Disambiguator.h b/libyul/optimiser/Disambiguator.h index 0fcd41d9..bb83417b 100644 --- a/libyul/optimiser/Disambiguator.h +++ b/libyul/optimiser/Disambiguator.h @@ -20,20 +20,16 @@ #pragma once -#include <libyul/ASTDataForward.h> - +#include <libyul/AsmDataForward.h> +#include <libyul/AsmAnalysisInfo.h> #include <libyul/optimiser/ASTCopier.h> #include <libyul/optimiser/NameDispenser.h> -#include <libsolidity/inlineasm/AsmAnalysisInfo.h> - #include <boost/variant.hpp> #include <boost/optional.hpp> #include <set> -namespace dev -{ namespace yul { @@ -44,7 +40,7 @@ class Disambiguator: public ASTCopier { public: explicit Disambiguator( - solidity::assembly::AsmAnalysisInfo const& _analysisInfo, + AsmAnalysisInfo const& _analysisInfo, std::set<YulString> const& _externallyUsedIdentifiers = {} ): m_info(_analysisInfo), m_externallyUsedIdentifiers(_externallyUsedIdentifiers), m_nameDispenser(m_externallyUsedIdentifiers) @@ -58,16 +54,15 @@ protected: void leaveFunction(FunctionDefinition const& _function) override; YulString translateIdentifier(YulString _name) override; - void enterScopeInternal(solidity::assembly::Scope& _scope); - void leaveScopeInternal(solidity::assembly::Scope& _scope); + void enterScopeInternal(Scope& _scope); + void leaveScopeInternal(Scope& _scope); - solidity::assembly::AsmAnalysisInfo const& m_info; + AsmAnalysisInfo const& m_info; std::set<YulString> const& m_externallyUsedIdentifiers; - std::vector<solidity::assembly::Scope*> m_scopes; + std::vector<Scope*> m_scopes; std::map<void const*, YulString> m_translations; NameDispenser m_nameDispenser; }; } -} diff --git a/libyul/optimiser/ExpressionInliner.cpp b/libyul/optimiser/ExpressionInliner.cpp index 07e88191..27d43ac0 100644 --- a/libyul/optimiser/ExpressionInliner.cpp +++ b/libyul/optimiser/ExpressionInliner.cpp @@ -23,14 +23,13 @@ #include <libyul/optimiser/InlinableExpressionFunctionFinder.h> #include <libyul/optimiser/Substitution.h> #include <libyul/optimiser/Semantics.h> - -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> #include <boost/algorithm/cxx11/all_of.hpp> using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; using namespace dev::solidity; void ExpressionInliner::run() diff --git a/libyul/optimiser/ExpressionInliner.h b/libyul/optimiser/ExpressionInliner.h index ee98da8f..14e80c0a 100644 --- a/libyul/optimiser/ExpressionInliner.h +++ b/libyul/optimiser/ExpressionInliner.h @@ -20,16 +20,13 @@ #pragma once #include <libyul/optimiser/ASTWalker.h> - -#include <libyul/ASTDataForward.h> +#include <libyul/AsmDataForward.h> #include <boost/variant.hpp> #include <boost/optional.hpp> #include <set> -namespace dev -{ namespace yul { @@ -69,4 +66,3 @@ private: } -} diff --git a/libyul/optimiser/ExpressionJoiner.cpp b/libyul/optimiser/ExpressionJoiner.cpp index 7e57a629..de2b5d53 100644 --- a/libyul/optimiser/ExpressionJoiner.cpp +++ b/libyul/optimiser/ExpressionJoiner.cpp @@ -24,8 +24,7 @@ #include <libyul/optimiser/NameCollector.h> #include <libyul/optimiser/Utilities.h> #include <libyul/Exceptions.h> - -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> #include <libdevcore/CommonData.h> @@ -33,7 +32,7 @@ using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; using namespace dev::solidity; void ExpressionJoiner::operator()(FunctionalInstruction& _instruction) diff --git a/libyul/optimiser/ExpressionJoiner.h b/libyul/optimiser/ExpressionJoiner.h index 0cc61981..643d62b0 100644 --- a/libyul/optimiser/ExpressionJoiner.h +++ b/libyul/optimiser/ExpressionJoiner.h @@ -20,14 +20,11 @@ */ #pragma once -#include <libyul/ASTDataForward.h> - +#include <libyul/AsmDataForward.h> #include <libyul/optimiser/ASTWalker.h> #include <map> -namespace dev -{ namespace yul { @@ -99,4 +96,3 @@ private: }; } -} diff --git a/libyul/optimiser/ExpressionSimplifier.cpp b/libyul/optimiser/ExpressionSimplifier.cpp index 64e9d7e7..cda44e8e 100644 --- a/libyul/optimiser/ExpressionSimplifier.cpp +++ b/libyul/optimiser/ExpressionSimplifier.cpp @@ -23,14 +23,13 @@ #include <libyul/optimiser/SimplificationRules.h> #include <libyul/optimiser/Semantics.h> #include <libyul/optimiser/SSAValueTracker.h> - -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> #include <libdevcore/CommonData.h> using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; using namespace dev::solidity; diff --git a/libyul/optimiser/ExpressionSimplifier.h b/libyul/optimiser/ExpressionSimplifier.h index 5965a1bb..fe3507f8 100644 --- a/libyul/optimiser/ExpressionSimplifier.h +++ b/libyul/optimiser/ExpressionSimplifier.h @@ -20,12 +20,10 @@ #pragma once -#include <libyul/ASTDataForward.h> +#include <libyul/AsmDataForward.h> #include <libyul/optimiser/ASTWalker.h> -namespace dev -{ namespace yul { @@ -52,4 +50,3 @@ private: }; } -} diff --git a/libyul/optimiser/ExpressionSplitter.cpp b/libyul/optimiser/ExpressionSplitter.cpp index 42730864..a3b2dc11 100644 --- a/libyul/optimiser/ExpressionSplitter.cpp +++ b/libyul/optimiser/ExpressionSplitter.cpp @@ -23,7 +23,7 @@ #include <libyul/optimiser/ASTWalker.h> -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> #include <libdevcore/CommonData.h> @@ -32,7 +32,7 @@ using namespace std; using namespace dev; using namespace langutil; -using namespace dev::yul; +using namespace yul; using namespace dev::solidity; void ExpressionSplitter::operator()(FunctionalInstruction& _instruction) diff --git a/libyul/optimiser/ExpressionSplitter.h b/libyul/optimiser/ExpressionSplitter.h index 82274203..d4d2b3f6 100644 --- a/libyul/optimiser/ExpressionSplitter.h +++ b/libyul/optimiser/ExpressionSplitter.h @@ -20,15 +20,13 @@ */ #pragma once -#include <libyul/ASTDataForward.h> +#include <libyul/AsmDataForward.h> #include <libyul/optimiser/ASTWalker.h> #include <libyul/optimiser/NameDispenser.h> #include <vector> -namespace dev -{ namespace yul { @@ -83,4 +81,3 @@ private: }; } -} diff --git a/libyul/optimiser/ForLoopInitRewriter.cpp b/libyul/optimiser/ForLoopInitRewriter.cpp index 0decf5e2..80d39248 100644 --- a/libyul/optimiser/ForLoopInitRewriter.cpp +++ b/libyul/optimiser/ForLoopInitRewriter.cpp @@ -15,13 +15,13 @@ along with solidity. If not, see <http://www.gnu.org/licenses/>. */ #include <libyul/optimiser/ForLoopInitRewriter.h> -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> #include <libdevcore/CommonData.h> #include <functional> using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; void ForLoopInitRewriter::operator()(Block& _block) { diff --git a/libyul/optimiser/ForLoopInitRewriter.h b/libyul/optimiser/ForLoopInitRewriter.h index 64f53711..e925c6c2 100644 --- a/libyul/optimiser/ForLoopInitRewriter.h +++ b/libyul/optimiser/ForLoopInitRewriter.h @@ -18,8 +18,6 @@ #include <libyul/optimiser/ASTWalker.h> -namespace dev -{ namespace yul { @@ -36,4 +34,3 @@ public: }; } -} diff --git a/libyul/optimiser/FullInliner.cpp b/libyul/optimiser/FullInliner.cpp index c9057cf3..8ae26fbb 100644 --- a/libyul/optimiser/FullInliner.cpp +++ b/libyul/optimiser/FullInliner.cpp @@ -27,8 +27,7 @@ #include <libyul/optimiser/Metrics.h> #include <libyul/optimiser/SSAValueTracker.h> #include <libyul/Exceptions.h> - -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> #include <libdevcore/CommonData.h> #include <libdevcore/Visitor.h> @@ -37,7 +36,7 @@ using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; using namespace dev::solidity; FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser): diff --git a/libyul/optimiser/FullInliner.h b/libyul/optimiser/FullInliner.h index 5ebb3bf6..a8fe76c6 100644 --- a/libyul/optimiser/FullInliner.h +++ b/libyul/optimiser/FullInliner.h @@ -19,7 +19,7 @@ */ #pragma once -#include <libyul/ASTDataForward.h> +#include <libyul/AsmDataForward.h> #include <libyul/optimiser/ASTCopier.h> #include <libyul/optimiser/ASTWalker.h> @@ -33,8 +33,6 @@ #include <set> -namespace dev -{ namespace yul { @@ -153,4 +151,3 @@ public: } -} diff --git a/libyul/optimiser/FunctionGrouper.cpp b/libyul/optimiser/FunctionGrouper.cpp index 3d2e5322..02ce22cd 100644 --- a/libyul/optimiser/FunctionGrouper.cpp +++ b/libyul/optimiser/FunctionGrouper.cpp @@ -21,13 +21,13 @@ #include <libyul/optimiser/FunctionGrouper.h> -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> #include <boost/range/algorithm_ext/erase.hpp> using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; using namespace dev::solidity; diff --git a/libyul/optimiser/FunctionGrouper.h b/libyul/optimiser/FunctionGrouper.h index 63cfbfb1..3b3f48a7 100644 --- a/libyul/optimiser/FunctionGrouper.h +++ b/libyul/optimiser/FunctionGrouper.h @@ -21,10 +21,8 @@ #pragma once -#include <libyul/ASTDataForward.h> +#include <libyul/AsmDataForward.h> -namespace dev -{ namespace yul { @@ -43,4 +41,3 @@ public: }; } -} diff --git a/libyul/optimiser/FunctionHoister.cpp b/libyul/optimiser/FunctionHoister.cpp index c196dead..bd1c781b 100644 --- a/libyul/optimiser/FunctionHoister.cpp +++ b/libyul/optimiser/FunctionHoister.cpp @@ -22,14 +22,13 @@ #include <libyul/optimiser/FunctionHoister.h> #include <libyul/optimiser/Utilities.h> - -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> #include <libdevcore/CommonData.h> using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; using namespace dev::solidity; void FunctionHoister::operator()(Block& _block) diff --git a/libyul/optimiser/FunctionHoister.h b/libyul/optimiser/FunctionHoister.h index 823b9e2b..31092069 100644 --- a/libyul/optimiser/FunctionHoister.h +++ b/libyul/optimiser/FunctionHoister.h @@ -21,12 +21,9 @@ #pragma once -#include <libyul/ASTDataForward.h> - +#include <libyul/AsmDataForward.h> #include <libyul/optimiser/ASTWalker.h> -namespace dev -{ namespace yul { @@ -49,4 +46,3 @@ private: }; } -} diff --git a/libyul/optimiser/InlinableExpressionFunctionFinder.cpp b/libyul/optimiser/InlinableExpressionFunctionFinder.cpp index deaaee97..662cdf25 100644 --- a/libyul/optimiser/InlinableExpressionFunctionFinder.cpp +++ b/libyul/optimiser/InlinableExpressionFunctionFinder.cpp @@ -21,12 +21,11 @@ #include <libyul/optimiser/InlinableExpressionFunctionFinder.h> #include <libyul/optimiser/Utilities.h> - -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; void InlinableExpressionFunctionFinder::operator()(Identifier const& _identifier) { diff --git a/libyul/optimiser/InlinableExpressionFunctionFinder.h b/libyul/optimiser/InlinableExpressionFunctionFinder.h index a96f042f..afde8a2a 100644 --- a/libyul/optimiser/InlinableExpressionFunctionFinder.h +++ b/libyul/optimiser/InlinableExpressionFunctionFinder.h @@ -20,13 +20,11 @@ #pragma once -#include <libyul/ASTDataForward.h> +#include <libyul/AsmDataForward.h> #include <libyul/optimiser/ASTWalker.h> #include <set> -namespace dev -{ namespace yul { @@ -66,4 +64,3 @@ private: }; } -} diff --git a/libyul/optimiser/MainFunction.cpp b/libyul/optimiser/MainFunction.cpp index f3306598..63eea2db 100644 --- a/libyul/optimiser/MainFunction.cpp +++ b/libyul/optimiser/MainFunction.cpp @@ -24,13 +24,13 @@ #include <libyul/optimiser/NameCollector.h> #include <libyul/Exceptions.h> -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> #include <libdevcore/CommonData.h> using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; using namespace dev::solidity; void MainFunction::operator()(Block& _block) diff --git a/libyul/optimiser/MainFunction.h b/libyul/optimiser/MainFunction.h index 4a73283a..96acc0ac 100644 --- a/libyul/optimiser/MainFunction.h +++ b/libyul/optimiser/MainFunction.h @@ -21,10 +21,8 @@ #pragma once -#include <libyul/ASTDataForward.h> +#include <libyul/AsmDataForward.h> -namespace dev -{ namespace yul { @@ -38,4 +36,3 @@ public: }; } -} diff --git a/libyul/optimiser/Metrics.cpp b/libyul/optimiser/Metrics.cpp index 066c6b58..a5557fb3 100644 --- a/libyul/optimiser/Metrics.cpp +++ b/libyul/optimiser/Metrics.cpp @@ -20,10 +20,10 @@ #include <libyul/optimiser/Metrics.h> -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> using namespace dev; -using namespace dev::yul; +using namespace yul; size_t CodeSize::codeSize(Statement const& _statement) { diff --git a/libyul/optimiser/Metrics.h b/libyul/optimiser/Metrics.h index e65110a8..ca244600 100644 --- a/libyul/optimiser/Metrics.h +++ b/libyul/optimiser/Metrics.h @@ -22,8 +22,6 @@ #include <libyul/optimiser/ASTWalker.h> -namespace dev -{ namespace yul { @@ -49,4 +47,3 @@ private: }; } -} diff --git a/libyul/optimiser/NameCollector.cpp b/libyul/optimiser/NameCollector.cpp index 36f55b99..f9079827 100644 --- a/libyul/optimiser/NameCollector.cpp +++ b/libyul/optimiser/NameCollector.cpp @@ -20,11 +20,11 @@ #include <libyul/optimiser/NameCollector.h> -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; void NameCollector::operator()(VariableDeclaration const& _varDecl) { diff --git a/libyul/optimiser/NameCollector.h b/libyul/optimiser/NameCollector.h index 8ef0178d..c177a399 100644 --- a/libyul/optimiser/NameCollector.h +++ b/libyul/optimiser/NameCollector.h @@ -25,8 +25,6 @@ #include <map> #include <set> -namespace dev -{ namespace yul { @@ -83,4 +81,3 @@ private: }; } -} diff --git a/libyul/optimiser/NameDispenser.cpp b/libyul/optimiser/NameDispenser.cpp index 3c870fa5..e7cdc60f 100644 --- a/libyul/optimiser/NameDispenser.cpp +++ b/libyul/optimiser/NameDispenser.cpp @@ -21,12 +21,11 @@ #include <libyul/optimiser/NameDispenser.h> #include <libyul/optimiser/NameCollector.h> - -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; NameDispenser::NameDispenser(Block const& _ast): NameDispenser(NameCollector(_ast).names()) diff --git a/libyul/optimiser/NameDispenser.h b/libyul/optimiser/NameDispenser.h index 7311440b..664a5265 100644 --- a/libyul/optimiser/NameDispenser.h +++ b/libyul/optimiser/NameDispenser.h @@ -19,14 +19,12 @@ */ #pragma once -#include <libyul/ASTDataForward.h> +#include <libyul/AsmDataForward.h> #include <libyul/YulString.h> #include <set> -namespace dev -{ namespace yul { @@ -58,4 +56,3 @@ private: }; } -} diff --git a/libyul/optimiser/RedundantAssignEliminator.cpp b/libyul/optimiser/RedundantAssignEliminator.cpp index b7217074..7b18e8ca 100644 --- a/libyul/optimiser/RedundantAssignEliminator.cpp +++ b/libyul/optimiser/RedundantAssignEliminator.cpp @@ -22,8 +22,7 @@ #include <libyul/optimiser/RedundantAssignEliminator.h> #include <libyul/optimiser/Semantics.h> - -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> #include <libdevcore/CommonData.h> @@ -31,7 +30,7 @@ using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; using namespace dev::solidity; void RedundantAssignEliminator::operator()(Identifier const& _identifier) diff --git a/libyul/optimiser/RedundantAssignEliminator.h b/libyul/optimiser/RedundantAssignEliminator.h index 76106aae..54d65823 100644 --- a/libyul/optimiser/RedundantAssignEliminator.h +++ b/libyul/optimiser/RedundantAssignEliminator.h @@ -21,14 +21,11 @@ #pragma once -#include <libyul/ASTDataForward.h> - +#include <libyul/AsmDataForward.h> #include <libyul/optimiser/ASTWalker.h> #include <map> -namespace dev -{ namespace yul { @@ -190,4 +187,3 @@ private: }; } -} diff --git a/libyul/optimiser/Rematerialiser.cpp b/libyul/optimiser/Rematerialiser.cpp index 38d50ef4..4180bfc3 100644 --- a/libyul/optimiser/Rematerialiser.cpp +++ b/libyul/optimiser/Rematerialiser.cpp @@ -23,12 +23,11 @@ #include <libyul/optimiser/Metrics.h> #include <libyul/optimiser/ASTCopier.h> #include <libyul/Exceptions.h> - -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; void Rematerialiser::visit(Expression& _e) { diff --git a/libyul/optimiser/Rematerialiser.h b/libyul/optimiser/Rematerialiser.h index f0e7cb01..b3841519 100644 --- a/libyul/optimiser/Rematerialiser.h +++ b/libyul/optimiser/Rematerialiser.h @@ -22,8 +22,6 @@ #include <libyul/optimiser/DataFlowAnalyzer.h> -namespace dev -{ namespace yul { @@ -41,4 +39,3 @@ protected: }; } -} diff --git a/libyul/optimiser/SSATransform.cpp b/libyul/optimiser/SSATransform.cpp index 6fb4b08d..928c0859 100644 --- a/libyul/optimiser/SSATransform.cpp +++ b/libyul/optimiser/SSATransform.cpp @@ -23,8 +23,7 @@ #include <libyul/optimiser/NameCollector.h> #include <libyul/optimiser/NameDispenser.h> - -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> #include <libdevcore/CommonData.h> @@ -32,7 +31,7 @@ using namespace std; using namespace dev; using namespace langutil; -using namespace dev::yul; +using namespace yul; using namespace dev::solidity; void SSATransform::operator()(Identifier& _identifier) diff --git a/libyul/optimiser/SSATransform.h b/libyul/optimiser/SSATransform.h index bb642549..4cb62f23 100644 --- a/libyul/optimiser/SSATransform.h +++ b/libyul/optimiser/SSATransform.h @@ -20,14 +20,11 @@ */ #pragma once -#include <libyul/ASTDataForward.h> - +#include <libyul/AsmDataForward.h> #include <libyul/optimiser/ASTWalker.h> #include <vector> -namespace dev -{ namespace yul { @@ -95,4 +92,3 @@ private: }; } -} diff --git a/libyul/optimiser/SSAValueTracker.cpp b/libyul/optimiser/SSAValueTracker.cpp index 491117da..35b29b04 100644 --- a/libyul/optimiser/SSAValueTracker.cpp +++ b/libyul/optimiser/SSAValueTracker.cpp @@ -21,11 +21,11 @@ #include <libyul/optimiser/SSAValueTracker.h> -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; void SSAValueTracker::operator()(Assignment const& _assignment) { diff --git a/libyul/optimiser/SSAValueTracker.h b/libyul/optimiser/SSAValueTracker.h index acd5229c..e182e013 100644 --- a/libyul/optimiser/SSAValueTracker.h +++ b/libyul/optimiser/SSAValueTracker.h @@ -26,8 +26,6 @@ #include <map> #include <set> -namespace dev -{ namespace yul { @@ -54,4 +52,3 @@ private: }; } -} diff --git a/libyul/optimiser/Semantics.cpp b/libyul/optimiser/Semantics.cpp index 3c49016e..91bb2709 100644 --- a/libyul/optimiser/Semantics.cpp +++ b/libyul/optimiser/Semantics.cpp @@ -21,8 +21,7 @@ #include <libyul/optimiser/Semantics.h> #include <libyul/Exceptions.h> - -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> #include <libevmasm/SemanticInformation.h> @@ -30,7 +29,7 @@ using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; MovableChecker::MovableChecker(Expression const& _expression) { diff --git a/libyul/optimiser/Semantics.h b/libyul/optimiser/Semantics.h index a7e8706b..70c50806 100644 --- a/libyul/optimiser/Semantics.h +++ b/libyul/optimiser/Semantics.h @@ -24,8 +24,6 @@ #include <set> -namespace dev -{ namespace yul { @@ -57,4 +55,3 @@ private: }; } -} diff --git a/libyul/optimiser/SimplificationRules.cpp b/libyul/optimiser/SimplificationRules.cpp index a15ed391..b3190fef 100644 --- a/libyul/optimiser/SimplificationRules.cpp +++ b/libyul/optimiser/SimplificationRules.cpp @@ -24,15 +24,14 @@ #include <libyul/optimiser/ASTCopier.h> #include <libyul/optimiser/Semantics.h> #include <libyul/optimiser/SyntacticalEquality.h> - -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> #include <libevmasm/RuleList.h> using namespace std; using namespace dev; using namespace langutil; -using namespace dev::yul; +using namespace yul; SimplificationRule<Pattern> const* SimplificationRules::findFirstMatch( @@ -124,7 +123,7 @@ bool Pattern::matches(Expression const& _expr, map<YulString, Expression const*> if (expr->type() != typeid(Literal)) return false; Literal const& literal = boost::get<Literal>(*expr); - if (literal.kind != assembly::LiteralKind::Number) + if (literal.kind != LiteralKind::Number) return false; if (m_data && *m_data != u256(literal.value.str())) return false; @@ -194,7 +193,7 @@ Expression Pattern::toExpression(SourceLocation const& _location) const if (m_kind == PatternKind::Constant) { assertThrow(m_data, OptimizerException, "No match group and no constant value given."); - return Literal{_location, assembly::LiteralKind::Number, YulString{formatNumber(*m_data)}, {}}; + return Literal{_location, LiteralKind::Number, YulString{formatNumber(*m_data)}, {}}; } else if (m_kind == PatternKind::Operation) { @@ -209,7 +208,7 @@ Expression Pattern::toExpression(SourceLocation const& _location) const u256 Pattern::d() const { Literal const& literal = boost::get<Literal>(matchGroupValue()); - assertThrow(literal.kind == assembly::LiteralKind::Number, OptimizerException, ""); + assertThrow(literal.kind == LiteralKind::Number, OptimizerException, ""); assertThrow(isValidDecimal(literal.value.str()) || isValidHex(literal.value.str()), OptimizerException, ""); return u256(literal.value.str()); } diff --git a/libyul/optimiser/SimplificationRules.h b/libyul/optimiser/SimplificationRules.h index bd6aa4de..16aaba04 100644 --- a/libyul/optimiser/SimplificationRules.h +++ b/libyul/optimiser/SimplificationRules.h @@ -23,17 +23,14 @@ #include <libevmasm/ExpressionClasses.h> #include <libevmasm/SimplificationRule.h> -#include <libyul/ASTDataForward.h> - -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmDataForward.h> +#include <libyul/AsmData.h> #include <boost/noncopyable.hpp> #include <functional> #include <vector> -namespace dev -{ namespace yul { @@ -86,11 +83,11 @@ public: /// Matches any expression. Pattern(PatternKind _kind = PatternKind::Any): m_kind(_kind) {} // Matches a specific constant value. - Pattern(unsigned _value): Pattern(u256(_value)) {} + Pattern(unsigned _value): Pattern(dev::u256(_value)) {} // Matches a specific constant value. - Pattern(u256 const& _value): m_kind(PatternKind::Constant), m_data(std::make_shared<u256>(_value)) {} + Pattern(dev::u256 const& _value): m_kind(PatternKind::Constant), m_data(std::make_shared<dev::u256>(_value)) {} // Matches a given instruction with given arguments - Pattern(solidity::Instruction _instruction, std::vector<Pattern> const& _arguments = {}); + Pattern(dev::solidity::Instruction _instruction, std::vector<Pattern> const& _arguments = {}); /// Sets this pattern to be part of the match group with the identifier @a _group. /// Inside one rule, all patterns in the same match group have to match expressions from the /// same expression equivalence class. @@ -101,9 +98,9 @@ public: std::vector<Pattern> arguments() const { return m_arguments; } /// @returns the data of the matched expression if this pattern is part of a match group. - u256 d() const; + dev::u256 d() const; - solidity::Instruction instruction() const; + dev::solidity::Instruction instruction() const; /// Turns this pattern into an actual expression. Should only be called /// for patterns resulting from an action, i.e. with match groups assigned. @@ -113,12 +110,11 @@ private: Expression const& matchGroupValue() const; PatternKind m_kind = PatternKind::Any; - solidity::Instruction m_instruction; ///< Only valid if m_kind is Operation - std::shared_ptr<u256> m_data; ///< Only valid if m_kind is Constant + dev::solidity::Instruction m_instruction; ///< Only valid if m_kind is Operation + std::shared_ptr<dev::u256> m_data; ///< Only valid if m_kind is Constant std::vector<Pattern> m_arguments; unsigned m_matchGroup = 0; std::map<unsigned, Expression const*>* m_matchGroups = nullptr; }; } -} diff --git a/libyul/optimiser/Substitution.cpp b/libyul/optimiser/Substitution.cpp index 9b3d4c03..bc9efe96 100644 --- a/libyul/optimiser/Substitution.cpp +++ b/libyul/optimiser/Substitution.cpp @@ -20,11 +20,11 @@ #include <libyul/optimiser/Substitution.h> -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; Expression Substitution::translate(Expression const& _expression) { diff --git a/libyul/optimiser/Substitution.h b/libyul/optimiser/Substitution.h index 3cc4b45e..41f73b92 100644 --- a/libyul/optimiser/Substitution.h +++ b/libyul/optimiser/Substitution.h @@ -21,13 +21,10 @@ #pragma once #include <libyul/optimiser/ASTCopier.h> - #include <libyul/YulString.h> #include <map> -namespace dev -{ namespace yul { @@ -47,4 +44,3 @@ private: }; } -} diff --git a/libyul/optimiser/Suite.cpp b/libyul/optimiser/Suite.cpp index 4d6dad45..36f0e1eb 100644 --- a/libyul/optimiser/Suite.cpp +++ b/libyul/optimiser/Suite.cpp @@ -35,21 +35,19 @@ #include <libyul/optimiser/SSATransform.h> #include <libyul/optimiser/RedundantAssignEliminator.h> #include <libyul/optimiser/VarDeclPropagator.h> - -#include <libsolidity/inlineasm/AsmAnalysisInfo.h> -#include <libsolidity/inlineasm/AsmData.h> - -#include <libsolidity/inlineasm/AsmPrinter.h> +#include <libyul/AsmAnalysisInfo.h> +#include <libyul/AsmData.h> +#include <libyul/AsmPrinter.h> #include <libdevcore/CommonData.h> using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; void OptimiserSuite::run( Block& _ast, - solidity::assembly::AsmAnalysisInfo const& _analysisInfo, + AsmAnalysisInfo const& _analysisInfo, set<YulString> const& _externallyUsedIdentifiers ) { diff --git a/libyul/optimiser/Suite.h b/libyul/optimiser/Suite.h index 5b564c56..795326b4 100644 --- a/libyul/optimiser/Suite.h +++ b/libyul/optimiser/Suite.h @@ -20,23 +20,16 @@ #pragma once -#include <libyul/ASTDataForward.h> +#include <libyul/AsmDataForward.h> #include <libyul/YulString.h> #include <set> -namespace dev -{ -namespace solidity -{ -namespace assembly -{ -struct AsmAnalysisInfo; -} -} namespace yul { +struct AsmAnalysisInfo; + /** * Optimiser suite that combines all steps and also provides the settings for the heuristics */ @@ -45,11 +38,10 @@ class OptimiserSuite public: static void run( Block& _ast, - solidity::assembly::AsmAnalysisInfo const& _analysisInfo, + AsmAnalysisInfo const& _analysisInfo, std::set<YulString> const& _externallyUsedIdentifiers = {} ); }; } -} diff --git a/libyul/optimiser/SyntacticalEquality.cpp b/libyul/optimiser/SyntacticalEquality.cpp index 66912383..99ce06e5 100644 --- a/libyul/optimiser/SyntacticalEquality.cpp +++ b/libyul/optimiser/SyntacticalEquality.cpp @@ -21,14 +21,13 @@ #include <libyul/optimiser/SyntacticalEquality.h> #include <libyul/Exceptions.h> - -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> #include <libdevcore/CommonData.h> using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; bool SyntacticalEqualityChecker::equal(Expression const& _e1, Expression const& _e2) { diff --git a/libyul/optimiser/SyntacticalEquality.h b/libyul/optimiser/SyntacticalEquality.h index e9fbebe0..63c51b4f 100644 --- a/libyul/optimiser/SyntacticalEquality.h +++ b/libyul/optimiser/SyntacticalEquality.h @@ -20,12 +20,10 @@ #pragma once -#include <libyul/ASTDataForward.h> +#include <libyul/AsmDataForward.h> #include <vector> -namespace dev -{ namespace yul { @@ -47,4 +45,3 @@ protected: }; } -} diff --git a/libyul/optimiser/UnusedPruner.cpp b/libyul/optimiser/UnusedPruner.cpp index 71e86798..31aead82 100644 --- a/libyul/optimiser/UnusedPruner.cpp +++ b/libyul/optimiser/UnusedPruner.cpp @@ -24,14 +24,13 @@ #include <libyul/optimiser/Semantics.h> #include <libyul/optimiser/Utilities.h> #include <libyul/Exceptions.h> - -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> #include <boost/algorithm/cxx11/none_of.hpp> using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; UnusedPruner::UnusedPruner(Block& _ast, set<YulString> const& _externallyUsedFunctions) { diff --git a/libyul/optimiser/UnusedPruner.h b/libyul/optimiser/UnusedPruner.h index b5b46443..64e02b35 100644 --- a/libyul/optimiser/UnusedPruner.h +++ b/libyul/optimiser/UnusedPruner.h @@ -26,8 +26,6 @@ #include <map> #include <set> -namespace dev -{ namespace yul { @@ -62,4 +60,3 @@ private: }; } -} diff --git a/libyul/optimiser/Utilities.cpp b/libyul/optimiser/Utilities.cpp index df01ed39..b8cdd339 100644 --- a/libyul/optimiser/Utilities.cpp +++ b/libyul/optimiser/Utilities.cpp @@ -20,7 +20,7 @@ #include <libyul/optimiser/Utilities.h> -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> #include <libdevcore/CommonData.h> @@ -28,9 +28,9 @@ using namespace std; using namespace dev; -using namespace dev::yul; +using namespace yul; -void dev::yul::removeEmptyBlocks(Block& _block) +void yul::removeEmptyBlocks(Block& _block) { auto isEmptyBlock = [](Statement const& _st) -> bool { return _st.type() == typeid(Block) && boost::get<Block>(_st).statements.empty(); diff --git a/libyul/optimiser/Utilities.h b/libyul/optimiser/Utilities.h index 5b18a27c..c543b119 100644 --- a/libyul/optimiser/Utilities.h +++ b/libyul/optimiser/Utilities.h @@ -20,10 +20,8 @@ #pragma once -#include <libyul/ASTDataForward.h> +#include <libyul/AsmDataForward.h> -namespace dev -{ namespace yul { @@ -31,4 +29,3 @@ namespace yul void removeEmptyBlocks(Block& _block); } -} diff --git a/libyul/optimiser/VarDeclPropagator.cpp b/libyul/optimiser/VarDeclPropagator.cpp index 537b7020..bf974f44 100644 --- a/libyul/optimiser/VarDeclPropagator.cpp +++ b/libyul/optimiser/VarDeclPropagator.cpp @@ -16,7 +16,7 @@ */ #include <libyul/optimiser/VarDeclPropagator.h> -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> #include <libdevcore/CommonData.h> #include <boost/range/algorithm_ext/erase.hpp> #include <algorithm> @@ -24,10 +24,7 @@ using namespace std; using namespace dev; -using namespace dev::yul; - -using dev::solidity::assembly::TypedName; -using dev::solidity::assembly::TypedNameList; +using namespace yul; void VarDeclPropagator::operator()(Block& _block) { diff --git a/libyul/optimiser/VarDeclPropagator.h b/libyul/optimiser/VarDeclPropagator.h index 4522d23a..1908c214 100644 --- a/libyul/optimiser/VarDeclPropagator.h +++ b/libyul/optimiser/VarDeclPropagator.h @@ -17,16 +17,14 @@ #pragma once -#include <libyul/ASTDataForward.h> +#include <libyul/AsmDataForward.h> #include <libyul/optimiser/ASTWalker.h> #include <libyul/Exceptions.h> -#include <libsolidity/inlineasm/AsmDataForward.h> +#include <libyul/AsmDataForward.h> #include <vector> #include <set> #include <map> -namespace dev -{ namespace yul { @@ -60,4 +58,3 @@ private: }; } -} diff --git a/scripts/bytecodecompare/storebytecode.sh b/scripts/bytecodecompare/storebytecode.sh index ccf6e60e..4208d67f 100755 --- a/scripts/bytecodecompare/storebytecode.sh +++ b/scripts/bytecodecompare/storebytecode.sh @@ -58,7 +58,7 @@ for (var optimize of [false, true]) if (filename !== undefined) { var inputs = {} - inputs[filename] = fs.readFileSync(filename).toString() + inputs[filename] = { content: fs.readFileSync(filename).toString() } var input = { language: 'Solidity', sources: inputs, @@ -68,16 +68,22 @@ for (var optimize of [false, true]) } } var result = JSON.parse(compiler.compile(JSON.stringify(input))) - if (!('contracts' in result) || Object.keys(result['contracts']).length === 0) + if ( + !('contracts' in result) || + Object.keys(result['contracts']).length === 0 || + !result['contracts'][filename] || + Object.keys(result['contracts'][filename]).length === 0 + ) { + // NOTE: do not exit here because this may be run on source which cannot be compiled console.log(filename + ': ERROR') } else { - for (var contractName in result['contracts']) + for (var contractName in result['contracts'][filename]) { - console.log(contractName + ' ' + result['contracts'][contractName].evm.bytecode.object) - console.log(contractName + ' ' + result['contracts'][contractName].metadata) + console.log(filename + ':' + contractName + ' ' + result['contracts'][filename][contractName].evm.bytecode.object) + console.log(filename + ':' + contractName + ' ' + result['contracts'][filename][contractName].metadata) } } } diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index b9f0bf79..b523f052 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -70,6 +70,24 @@ namespace dev namespace solidity { +bool g_hasOutput = false; + +std::ostream& sout() +{ + g_hasOutput = true; + return cout; +} + +std::ostream& serr(bool _used = true) +{ + if (_used) + g_hasOutput = true; + return cerr; +} + +#define cout +#define cerr + static string const g_stdinFileNameStr = "<stdin>"; static string const g_strAbi = "abi"; static string const g_strAllowPaths = "allow-paths"; @@ -181,7 +199,7 @@ static set<string> const g_machineArgs static void version() { - cout << + sout() << "solc, the solidity compiler commandline interface" << endl << "Version: " << @@ -192,9 +210,9 @@ static void version() static void license() { - cout << otherLicenses << endl; + sout() << otherLicenses << endl; // This is a static variable generated by cmake from LICENSE.txt - cout << licenseText << endl; + sout() << licenseText << endl; exit(0); } @@ -230,8 +248,8 @@ void CommandLineInterface::handleBinary(string const& _contract) createFile(m_compiler->filesystemFriendlyName(_contract) + ".bin", objectWithLinkRefsHex(m_compiler->object(_contract))); else { - cout << "Binary: " << endl; - cout << objectWithLinkRefsHex(m_compiler->object(_contract)) << endl; + sout() << "Binary: " << endl; + sout() << objectWithLinkRefsHex(m_compiler->object(_contract)) << endl; } } if (m_args.count(g_argBinaryRuntime)) @@ -240,8 +258,8 @@ void CommandLineInterface::handleBinary(string const& _contract) createFile(m_compiler->filesystemFriendlyName(_contract) + ".bin-runtime", objectWithLinkRefsHex(m_compiler->runtimeObject(_contract))); else { - cout << "Binary of the runtime part: " << endl; - cout << objectWithLinkRefsHex(m_compiler->runtimeObject(_contract)) << endl; + sout() << "Binary of the runtime part: " << endl; + sout() << objectWithLinkRefsHex(m_compiler->runtimeObject(_contract)) << endl; } } } @@ -252,9 +270,9 @@ void CommandLineInterface::handleOpcode(string const& _contract) createFile(m_compiler->filesystemFriendlyName(_contract) + ".opcode", solidity::disassemble(m_compiler->object(_contract).bytecode)); else { - cout << "Opcodes: " << endl; - cout << solidity::disassemble(m_compiler->object(_contract).bytecode); - cout << endl; + sout() << "Opcodes: " << endl; + sout() << solidity::disassemble(m_compiler->object(_contract).bytecode); + sout() << endl; } } @@ -279,7 +297,7 @@ void CommandLineInterface::handleSignatureHashes(string const& _contract) if (m_args.count(g_argOutputDir)) createFile(m_compiler->filesystemFriendlyName(_contract) + ".signatures", out); else - cout << "Function signatures: " << endl << out; + sout() << "Function signatures: " << endl << out; } void CommandLineInterface::handleMetadata(string const& _contract) @@ -291,7 +309,7 @@ void CommandLineInterface::handleMetadata(string const& _contract) if (m_args.count(g_argOutputDir)) createFile(m_compiler->filesystemFriendlyName(_contract) + "_meta.json", data); else - cout << "Metadata: " << endl << data << endl; + sout() << "Metadata: " << endl << data << endl; } void CommandLineInterface::handleABI(string const& _contract) @@ -303,7 +321,7 @@ void CommandLineInterface::handleABI(string const& _contract) if (m_args.count(g_argOutputDir)) createFile(m_compiler->filesystemFriendlyName(_contract) + ".abi", data); else - cout << "Contract JSON ABI " << endl << data << endl; + sout() << "Contract JSON ABI " << endl << data << endl; } void CommandLineInterface::handleNatspec(bool _natspecDev, string const& _contract) @@ -337,8 +355,8 @@ void CommandLineInterface::handleNatspec(bool _natspecDev, string const& _contra createFile(m_compiler->filesystemFriendlyName(_contract) + suffix, output); else { - cout << title << endl; - cout << output << endl; + sout() << title << endl; + sout() << output << endl; } } @@ -347,39 +365,39 @@ void CommandLineInterface::handleNatspec(bool _natspecDev, string const& _contra void CommandLineInterface::handleGasEstimation(string const& _contract) { Json::Value estimates = m_compiler->gasEstimates(_contract); - cout << "Gas estimation:" << endl; + sout() << "Gas estimation:" << endl; if (estimates["creation"].isObject()) { Json::Value creation = estimates["creation"]; - cout << "construction:" << endl; - cout << " " << creation["executionCost"].asString(); - cout << " + " << creation["codeDepositCost"].asString(); - cout << " = " << creation["totalCost"].asString() << endl; + sout() << "construction:" << endl; + sout() << " " << creation["executionCost"].asString(); + sout() << " + " << creation["codeDepositCost"].asString(); + sout() << " = " << creation["totalCost"].asString() << endl; } if (estimates["external"].isObject()) { Json::Value externalFunctions = estimates["external"]; - cout << "external:" << endl; + sout() << "external:" << endl; for (auto const& name: externalFunctions.getMemberNames()) { if (name.empty()) - cout << " fallback:\t"; + sout() << " fallback:\t"; else - cout << " " << name << ":\t"; - cout << externalFunctions[name].asString() << endl; + sout() << " " << name << ":\t"; + sout() << externalFunctions[name].asString() << endl; } } if (estimates["internal"].isObject()) { Json::Value internalFunctions = estimates["internal"]; - cout << "internal:" << endl; + sout() << "internal:" << endl; for (auto const& name: internalFunctions.getMemberNames()) { - cout << " " << name << ":\t"; - cout << internalFunctions[name].asString() << endl; + sout() << " " << name << ":\t"; + sout() << internalFunctions[name].asString() << endl; } } } @@ -401,7 +419,7 @@ bool CommandLineInterface::readInputFilesAndConfigureRemappings() } else { - cerr << "Invalid remapping: \"" << path << "\"." << endl; + serr() << "Invalid remapping: \"" << path << "\"." << endl; return false; } } @@ -414,11 +432,11 @@ bool CommandLineInterface::readInputFilesAndConfigureRemappings() { if (!ignoreMissing) { - cerr << infile << " is not found." << endl; + serr() << infile << " is not found." << endl; return false; } else - cerr << infile << " is not found. Skipping." << endl; + serr() << infile << " is not found. Skipping." << endl; continue; } @@ -427,11 +445,11 @@ bool CommandLineInterface::readInputFilesAndConfigureRemappings() { if (!ignoreMissing) { - cerr << infile << " is not a valid file." << endl; + serr() << infile << " is not a valid file." << endl; return false; } else - cerr << infile << " is not a valid file. Skipping." << endl; + serr() << infile << " is not a valid file. Skipping." << endl; continue; } @@ -445,7 +463,7 @@ bool CommandLineInterface::readInputFilesAndConfigureRemappings() m_sourceCodes[g_stdinFileName] = dev::readStandardInput(); if (m_sourceCodes.size() == 0) { - cerr << "No input files given. If you wish to use the standard input please specify \"-\" explicitly." << endl; + serr() << "No input files given. If you wish to use the standard input please specify \"-\" explicitly." << endl; return false; } @@ -476,7 +494,7 @@ bool CommandLineInterface::parseLibraryOption(string const& _input) auto colon = lib.rfind(':'); if (colon == string::npos) { - cerr << "Colon separator missing in library address specifier \"" << lib << "\"" << endl; + serr() << "Colon separator missing in library address specifier \"" << lib << "\"" << endl; return false; } string libName(lib.begin(), lib.begin() + colon); @@ -487,26 +505,26 @@ bool CommandLineInterface::parseLibraryOption(string const& _input) addrString = addrString.substr(2); if (addrString.empty()) { - cerr << "Empty address provided for library \"" << libName << "\": " << endl; - cerr << "Note that there should not be any whitespace after the colon." << endl; + serr() << "Empty address provided for library \"" << libName << "\": " << endl; + serr() << "Note that there should not be any whitespace after the colon." << endl; return false; } else if (addrString.length() != 40) { - cerr << "Invalid length for address for library \"" << libName << "\": " << addrString.length() << " instead of 40 characters." << endl; + serr() << "Invalid length for address for library \"" << libName << "\": " << addrString.length() << " instead of 40 characters." << endl; return false; } if (!passesAddressChecksum(addrString, false)) { - cerr << "Invalid checksum on address for library \"" << libName << "\": " << addrString << endl; - cerr << "The correct checksum is " << dev::getChecksummedAddress(addrString) << endl; + serr() << "Invalid checksum on address for library \"" << libName << "\": " << addrString << endl; + serr() << "The correct checksum is " << dev::getChecksummedAddress(addrString) << endl; return false; } bytes binAddr = fromHex(addrString); h160 address(binAddr, h160::AlignRight); if (binAddr.size() > 20 || address == h160()) { - cerr << "Invalid address for library \"" << libName << "\": " << addrString << endl; + serr() << "Invalid address for library \"" << libName << "\": " << addrString << endl; return false; } m_libraries[libName] = address; @@ -526,7 +544,7 @@ void CommandLineInterface::createFile(string const& _fileName, string const& _da string pathName = (p / _fileName).string(); if (fs::exists(pathName) && !m_args.count(g_strOverwrite)) { - cerr << "Refusing to overwrite existing file \"" << pathName << "\" (use --overwrite to force)." << endl; + serr() << "Refusing to overwrite existing file \"" << pathName << "\" (use --overwrite to force)." << endl; m_error = true; return; } @@ -543,6 +561,8 @@ void CommandLineInterface::createJson(string const& _fileName, string const& _js bool CommandLineInterface::parseArguments(int _argc, char** _argv) { + g_hasOutput = false; + // Declare the supported options. po::options_description desc(R"(solc, the Solidity commandline compiler. @@ -667,13 +687,13 @@ Allowed options)", } catch (po::error const& _exception) { - cerr << _exception.what() << endl; + serr() << _exception.what() << endl; return false; } if (m_args.count(g_argHelp) || (isatty(fileno(stdin)) && _argc == 1)) { - cout << desc; + sout() << desc; return false; } @@ -695,7 +715,7 @@ Allowed options)", for (string const& item: boost::split(requests, m_args[g_argCombinedJson].as<string>(), boost::is_any_of(","))) if (!g_combinedJsonArgs.count(item)) { - cerr << "Invalid option to --combined-json: " << item << endl; + serr() << "Invalid option to --combined-json: " << item << endl; return false; } } @@ -759,9 +779,7 @@ bool CommandLineInterface::processInput() // path comparison in later parts of the code, so we need to strip // it. if (filesystem_path.filename() == ".") - { filesystem_path.remove_filename(); - } m_allowedDirectories.push_back(filesystem_path); } } @@ -770,7 +788,7 @@ bool CommandLineInterface::processInput() { string input = dev::readStandardInput(); StandardCompiler compiler(fileReader); - cout << compiler.compile(input) << endl; + sout() << compiler.compile(input) << endl; return true; } @@ -788,7 +806,7 @@ bool CommandLineInterface::processInput() boost::optional<EVMVersion> versionOption = EVMVersion::fromString(versionOptionStr); if (!versionOption) { - cerr << "Invalid option for --evm-version: " << versionOptionStr << endl; + serr() << "Invalid option for --evm-version: " << versionOptionStr << endl; return false; } m_evmVersion = *versionOption; @@ -813,7 +831,7 @@ bool CommandLineInterface::processInput() targetMachine = Machine::eWasm; else { - cerr << "Invalid option for --machine: " << machine << endl; + serr() << "Invalid option for --machine: " << machine << endl; return false; } } @@ -829,7 +847,7 @@ bool CommandLineInterface::processInput() m_compiler.reset(new CompilerStack(fileReader)); auto scannerFromSourceName = [&](string const& _sourceName) -> Scanner const& { return m_compiler->scanner(_sourceName); }; - SourceReferenceFormatter formatter(cerr, scannerFromSourceName); + SourceReferenceFormatter formatter(serr(false), scannerFromSourceName); try { @@ -850,48 +868,55 @@ bool CommandLineInterface::processInput() bool successful = m_compiler->compile(); for (auto const& error: m_compiler->errors()) + { + g_hasOutput = true; formatter.printExceptionInformation( *error, (error->type() == Error::Type::Warning) ? "Warning" : "Error" ); + } if (!successful) return false; } catch (CompilerError const& _exception) { + g_hasOutput = true; formatter.printExceptionInformation(_exception, "Compiler error"); return false; } catch (InternalCompilerError const& _exception) { - cerr << "Internal compiler error during compilation:" << endl + serr() << "Internal compiler error during compilation:" << endl << boost::diagnostic_information(_exception); return false; } catch (UnimplementedFeatureError const& _exception) { - cerr << "Unimplemented feature:" << endl + serr() << "Unimplemented feature:" << endl << boost::diagnostic_information(_exception); return false; } catch (Error const& _error) { if (_error.type() == Error::Type::DocstringParsingError) - cerr << "Documentation parsing error: " << *boost::get_error_info<errinfo_comment>(_error) << endl; + serr() << "Documentation parsing error: " << *boost::get_error_info<errinfo_comment>(_error) << endl; else + { + g_hasOutput = true; formatter.printExceptionInformation(_error, _error.typeName()); + } return false; } catch (Exception const& _exception) { - cerr << "Exception during compilation: " << boost::diagnostic_information(_exception) << endl; + serr() << "Exception during compilation: " << boost::diagnostic_information(_exception) << endl; return false; } catch (...) { - cerr << "Unknown exception during compilation." << endl; + serr() << "Unknown exception during compilation." << endl; return false; } @@ -972,7 +997,7 @@ void CommandLineInterface::handleCombinedJSON() if (m_args.count(g_argOutputDir)) createJson("combined", json); else - cout << json << endl; + sout() << json << endl; } void CommandLineInterface::handleAst(string const& _argStr) @@ -1028,10 +1053,10 @@ void CommandLineInterface::handleAst(string const& _argStr) } else { - cout << title << endl << endl; + sout() << title << endl << endl; for (auto const& sourceCode: m_sourceCodes) { - cout << endl << "======= " << sourceCode.first << " =======" << endl; + sout() << endl << "======= " << sourceCode.first << " =======" << endl; if (_argStr == g_argAst) { ASTPrinter printer( @@ -1039,10 +1064,10 @@ void CommandLineInterface::handleAst(string const& _argStr) sourceCode.second, gasCosts ); - printer.print(cout); + printer.print(sout()); } else - ASTJsonConverter(legacyFormat, m_compiler->sourceIndices()).print(cout, m_compiler->ast(sourceCode.first)); + ASTJsonConverter(legacyFormat, m_compiler->sourceIndices()).print(sout(), m_compiler->ast(sourceCode.first)); } } } @@ -1090,7 +1115,7 @@ bool CommandLineInterface::link() if (it == end) break; if (end - it < placeholderSize) { - cerr << "Error in binary object file " << src.first << " at position " << (end - src.second.begin()) << endl; + serr() << "Error in binary object file " << src.first << " at position " << (end - src.second.begin()) << endl; return false; } @@ -1101,7 +1126,7 @@ bool CommandLineInterface::link() copy(hexStr.begin(), hexStr.end(), it); } else - cerr << "Reference \"" << name << "\" in file \"" << src.first << "\" still unresolved." << endl; + serr() << "Reference \"" << name << "\" in file \"" << src.first << "\" still unresolved." << endl; it += placeholderSize; } // Remove hints for resolved libraries. @@ -1117,17 +1142,18 @@ void CommandLineInterface::writeLinkedFiles() { for (auto const& src: m_sourceCodes) if (src.first == g_stdinFileName) - cout << src.second << endl; + sout() << src.second << endl; else { ofstream outFile(src.first); outFile << src.second; if (!outFile) { - cerr << "Could not write to file " << src.first << ". Aborting." << endl; + serr() << "Could not write to file " << src.first << ". Aborting." << endl; return; } } + sout() << "Linking completed." << endl; } string CommandLineInterface::libraryPlaceholderHint(string const& _libraryName) @@ -1164,12 +1190,12 @@ bool CommandLineInterface::assemble( } catch (Exception const& _exception) { - cerr << "Exception in assembler: " << boost::diagnostic_information(_exception) << endl; + serr() << "Exception in assembler: " << boost::diagnostic_information(_exception) << endl; return false; } catch (...) { - cerr << "Unknown exception in assembler." << endl; + serr() << "Unknown exception in assembler." << endl; return false; } } @@ -1178,13 +1204,16 @@ bool CommandLineInterface::assemble( { auto const& stack = sourceAndStack.second; auto scannerFromSourceName = [&](string const&) -> Scanner const& { return stack.scanner(); }; - SourceReferenceFormatter formatter(cerr, scannerFromSourceName); + SourceReferenceFormatter formatter(serr(false), scannerFromSourceName); for (auto const& error: stack.errors()) + { + g_hasOutput = true; formatter.printExceptionInformation( *error, (error->type() == Error::Type::Warning) ? "Warning" : "Error" ); + } if (!Error::containsOnlyWarnings(stack.errors())) successful = false; } @@ -1198,11 +1227,11 @@ bool CommandLineInterface::assemble( _targetMachine == AssemblyStack::Machine::EVM ? "EVM" : _targetMachine == AssemblyStack::Machine::EVM15 ? "EVM 1.5" : "eWasm"; - cout << endl << "======= " << src.first << " (" << machine << ") =======" << endl; + sout() << endl << "======= " << src.first << " (" << machine << ") =======" << endl; AssemblyStack& stack = assemblyStacks[src.first]; - cout << endl << "Pretty printed source:" << endl; - cout << stack.print() << endl; + sout() << endl << "Pretty printed source:" << endl; + sout() << stack.print() << endl; MachineAssemblyObject object; try @@ -1211,26 +1240,26 @@ bool CommandLineInterface::assemble( } catch (Exception const& _exception) { - cerr << "Exception while assembling: " << boost::diagnostic_information(_exception) << endl; + serr() << "Exception while assembling: " << boost::diagnostic_information(_exception) << endl; return false; } catch (...) { - cerr << "Unknown exception while assembling." << endl; + serr() << "Unknown exception while assembling." << endl; return false; } - cout << endl << "Binary representation:" << endl; + sout() << endl << "Binary representation:" << endl; if (object.bytecode) - cout << object.bytecode->toHex() << endl; + sout() << object.bytecode->toHex() << endl; else - cerr << "No binary representation found." << endl; + serr() << "No binary representation found." << endl; - cout << endl << "Text representation:" << endl; + sout() << endl << "Text representation:" << endl; if (!object.assembly.empty()) - cout << object.assembly << endl; + sout() << object.assembly << endl; else - cerr << "No text representation found." << endl; + serr() << "No text representation found." << endl; } return true; @@ -1249,7 +1278,7 @@ void CommandLineInterface::outputCompilationResults() for (string const& contract: contracts) { if (needsHumanTargetedStdout(m_args)) - cout << endl << "======= " << contract << " =======" << endl; + sout() << endl << "======= " << contract << " =======" << endl; // do we need EVM assembly? if (m_args.count(g_argAsm) || m_args.count(g_argAsmJson)) @@ -1266,7 +1295,7 @@ void CommandLineInterface::outputCompilationResults() } else { - cout << "EVM assembly:" << endl << ret << endl; + sout() << "EVM assembly:" << endl << ret << endl; } } @@ -1280,6 +1309,14 @@ void CommandLineInterface::outputCompilationResults() handleNatspec(true, contract); handleNatspec(false, contract); } // end of contracts iteration + + if (!g_hasOutput) + { + if (m_args.count(g_argOutputDir)) + sout() << "Compiler run successful. Artifact(s) can be found in directory " << m_args.at(g_argOutputDir).as<string>() << "." << endl; + else + serr() << "Compiler run successful, no output requested." << endl; + } } } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index acfc7d00..10b78bdc 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -27,7 +27,7 @@ add_executable(soltest ${sources} ${headers} ${liblll_sources} ${liblll_headers} ${libsolidity_sources} ${libsolidity_headers} ) -target_link_libraries(soltest PRIVATE libsolc solidity evmasm devcore ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES}) +target_link_libraries(soltest PRIVATE libsolc yul solidity evmasm devcore ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES}) if (LLL) target_link_libraries(soltest PRIVATE lll) diff --git a/test/libsolidity/TestCase.cpp b/test/TestCase.cpp index 17972269..e9e2c9f2 100644 --- a/test/libsolidity/TestCase.cpp +++ b/test/TestCase.cpp @@ -15,7 +15,7 @@ along with solidity. If not, see <http://www.gnu.org/licenses/>. */ -#include <test/libsolidity/TestCase.h> +#include <test/TestCase.h> #include <boost/algorithm/string.hpp> #include <boost/algorithm/string/predicate.hpp> diff --git a/test/libsolidity/TestCase.h b/test/TestCase.h index 3c05ae4e..3c05ae4e 100644 --- a/test/libsolidity/TestCase.h +++ b/test/TestCase.h diff --git a/test/boostTest.cpp b/test/boostTest.cpp index 5352ef85..7cb0c143 100644 --- a/test/boostTest.cpp +++ b/test/boostTest.cpp @@ -38,6 +38,7 @@ #include <test/Options.h> #include <test/libsolidity/ASTJSONTest.h> #include <test/libsolidity/SyntaxTest.h> +#include <test/libsolidity/SMTCheckerJSONTest.h> #include <test/libyul/YulOptimizerTest.h> #include <boost/algorithm/string.hpp> @@ -143,15 +144,24 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] ) master, dev::test::Options::get().testPath / "libyul", "yulOptimizerTests", - dev::yul::test::YulOptimizerTest::create + yul::test::YulOptimizerTest::create ) > 0, "no Yul Optimizer tests found"); if (!dev::test::Options::get().disableSMT) + { solAssert(registerTests( master, dev::test::Options::get().testPath / "libsolidity", "smtCheckerTests", SyntaxTest::create ) > 0, "no SMT checker tests found"); + + solAssert(registerTests( + master, + dev::test::Options::get().testPath / "libsolidity", + "smtCheckerTestsJSON", + SMTCheckerTest::create + ) > 0, "no SMT checker JSON tests found"); + } if (dev::test::Options::get().disableIPC) { for (auto suite: { diff --git a/test/libsolidity/ASTJSONTest.h b/test/libsolidity/ASTJSONTest.h index 9760ef66..dcdaf221 100644 --- a/test/libsolidity/ASTJSONTest.h +++ b/test/libsolidity/ASTJSONTest.h @@ -18,7 +18,7 @@ #pragma once #include <test/libsolidity/FormattedScope.h> -#include <test/libsolidity/TestCase.h> +#include <test/TestCase.h> #include <iosfwd> #include <string> diff --git a/test/libsolidity/SMTChecker.cpp b/test/libsolidity/SMTChecker.cpp index 13fcc5b4..a49618bd 100644 --- a/test/libsolidity/SMTChecker.cpp +++ b/test/libsolidity/SMTChecker.cpp @@ -56,599 +56,6 @@ protected: BOOST_FIXTURE_TEST_SUITE(SMTChecker, SMTCheckerFramework) -BOOST_AUTO_TEST_CASE(smoke_test) -{ - string text = R"( - contract C { } - )"; - CHECK_SUCCESS_NO_WARNINGS(text); -} - -BOOST_AUTO_TEST_CASE(simple_overflow) -{ - string text = R"( - contract C { - function f(uint a, uint b) public pure returns (uint) { return a + b; } - } - )"; - CHECK_WARNING(text, "Overflow (resulting value larger than"); -} - -BOOST_AUTO_TEST_CASE(warn_on_typecast) -{ - string text = R"( - contract C { - function f() public pure returns (uint) { - return uint8(1); - } - } - )"; - CHECK_WARNING(text, "Assertion checker does not yet implement this expression."); -} - -BOOST_AUTO_TEST_CASE(warn_on_struct) -{ - string text = R"( - pragma experimental ABIEncoderV2; - contract C { - struct A { uint a; uint b; } - function f() public pure returns (A memory) { - return A({ a: 1, b: 2 }); - } - } - )"; - CHECK_WARNING_ALLOW_MULTI(text, (vector<string>{ - "Experimental feature", - "Assertion checker does not yet implement this expression.", - "Assertion checker does not yet support the type of this variable." - })); -} - -BOOST_AUTO_TEST_CASE(simple_assert) -{ - string text = R"( - contract C { - function f(uint a) public pure { assert(a == 2); } - } - )"; - CHECK_WARNING(text, "Assertion violation happens here"); -} - -BOOST_AUTO_TEST_CASE(simple_assert_with_require) -{ - string text = R"( - contract C { - function f(uint a) public pure { require(a < 10); assert(a < 20); } - } - )"; - CHECK_SUCCESS_NO_WARNINGS(text); -} - -BOOST_AUTO_TEST_CASE(assignment_in_declaration) -{ - string text = R"( - contract C { - function f() public pure { uint a = 2; assert(a == 2); } - } - )"; - CHECK_SUCCESS_NO_WARNINGS(text); -} - -BOOST_AUTO_TEST_CASE(branches_merge_variables) -{ - // Branch does not touch variable a - string text = R"( - contract C { - function f(uint x) public pure { - uint a = 3; - if (x > 10) { - } - assert(a == 3); - } - } - )"; - CHECK_SUCCESS_NO_WARNINGS(text); - // Positive branch touches variable a, but assertion should still hold. - text = R"( - contract C { - function f(uint x) public pure { - uint a = 3; - if (x > 10) { - a = 3; - } - assert(a == 3); - } - } - )"; - CHECK_SUCCESS_NO_WARNINGS(text); - // Negative branch touches variable a, but assertion should still hold. - text = R"( - contract C { - function f(uint x) public pure { - uint a = 3; - if (x > 10) { - } else { - a = 3; - } - assert(a == 3); - } - } - )"; - CHECK_SUCCESS_NO_WARNINGS(text); - // Variable is not merged, if it is only read. - text = R"( - contract C { - function f(uint x) public pure { - uint a = 3; - if (x > 10) { - assert(a == 3); - } else { - assert(a == 3); - } - assert(a == 3); - } - } - )"; - CHECK_SUCCESS_NO_WARNINGS(text); - // Variable is reset in both branches - text = R"( - contract C { - function f(uint x) public pure { - uint a = 2; - if (x > 10) { - a = 3; - } else { - a = 3; - } - assert(a == 3); - } - } - )"; - CHECK_SUCCESS_NO_WARNINGS(text); - // Variable is reset in both branches - text = R"( - contract C { - function f(uint x) public pure { - uint a = 2; - if (x > 10) { - a = 3; - } else { - a = 4; - } - assert(a >= 3); - } - } - )"; - CHECK_SUCCESS_NO_WARNINGS(text); -} - -BOOST_AUTO_TEST_CASE(branches_assert_condition) -{ - string text = R"( - contract C { - function f(uint x) public pure { - if (x > 10) { - assert(x > 9); - } - else - { - assert(x < 11); - } - } - } - )"; - CHECK_SUCCESS_NO_WARNINGS(text); - text = R"( - contract C { - function f(uint x) public pure { - if (x > 10) { - assert(x > 9); - } - else if (x > 2) - { - assert(x <= 10 && x > 2); - } - else - { - assert(0 <= x && x <= 2); - } - } - } - )"; - CHECK_SUCCESS_NO_WARNINGS(text); -} - -BOOST_AUTO_TEST_CASE(ways_to_merge_variables) -{ - string text = R"( - contract C { - function f(uint x) public pure { - uint a = 3; - if (x > 10) { - a++; - } - assert(a == 3); - } - } - )"; - CHECK_WARNING(text, "Assertion violation happens here"); - text = R"( - contract C { - function f(uint x) public pure { - uint a = 3; - if (x > 10) { - ++a; - } - assert(a == 3); - } - } - )"; - CHECK_WARNING(text, "Assertion violation happens here"); - text = R"( - contract C { - function f(uint x) public pure { - uint a = 3; - if (x > 10) { - a = 5; - } - assert(a == 3); - } - } - )"; - CHECK_WARNING(text, "Assertion violation happens here"); -} - -BOOST_AUTO_TEST_CASE(bool_simple) -{ - string text = R"( - contract C { - function f(bool x) public pure { - assert(x); - } - } - )"; - CHECK_WARNING(text, "Assertion violation happens here"); - text = R"( - contract C { - function f(bool x, bool y) public pure { - assert(x == y); - } - } - )"; - CHECK_WARNING(text, "Assertion violation happens here"); - text = R"( - contract C { - function f(bool x, bool y) public pure { - bool z = x || y; - assert(!(x && y) || z); - } - } - )"; - CHECK_SUCCESS_NO_WARNINGS(text); - text = R"( - contract C { - function f(bool x) public pure { - if (x) { - assert(x); - } else { - assert(!x); - } - } - } - )"; - CHECK_SUCCESS_NO_WARNINGS(text); - text = R"( - contract C { - function f(bool x) public pure { - bool y = x; - assert(x == y); - } - } - )"; - CHECK_SUCCESS_NO_WARNINGS(text); - text = R"( - contract C { - function f(bool x) public pure { - require(x); - bool y; - y = false; - assert(x || y); - } - } - )"; - CHECK_SUCCESS_NO_WARNINGS(text); -} - -BOOST_AUTO_TEST_CASE(bool_int_mixed) -{ - string text = R"( - contract C { - function f(bool x) public pure { - uint a; - if (x) - a = 1; - assert(!x || a > 0); - } - } - )"; - CHECK_SUCCESS_NO_WARNINGS(text); - text = R"( - contract C { - function f(bool x, uint a) public pure { - require(!x || a > 0); - uint b = a; - assert(!x || b > 0); - } - } - )"; - CHECK_SUCCESS_NO_WARNINGS(text); - text = R"( - contract C { - function f(bool x, bool y) public pure { - uint a; - if (x) { - if (y) { - a = 0; - } else { - a = 1; - } - } else { - if (y) { - a = 1; - } else { - a = 0; - } - } - bool xor_x_y = (x && !y) || (!x && y); - assert(!xor_x_y || a > 0); - } - } - )"; - CHECK_SUCCESS_NO_WARNINGS(text); -} - -BOOST_AUTO_TEST_CASE(storage_value_vars) -{ - string text = R"( - contract C - { - address a; - bool b; - uint c; - function f(uint x) public { - if (x == 0) - { - a = 0x0000000000000000000000000000000000000100; - b = true; - } - else - { - a = 0x0000000000000000000000000000000000000200; - b = false; - } - assert(a > 0x0000000000000000000000000000000000000000 && b); - } - } - )"; - CHECK_WARNING(text, "Assertion violation happens here"); - text = R"( - contract C - { - address a; - bool b; - uint c; - function f() public view { - assert(c > 0); - } - } - )"; - CHECK_WARNING(text, "Assertion violation happens here"); - text = R"( - contract C - { - function f(uint x) public { - if (x == 0) - { - a = 0x0000000000000000000000000000000000000100; - b = true; - } - else - { - a = 0x0000000000000000000000000000000000000200; - b = false; - } - assert(b == (a < 0x0000000000000000000000000000000000000200)); - } - - function g() public view { - require(a < 0x0000000000000000000000000000000000000100); - assert(c >= 0); - } - address a; - bool b; - uint c; - } - )"; - CHECK_SUCCESS_NO_WARNINGS(text); - text = R"( - contract C - { - function f() public view { - assert(c > 0); - } - uint c; - } - )"; - CHECK_WARNING(text, "Assertion violation happens here"); - -} - -BOOST_AUTO_TEST_CASE(while_loop_simple) -{ - // Check that variables are cleared - string text = R"( - contract C { - function f(uint x) public pure { - x = 2; - while (x > 1) { - x = 2; - } - assert(x == 2); - } - } - )"; - CHECK_WARNING(text, "Assertion violation happens here"); - // Check that condition is assumed. - text = R"( - contract C { - function f(uint x) public pure { - while (x == 2) { - assert(x == 2); - } - } - } - )"; - CHECK_SUCCESS_NO_WARNINGS(text); - // Check that condition is not assumed after the body anymore - text = R"( - contract C { - function f(uint x) public pure { - while (x == 2) { - } - assert(x == 2); - } - } - )"; - CHECK_WARNING(text, "Assertion violation happens here"); - // Check that negation of condition is not assumed after the body anymore - text = R"( - contract C { - function f(uint x) public pure { - while (x == 2) { - } - assert(x != 2); - } - } - )"; - CHECK_WARNING(text, "Assertion violation happens here"); - // Check that side-effects of condition are taken into account - text = R"( - contract C { - function f(uint x, uint y) public pure { - x = 7; - while ((x = y) > 0) { - } - assert(x == 7); - } - } - )"; - CHECK_WARNING(text, "Assertion violation happens here"); -} - -BOOST_AUTO_TEST_CASE(constant_condition) -{ - string text = R"( - contract C { - function f(uint x) public pure { - if (x >= 0) { revert(); } - } - } - )"; - CHECK_WARNING_ALLOW_MULTI(text, (vector<string>{ - "Condition is always true", - "Assertion checker does not yet implement this type of function call" - })); - text = R"( - contract C { - function f(uint x) public pure { - if (x >= 10) { if (x < 10) { revert(); } } - } - } - )"; - CHECK_WARNING_ALLOW_MULTI(text, (vector<string>{ - "Condition is always false", - "Assertion checker does not yet implement this type of function call" - })); - // a plain literal constant is fine - text = R"( - contract C { - function f(uint) public pure { - if (true) { revert(); } - } - } - )"; - CHECK_WARNING(text, "Assertion checker does not yet implement this type of function call"); -} - - -BOOST_AUTO_TEST_CASE(for_loop) -{ - string text = R"( - contract C { - function f(uint x) public pure { - require(x == 2); - for (;;) {} - assert(x == 2); - } - } - )"; - CHECK_SUCCESS_NO_WARNINGS(text); - text = R"( - contract C { - function f(uint x) public pure { - for (; x == 2; ) { - assert(x == 2); - } - } - } - )"; - CHECK_SUCCESS_NO_WARNINGS(text); - text = R"( - contract C { - function f(uint x) public pure { - for (uint y = 2; x < 10; ) { - assert(y == 2); - } - } - } - )"; - CHECK_SUCCESS_NO_WARNINGS(text); - text = R"( - contract C { - function f(uint x) public pure { - for (uint y = 2; x < 10; y = 3) { - assert(y == 2); - } - } - } - )"; - CHECK_WARNING(text, "Assertion violation"); - text = R"( - contract C { - function f(uint x) public pure { - uint y; - for (y = 2; x < 10; ) { - y = 3; - } - assert(y == 3); - } - } - )"; - CHECK_WARNING(text, "Assertion violation"); - text = R"( - contract C { - function f(uint x) public pure { - uint y; - for (y = 2; x < 10; ) { - y = 3; - } - assert(y == 2); - } - } - )"; - CHECK_WARNING(text, "Assertion violation"); -} - BOOST_AUTO_TEST_CASE(division) { string text = R"( diff --git a/test/libsolidity/SMTCheckerJSONTest.cpp b/test/libsolidity/SMTCheckerJSONTest.cpp new file mode 100644 index 00000000..6e1329a9 --- /dev/null +++ b/test/libsolidity/SMTCheckerJSONTest.cpp @@ -0,0 +1,128 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <test/libsolidity/SMTCheckerJSONTest.h> +#include <test/Options.h> +#include <libsolidity/interface/StandardCompiler.h> +#include <libdevcore/JSON.h> +#include <boost/algorithm/string.hpp> +#include <boost/algorithm/string/join.hpp> +#include <boost/algorithm/string/predicate.hpp> +#include <boost/throw_exception.hpp> +#include <fstream> +#include <memory> +#include <stdexcept> +#include <sstream> + +using namespace dev; +using namespace solidity; +using namespace dev::solidity::test; +using namespace dev::solidity::test::formatting; +using namespace std; +using namespace boost::unit_test; + +SMTCheckerTest::SMTCheckerTest(string const& _filename) +: SyntaxTest(_filename) +{ + BOOST_REQUIRE_MESSAGE(boost::algorithm::ends_with(_filename, ".sol"), "Invalid test contract file name: \"" + _filename + "\"."); + + string jsonFilename = _filename.substr(0, _filename.size() - 4) + ".json"; + BOOST_CHECK(jsonParseFile(jsonFilename, m_smtResponses)); + BOOST_CHECK(m_smtResponses.isObject()); +} + +bool SMTCheckerTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted) +{ + StandardCompiler compiler; + + // Run the compiler and retrieve the smtlib2queries (1st run) + string versionPragma = "pragma solidity >=0.0;\n"; + Json::Value input = buildJson(versionPragma); + Json::Value result = compiler.compile(input); + + // This is the list of query hashes requested by the 1st run + vector<string> outHashes = hashesFromJson(result, "auxiliaryInputRequested", "smtlib2queries"); + + // This is the list of responses provided in the test + string auxInput("auxiliaryInput"); + BOOST_CHECK(m_smtResponses.isMember(auxInput)); + vector<string> inHashes = hashesFromJson(m_smtResponses, auxInput, "smtlib2responses"); + + // Ensure that the provided list matches the requested one + BOOST_CHECK_MESSAGE( + outHashes == inHashes, + "SMT query hashes differ: " + boost::algorithm::join(outHashes, ", ") + " x " + boost::algorithm::join(inHashes, ", ") + ); + + // Rerun the compiler with the provided hashed (2nd run) + input[auxInput] = m_smtResponses[auxInput]; + Json::Value endResult = compiler.compile(input); + + BOOST_CHECK(endResult.isMember("errors")); + Json::Value const& errors = endResult["errors"]; + for (auto const& error: errors) + { + BOOST_CHECK(error.isMember("type") && error["type"].isString()); + BOOST_CHECK(error.isMember("message") && error["message"].isString()); + if (!error.isMember("sourceLocation")) + continue; + Json::Value const& location = error["sourceLocation"]; + BOOST_CHECK(location.isMember("start") && location["start"].isInt()); + BOOST_CHECK(location.isMember("end") && location["end"].isInt()); + int start = location["start"].asInt(); + int end = location["end"].asInt(); + if (start >= static_cast<int>(versionPragma.size())) + start -= versionPragma.size(); + if (end >= static_cast<int>(versionPragma.size())) + end -= versionPragma.size(); + m_errorList.emplace_back(SyntaxTestError{ + error["type"].asString(), + error["message"].asString(), + start, + end + }); + } + + return printExpectationAndError(_stream, _linePrefix, _formatted); +} + +vector<string> SMTCheckerTest::hashesFromJson(Json::Value const& _jsonObj, string const& _auxInput, string const& _smtlib) +{ + vector<string> hashes; + Json::Value const& auxInputs = _jsonObj[_auxInput]; + if (!!auxInputs) + { + Json::Value const& smtlib = auxInputs[_smtlib]; + if (!!smtlib) + for (auto const& hashString: smtlib.getMemberNames()) + hashes.push_back(hashString); + } + return hashes; +} + +Json::Value SMTCheckerTest::buildJson(string const& _extra) +{ + string language = "\"language\": \"Solidity\""; + string sourceName = "\"A\""; + string sourceContent = "\"" + _extra + m_source + "\""; + string sourceObj = "{ \"content\": " + sourceContent + "}"; + string sources = " \"sources\": { " + sourceName + ": " + sourceObj + "}"; + string input = "{" + language + ", " + sources + "}"; + Json::Value source; + BOOST_REQUIRE(jsonParse(input, source)); + return source; +} diff --git a/test/libsolidity/SMTCheckerJSONTest.h b/test/libsolidity/SMTCheckerJSONTest.h new file mode 100644 index 00000000..cf41acac --- /dev/null +++ b/test/libsolidity/SMTCheckerJSONTest.h @@ -0,0 +1,53 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see <http://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <test/libsolidity/SyntaxTest.h> + +#include <libdevcore/JSON.h> + +#include <string> + +namespace dev +{ +namespace solidity +{ +namespace test +{ + +class SMTCheckerTest: public SyntaxTest +{ +public: + static std::unique_ptr<TestCase> create(std::string const& _filename) + { + return std::unique_ptr<TestCase>(new SMTCheckerTest(_filename)); + } + SMTCheckerTest(std::string const& _filename); + + bool run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override; + +private: + std::vector<std::string> hashesFromJson(Json::Value const& _jsonObj, std::string const& _auxInput, std::string const& _smtlib); + Json::Value buildJson(std::string const& _extra); + + Json::Value m_smtResponses; +}; + +} +} +} diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 041f29a8..e591432a 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -9388,6 +9388,25 @@ BOOST_AUTO_TEST_CASE(using_for_by_name) ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(6 * 7))); } +BOOST_AUTO_TEST_CASE(bound_function_in_function) +{ + char const* sourceCode = R"( + library L { + function g(function() internal returns (uint) _t) internal returns (uint) { return _t(); } + } + contract C { + using L for *; + function f() public returns (uint) { + return t.g(); + } + function t() public pure returns (uint) { return 7; } + } + )"; + compileAndRun(sourceCode, 0, "L"); + compileAndRun(sourceCode, 0, "C", bytes(), map<string, Address>{{"L", m_contractAddress}}); + ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7))); +} + BOOST_AUTO_TEST_CASE(bound_function_in_var) { char const* sourceCode = R"( diff --git a/test/libsolidity/SyntaxTest.cpp b/test/libsolidity/SyntaxTest.cpp index 45d32b55..c47ea599 100644 --- a/test/libsolidity/SyntaxTest.cpp +++ b/test/libsolidity/SyntaxTest.cpp @@ -92,6 +92,11 @@ bool SyntaxTest::run(ostream& _stream, string const& _linePrefix, bool const _fo }); } + return printExpectationAndError(_stream, _linePrefix, _formatted); +} + +bool SyntaxTest::printExpectationAndError(ostream& _stream, string const& _linePrefix, bool const _formatted) +{ if (m_expectations != m_errorList) { string nextIndentLevel = _linePrefix + " "; diff --git a/test/libsolidity/SyntaxTest.h b/test/libsolidity/SyntaxTest.h index 0f151e66..12c14087 100644 --- a/test/libsolidity/SyntaxTest.h +++ b/test/libsolidity/SyntaxTest.h @@ -19,7 +19,7 @@ #include <test/libsolidity/AnalysisFramework.h> #include <test/libsolidity/FormattedScope.h> -#include <test/libsolidity/TestCase.h> +#include <test/TestCase.h> #include <liblangutil/Exceptions.h> #include <iosfwd> @@ -67,7 +67,7 @@ public: } static std::string errorMessage(Exception const& _e); -private: +protected: static void printErrorList( std::ostream& _stream, std::vector<SyntaxTestError> const& _errors, @@ -75,6 +75,8 @@ private: bool const _formatted = false ); + virtual bool printExpectationAndError(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false); + static std::vector<SyntaxTestError> parseExpectations(std::istream& _stream); std::string m_source; diff --git a/test/libsolidity/smtCheckerTests/complex/warn_on_struct.sol b/test/libsolidity/smtCheckerTests/complex/warn_on_struct.sol new file mode 100644 index 00000000..6d9afe7c --- /dev/null +++ b/test/libsolidity/smtCheckerTests/complex/warn_on_struct.sol @@ -0,0 +1,14 @@ +pragma experimental SMTChecker; + +contract C { + struct A { uint a; uint b; } + function f() public pure returns (uint) { + A memory a = A({ a: 1, b: 2 }); + } +} +// ---- +// Warning: (133-143): Unused local variable. +// Warning: (133-143): Assertion checker does not yet support the type of this variable. +// Warning: (146-163): Assertion checker does not yet implement this expression. +// Warning: (146-163): Internal error: Expression undefined for SMT solver. +// Warning: (146-163): Assertion checker does not yet implement this type. diff --git a/test/libsolidity/smtCheckerTests/complex/warn_on_typecast.sol b/test/libsolidity/smtCheckerTests/complex/warn_on_typecast.sol new file mode 100644 index 00000000..be785414 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/complex/warn_on_typecast.sol @@ -0,0 +1,8 @@ +pragma experimental SMTChecker; +contract C { + function f() public pure returns (uint) { + return uint8(1); + } +} +// ---- +// Warning: (106-114): Assertion checker does not yet implement this expression. diff --git a/test/libsolidity/smtCheckerTests/control_flow/assignment_in_declaration.sol b/test/libsolidity/smtCheckerTests/control_flow/assignment_in_declaration.sol new file mode 100644 index 00000000..0c701672 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/control_flow/assignment_in_declaration.sol @@ -0,0 +1,4 @@ +pragma experimental SMTChecker; +contract C { + function f() public pure { uint a = 2; assert(a == 2); } +} diff --git a/test/libsolidity/smtCheckerTests/control_flow/branches_assert_condition_1.sol b/test/libsolidity/smtCheckerTests/control_flow/branches_assert_condition_1.sol new file mode 100644 index 00000000..64f6e012 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/control_flow/branches_assert_condition_1.sol @@ -0,0 +1,12 @@ +pragma experimental SMTChecker; +contract C { + function f(uint x) public pure { + if (x > 10) { + assert(x > 9); + } + else + { + assert(x < 11); + } + } +} diff --git a/test/libsolidity/smtCheckerTests/control_flow/branches_assert_condition_2.sol b/test/libsolidity/smtCheckerTests/control_flow/branches_assert_condition_2.sol new file mode 100644 index 00000000..e39ab844 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/control_flow/branches_assert_condition_2.sol @@ -0,0 +1,16 @@ +pragma experimental SMTChecker; +contract C { + function f(uint x) public pure { + if (x > 10) { + assert(x > 9); + } + else if (x > 2) + { + assert(x <= 10 && x > 2); + } + else + { + assert(0 <= x && x <= 2); + } + } +} diff --git a/test/libsolidity/smtCheckerTests/control_flow/branches_merge_variables_1.sol b/test/libsolidity/smtCheckerTests/control_flow/branches_merge_variables_1.sol new file mode 100644 index 00000000..f93e32e4 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/control_flow/branches_merge_variables_1.sol @@ -0,0 +1,10 @@ +pragma experimental SMTChecker; +// Branch does not touch variable a +contract C { + function f(uint x) public pure { + uint a = 3; + if (x > 10) { + } + assert(a == 3); + } +} diff --git a/test/libsolidity/smtCheckerTests/control_flow/branches_merge_variables_2.sol b/test/libsolidity/smtCheckerTests/control_flow/branches_merge_variables_2.sol new file mode 100644 index 00000000..c00ef787 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/control_flow/branches_merge_variables_2.sol @@ -0,0 +1,11 @@ +pragma experimental SMTChecker; +// Positive branch touches variable a, but assertion should still hold. +contract C { + function f(uint x) public pure { + uint a = 3; + if (x > 10) { + a = 3; + } + assert(a == 3); + } +} diff --git a/test/libsolidity/smtCheckerTests/control_flow/branches_merge_variables_3.sol b/test/libsolidity/smtCheckerTests/control_flow/branches_merge_variables_3.sol new file mode 100644 index 00000000..4e18aa88 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/control_flow/branches_merge_variables_3.sol @@ -0,0 +1,12 @@ +pragma experimental SMTChecker; +// Negative branch touches variable a, but assertion should still hold. +contract C { + function f(uint x) public pure { + uint a = 3; + if (x > 10) { + } else { + a = 3; + } + assert(a == 3); + } +} diff --git a/test/libsolidity/smtCheckerTests/control_flow/branches_merge_variables_4.sol b/test/libsolidity/smtCheckerTests/control_flow/branches_merge_variables_4.sol new file mode 100644 index 00000000..e3a02704 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/control_flow/branches_merge_variables_4.sol @@ -0,0 +1,13 @@ +pragma experimental SMTChecker; +// Variable is not merged, if it is only read. +contract C { + function f(uint x) public pure { + uint a = 3; + if (x > 10) { + assert(a == 3); + } else { + assert(a == 3); + } + assert(a == 3); + } +} diff --git a/test/libsolidity/smtCheckerTests/control_flow/branches_merge_variables_5.sol b/test/libsolidity/smtCheckerTests/control_flow/branches_merge_variables_5.sol new file mode 100644 index 00000000..0bd1cf3a --- /dev/null +++ b/test/libsolidity/smtCheckerTests/control_flow/branches_merge_variables_5.sol @@ -0,0 +1,13 @@ +pragma experimental SMTChecker; +// Variable is reset in both branches +contract C { + function f(uint x) public pure { + uint a = 2; + if (x > 10) { + a = 3; + } else { + a = 3; + } + assert(a == 3); + } +} diff --git a/test/libsolidity/smtCheckerTests/control_flow/branches_merge_variables_6.sol b/test/libsolidity/smtCheckerTests/control_flow/branches_merge_variables_6.sol new file mode 100644 index 00000000..8e477179 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/control_flow/branches_merge_variables_6.sol @@ -0,0 +1,13 @@ +pragma experimental SMTChecker; +// Variable is reset in both branches +contract C { + function f(uint x) public pure { + uint a = 2; + if (x > 10) { + a = 3; + } else { + a = 4; + } + assert(a >= 3); + } +} diff --git a/test/libsolidity/smtCheckerTests/control_flow/ways_to_merge_variables_1.sol b/test/libsolidity/smtCheckerTests/control_flow/ways_to_merge_variables_1.sol new file mode 100644 index 00000000..16d6fdfe --- /dev/null +++ b/test/libsolidity/smtCheckerTests/control_flow/ways_to_merge_variables_1.sol @@ -0,0 +1,12 @@ +pragma experimental SMTChecker; +contract C { + function f(uint x) public pure { + uint a = 3; + if (x > 10) { + a++; + } + assert(a == 3); + } +} +// ---- +// Warning: (159-173): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/control_flow/ways_to_merge_variables_2.sol b/test/libsolidity/smtCheckerTests/control_flow/ways_to_merge_variables_2.sol new file mode 100644 index 00000000..e25ab20f --- /dev/null +++ b/test/libsolidity/smtCheckerTests/control_flow/ways_to_merge_variables_2.sol @@ -0,0 +1,12 @@ +pragma experimental SMTChecker; +contract C { + function f(uint x) public pure { + uint a = 3; + if (x > 10) { + ++a; + } + assert(a == 3); + } +} +// ---- +// Warning: (159-173): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/control_flow/ways_to_merge_variables_3.sol b/test/libsolidity/smtCheckerTests/control_flow/ways_to_merge_variables_3.sol new file mode 100644 index 00000000..03ae7216 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/control_flow/ways_to_merge_variables_3.sol @@ -0,0 +1,12 @@ +pragma experimental SMTChecker; +contract C { + function f(uint x) public pure { + uint a = 3; + if (x > 10) { + a = 5; + } + assert(a == 3); + } +} +// ---- +// Warning: (161-175): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/functions/function_call_does_not_clear_local_vars.sol b/test/libsolidity/smtCheckerTests/functions/function_call_does_not_clear_local_vars.sol new file mode 100644 index 00000000..b4260224 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/functions/function_call_does_not_clear_local_vars.sol @@ -0,0 +1,13 @@ +pragma experimental SMTChecker; +contract C { + function f() public { + uint a = 3; + this.f(); + assert(a == 3); + f(); + assert(a == 3); + } +} +// ---- +// Warning: (99-107): Assertion checker does not yet implement this type of function call. +// Warning: (141-144): Assertion checker does not support recursive function calls. diff --git a/test/libsolidity/smtCheckerTests/loops/for_loop_1.sol b/test/libsolidity/smtCheckerTests/loops/for_loop_1.sol new file mode 100644 index 00000000..8988efad --- /dev/null +++ b/test/libsolidity/smtCheckerTests/loops/for_loop_1.sol @@ -0,0 +1,8 @@ +pragma experimental SMTChecker; +contract C { + function f(uint x) public pure { + require(x == 2); + for (;;) {} + assert(x == 2); + } +} diff --git a/test/libsolidity/smtCheckerTests/loops/for_loop_2.sol b/test/libsolidity/smtCheckerTests/loops/for_loop_2.sol new file mode 100644 index 00000000..58c9f3a7 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/loops/for_loop_2.sol @@ -0,0 +1,8 @@ +pragma experimental SMTChecker; +contract C { + function f(uint x) public pure { + for (; x == 2; ) { + assert(x == 2); + } + } +} diff --git a/test/libsolidity/smtCheckerTests/loops/for_loop_3.sol b/test/libsolidity/smtCheckerTests/loops/for_loop_3.sol new file mode 100644 index 00000000..8bf9bdc7 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/loops/for_loop_3.sol @@ -0,0 +1,8 @@ +pragma experimental SMTChecker; +contract C { + function f(uint x) public pure { + for (uint y = 2; x < 10; ) { + assert(y == 2); + } + } +} diff --git a/test/libsolidity/smtCheckerTests/loops/for_loop_4.sol b/test/libsolidity/smtCheckerTests/loops/for_loop_4.sol new file mode 100644 index 00000000..4d082026 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/loops/for_loop_4.sol @@ -0,0 +1,10 @@ +pragma experimental SMTChecker; +contract C { + function f(uint x) public pure { + for (uint y = 2; x < 10; y = 3) { + assert(y == 2); + } + } +} +// ---- +// Warning: (136-150): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/loops/for_loop_5.sol b/test/libsolidity/smtCheckerTests/loops/for_loop_5.sol new file mode 100644 index 00000000..2c84960f --- /dev/null +++ b/test/libsolidity/smtCheckerTests/loops/for_loop_5.sol @@ -0,0 +1,12 @@ +pragma experimental SMTChecker; +contract C { + function f(uint x) public pure { + uint y; + for (y = 2; x < 10; ) { + y = 3; + } + assert(y == 3); + } +} +// ---- +// Warning: (167-181): Assertion violation happens here\nNote that some information is erased after the execution of loops.\nYou can re-introduce information using require(). diff --git a/test/libsolidity/smtCheckerTests/loops/for_loop_6.sol b/test/libsolidity/smtCheckerTests/loops/for_loop_6.sol new file mode 100644 index 00000000..90c4c328 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/loops/for_loop_6.sol @@ -0,0 +1,12 @@ +pragma experimental SMTChecker; +contract C { + function f(uint x) public pure { + uint y; + for (y = 2; x < 10; ) { + y = 3; + } + assert(y == 2); + } +} +// ---- +// Warning: (167-181): Assertion violation happens here\nNote that some information is erased after the execution of loops.\nYou can re-introduce information using require(). diff --git a/test/libsolidity/smtCheckerTests/loops/while_loop_simple_1.sol b/test/libsolidity/smtCheckerTests/loops/while_loop_simple_1.sol new file mode 100644 index 00000000..074be86f --- /dev/null +++ b/test/libsolidity/smtCheckerTests/loops/while_loop_simple_1.sol @@ -0,0 +1,13 @@ +pragma experimental SMTChecker; +// Check that variables are cleared +contract C { + function f(uint x) public pure { + x = 2; + while (x > 1) { + x = 2; + } + assert(x == 2); + } +} +// ---- +// Warning: (194-208): Assertion violation happens here\nNote that some information is erased after the execution of loops.\nYou can re-introduce information using require(). diff --git a/test/libsolidity/smtCheckerTests/loops/while_loop_simple_2.sol b/test/libsolidity/smtCheckerTests/loops/while_loop_simple_2.sol new file mode 100644 index 00000000..92a3f0fe --- /dev/null +++ b/test/libsolidity/smtCheckerTests/loops/while_loop_simple_2.sol @@ -0,0 +1,9 @@ +pragma experimental SMTChecker; +// Check that condition is assumed. +contract C { + function f(uint x) public pure { + while (x == 2) { + assert(x == 2); + } + } +} diff --git a/test/libsolidity/smtCheckerTests/loops/while_loop_simple_3.sol b/test/libsolidity/smtCheckerTests/loops/while_loop_simple_3.sol new file mode 100644 index 00000000..a37df888 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/loops/while_loop_simple_3.sol @@ -0,0 +1,11 @@ +pragma experimental SMTChecker; +// Check that condition is not assumed after the body anymore +contract C { + function f(uint x) public pure { + while (x == 2) { + } + assert(x == 2); + } +} +// ---- +// Warning: (187-201): Assertion violation happens here\nNote that some information is erased after the execution of loops.\nYou can re-introduce information using require(). diff --git a/test/libsolidity/smtCheckerTests/loops/while_loop_simple_4.sol b/test/libsolidity/smtCheckerTests/loops/while_loop_simple_4.sol new file mode 100644 index 00000000..f71da865 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/loops/while_loop_simple_4.sol @@ -0,0 +1,11 @@ +pragma experimental SMTChecker; +// Check that negation of condition is not assumed after the body anymore +contract C { + function f(uint x) public pure { + while (x == 2) { + } + assert(x != 2); + } +} +// ---- +// Warning: (199-213): Assertion violation happens here\nNote that some information is erased after the execution of loops.\nYou can re-introduce information using require(). diff --git a/test/libsolidity/smtCheckerTests/loops/while_loop_simple_5.sol b/test/libsolidity/smtCheckerTests/loops/while_loop_simple_5.sol new file mode 100644 index 00000000..41559c99 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/loops/while_loop_simple_5.sol @@ -0,0 +1,12 @@ +pragma experimental SMTChecker; +// Check that side-effects of condition are taken into account +contract C { + function f(uint x, uint y) public pure { + x = 7; + while ((x = y) > 0) { + } + assert(x == 7); + } +} +// ---- +// Warning: (216-230): Assertion violation happens here\nNote that some information is erased after the execution of loops.\nYou can re-introduce information using require(). diff --git a/test/libsolidity/smtCheckerTests/overflow/simple_overflow.sol b/test/libsolidity/smtCheckerTests/overflow/simple_overflow.sol new file mode 100644 index 00000000..894ff1a4 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/overflow/simple_overflow.sol @@ -0,0 +1,6 @@ +pragma experimental SMTChecker; +contract C { + function f(uint a, uint b) public pure returns (uint) { return a + b; } +} +// ---- +// Warning: (112-117): Overflow (resulting value larger than 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) happens here diff --git a/test/libsolidity/smtCheckerTests/simple/smoke_test.sol b/test/libsolidity/smtCheckerTests/simple/smoke_test.sol new file mode 100644 index 00000000..8b7b77da --- /dev/null +++ b/test/libsolidity/smtCheckerTests/simple/smoke_test.sol @@ -0,0 +1,3 @@ +pragma experimental SMTChecker; +contract C { +} diff --git a/test/libsolidity/smtCheckerTests/types/bool_int_mixed_1.sol b/test/libsolidity/smtCheckerTests/types/bool_int_mixed_1.sol new file mode 100644 index 00000000..d611cc17 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/bool_int_mixed_1.sol @@ -0,0 +1,9 @@ +pragma experimental SMTChecker; +contract C { + function f(bool x) public pure { + uint a; + if(x) + a = 1; + assert(!x || a > 0); + } +} diff --git a/test/libsolidity/smtCheckerTests/types/bool_int_mixed_2.sol b/test/libsolidity/smtCheckerTests/types/bool_int_mixed_2.sol new file mode 100644 index 00000000..24640c5a --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/bool_int_mixed_2.sol @@ -0,0 +1,8 @@ +pragma experimental SMTChecker; +contract C { + function f(bool x, uint a) public pure { + require(!x || a > 0); + uint b = a; + assert(!x || b > 0); + } +} diff --git a/test/libsolidity/smtCheckerTests/types/bool_int_mixed_3.sol b/test/libsolidity/smtCheckerTests/types/bool_int_mixed_3.sol new file mode 100644 index 00000000..f872e82f --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/bool_int_mixed_3.sol @@ -0,0 +1,21 @@ +pragma experimental SMTChecker; +contract C { + function f(bool x, bool y) public pure { + uint a; + if (x) { + if (y) { + a = 0; + } else { + a = 1; + } + } else { + if (y) { + a = 1; + } else { + a = 0; + } + } + bool xor_x_y = (x && !y) || (!x && y); + assert(!xor_x_y || a > 0); + } +} diff --git a/test/libsolidity/smtCheckerTests/types/bool_simple_1.sol b/test/libsolidity/smtCheckerTests/types/bool_simple_1.sol new file mode 100644 index 00000000..76b4b08b --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/bool_simple_1.sol @@ -0,0 +1,8 @@ +pragma experimental SMTChecker; +contract C { + function f(bool x) public pure { + assert(x); + } +} +// ---- +// Warning: (90-99): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/bool_simple_2.sol b/test/libsolidity/smtCheckerTests/types/bool_simple_2.sol new file mode 100644 index 00000000..5c166c02 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/bool_simple_2.sol @@ -0,0 +1,8 @@ +pragma experimental SMTChecker; +contract C { + function f(bool x, bool y) public pure { + assert(x == y); + } +} +// ---- +// Warning: (98-112): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/bool_simple_3.sol b/test/libsolidity/smtCheckerTests/types/bool_simple_3.sol new file mode 100644 index 00000000..1d2ab49f --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/bool_simple_3.sol @@ -0,0 +1,7 @@ +pragma experimental SMTChecker; +contract C { + function f(bool x, bool y) public pure { + bool z = x || y; + assert(!(x && y) || z); + } +} diff --git a/test/libsolidity/smtCheckerTests/types/bool_simple_4.sol b/test/libsolidity/smtCheckerTests/types/bool_simple_4.sol new file mode 100644 index 00000000..c40404a4 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/bool_simple_4.sol @@ -0,0 +1,10 @@ +pragma experimental SMTChecker; +contract C { + function f(bool x) public pure { + if(x) { + assert(x); + } else { + assert(!x); + } + } +} diff --git a/test/libsolidity/smtCheckerTests/types/bool_simple_5.sol b/test/libsolidity/smtCheckerTests/types/bool_simple_5.sol new file mode 100644 index 00000000..4cecebbc --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/bool_simple_5.sol @@ -0,0 +1,7 @@ +pragma experimental SMTChecker; +contract C { + function f(bool x) public pure { + bool y = x; + assert(x == y); + } +} diff --git a/test/libsolidity/smtCheckerTests/types/bool_simple_6.sol b/test/libsolidity/smtCheckerTests/types/bool_simple_6.sol new file mode 100644 index 00000000..90350bb6 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/bool_simple_6.sol @@ -0,0 +1,9 @@ +pragma experimental SMTChecker; +contract C { + function f(bool x) public pure { + require(x); + bool y; + y = false; + assert(x || y); + } +} diff --git a/test/libsolidity/smtCheckerTests/types/storage_value_vars_1.sol b/test/libsolidity/smtCheckerTests/types/storage_value_vars_1.sol new file mode 100644 index 00000000..84f6c77e --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/storage_value_vars_1.sol @@ -0,0 +1,22 @@ +pragma experimental SMTChecker; +contract C +{ + address a; + bool b; + uint c; + function f(uint x) public { + if (x == 0) + { + a = 0x0000000000000000000000000000000000000100; + b = true; + } + else + { + a = 0x0000000000000000000000000000000000000200; + b = false; + } + assert(a > 0x0000000000000000000000000000000000000000 && b); + } +} +// ---- +// Warning: (362-421): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/storage_value_vars_2.sol b/test/libsolidity/smtCheckerTests/types/storage_value_vars_2.sol new file mode 100644 index 00000000..bceddb38 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/storage_value_vars_2.sol @@ -0,0 +1,12 @@ +pragma experimental SMTChecker; +contract C +{ + address a; + bool b; + uint c; + function f() public view { + assert(c > 0); + } +} +// ---- +// Warning: (123-136): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/storage_value_vars_3.sol b/test/libsolidity/smtCheckerTests/types/storage_value_vars_3.sol new file mode 100644 index 00000000..39049b99 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/storage_value_vars_3.sol @@ -0,0 +1,25 @@ +pragma experimental SMTChecker; +contract C +{ + function f(uint x) public { + if (x == 0) + { + a = 0x0000000000000000000000000000000000000100; + b = true; + } + else + { + a = 0x0000000000000000000000000000000000000200; + b = false; + } + assert(b == (a < 0x0000000000000000000000000000000000000200)); + } + + function g() public view { + require(a < 0x0000000000000000000000000000000000000100); + assert(c >= 0); + } + address a; + bool b; + uint c; +} diff --git a/test/libsolidity/smtCheckerTests/types/storage_value_vars_4.sol b/test/libsolidity/smtCheckerTests/types/storage_value_vars_4.sol new file mode 100644 index 00000000..88b6b0ae --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/storage_value_vars_4.sol @@ -0,0 +1,10 @@ +pragma experimental SMTChecker; +contract C +{ + function f() public view { + assert(c > 0); + } + uint c; +} +// ---- +// Warning: (84-97): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/verification_target/constant_condition_1.sol b/test/libsolidity/smtCheckerTests/verification_target/constant_condition_1.sol new file mode 100644 index 00000000..b9fae4ee --- /dev/null +++ b/test/libsolidity/smtCheckerTests/verification_target/constant_condition_1.sol @@ -0,0 +1,9 @@ +pragma experimental SMTChecker; +contract C { + function f(uint x) public pure { + if (x >= 0) { revert(); } + } +} +// ---- +// Warning: (94-100): Condition is always true. +// Warning: (104-112): Assertion checker does not yet implement this type of function call. diff --git a/test/libsolidity/smtCheckerTests/verification_target/constant_condition_2.sol b/test/libsolidity/smtCheckerTests/verification_target/constant_condition_2.sol new file mode 100644 index 00000000..aaa613ea --- /dev/null +++ b/test/libsolidity/smtCheckerTests/verification_target/constant_condition_2.sol @@ -0,0 +1,9 @@ +pragma experimental SMTChecker; +contract C { + function f(uint x) public pure { + if (x >= 10) { if (x < 10) { revert(); } } + } +} +// ---- +// Warning: (109-115): Condition is always false. +// Warning: (119-127): Assertion checker does not yet implement this type of function call. diff --git a/test/libsolidity/smtCheckerTests/verification_target/constant_condition_3.sol b/test/libsolidity/smtCheckerTests/verification_target/constant_condition_3.sol new file mode 100644 index 00000000..f22cd65e --- /dev/null +++ b/test/libsolidity/smtCheckerTests/verification_target/constant_condition_3.sol @@ -0,0 +1,9 @@ +pragma experimental SMTChecker; +// a plain literal constant is fine +contract C { + function f(uint) public pure { + if (true) { revert(); } + } +} +// ---- +// Warning: (136-144): Assertion checker does not yet implement this type of function call. diff --git a/test/libsolidity/smtCheckerTests/verification_target/simple_assert.sol b/test/libsolidity/smtCheckerTests/verification_target/simple_assert.sol new file mode 100644 index 00000000..8bd6e61a --- /dev/null +++ b/test/libsolidity/smtCheckerTests/verification_target/simple_assert.sol @@ -0,0 +1,6 @@ +pragma experimental SMTChecker; +contract C { + function f(uint a) public pure { assert(a == 2); } +} +// ---- +// Warning: (82-96): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/verification_target/simple_assert_with_require.sol b/test/libsolidity/smtCheckerTests/verification_target/simple_assert_with_require.sol new file mode 100644 index 00000000..b66ae245 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/verification_target/simple_assert_with_require.sol @@ -0,0 +1,4 @@ +pragma experimental SMTChecker; +contract C { + function f(uint a) public pure { require(a < 10); assert(a < 20); } +} diff --git a/test/libsolidity/smtCheckerTestsJSON/multi.json b/test/libsolidity/smtCheckerTestsJSON/multi.json new file mode 100644 index 00000000..2ed5150d --- /dev/null +++ b/test/libsolidity/smtCheckerTestsJSON/multi.json @@ -0,0 +1,11 @@ +{ + "auxiliaryInput": + { + "smtlib2responses": + { + "0x0426cd198d1e7123a28ffac2b759a666b86508ad046babf5166500dd6d8ed308": "unsat\n(error \"line 31 column 26: model is not available\")", + "0xa51ca41ae407f5a727f27101cbc079834743cc8955f9f585582034ca634953f6": "sat\n((|EVALEXPR_0| 1))", + "0xe9477f683ff20aa57fcb08682150f86c5917e1d4c0686b278ab9b73446d0682c": "sat\n((|EVALEXPR_0| 0))" + } + } +} diff --git a/test/libsolidity/smtCheckerTestsJSON/multi.sol b/test/libsolidity/smtCheckerTestsJSON/multi.sol new file mode 100644 index 00000000..e0d69b1d --- /dev/null +++ b/test/libsolidity/smtCheckerTestsJSON/multi.sol @@ -0,0 +1,13 @@ +pragma experimental SMTChecker; + +contract C +{ + function f(uint x) public pure { + assert(x > 0); + assert(x > 100); + assert(x >= 0); + } +} +// ---- +// Warning: (82-95): Assertion violation happens here +// Warning: (99-114): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTestsJSON/simple.json b/test/libsolidity/smtCheckerTestsJSON/simple.json new file mode 100644 index 00000000..fd976b63 --- /dev/null +++ b/test/libsolidity/smtCheckerTestsJSON/simple.json @@ -0,0 +1,9 @@ +{ + "auxiliaryInput": + { + "smtlib2responses": + { + "0xe9477f683ff20aa57fcb08682150f86c5917e1d4c0686b278ab9b73446d0682c": "sat\n((|EVALEXPR_0| 0))" + } + } +} diff --git a/test/libsolidity/smtCheckerTestsJSON/simple.sol b/test/libsolidity/smtCheckerTestsJSON/simple.sol new file mode 100644 index 00000000..6bc7193d --- /dev/null +++ b/test/libsolidity/smtCheckerTestsJSON/simple.sol @@ -0,0 +1,10 @@ +pragma experimental SMTChecker; + +contract C +{ + function f(uint x) public pure { + assert(x > 0); + } +} +// ---- +// Warning: (82-95): Assertion violation happens here diff --git a/test/libsolidity/syntaxTests/bound/bound_all.sol b/test/libsolidity/syntaxTests/bound/bound_all.sol new file mode 100644 index 00000000..29f55b88 --- /dev/null +++ b/test/libsolidity/syntaxTests/bound/bound_all.sol @@ -0,0 +1,10 @@ +library L { + function g(function() internal returns (uint) _t) internal returns (uint) { return _t(); } +} +contract C { + using L for *; + function f() public returns (uint) { + return t.g(); + } + function t() public pure returns (uint) { return 7; } +} diff --git a/test/libsolidity/syntaxTests/bound/bound_call.sol b/test/libsolidity/syntaxTests/bound/bound_call.sol new file mode 100644 index 00000000..281f19b4 --- /dev/null +++ b/test/libsolidity/syntaxTests/bound/bound_call.sol @@ -0,0 +1,7 @@ +library D { function double(uint self) internal pure returns (uint) { return 2*self; } } +contract C { + using D for uint; + function f(uint a) public pure { + a.double(); + } +} diff --git a/test/libsolidity/syntaxTests/bound/bound_no_call.sol b/test/libsolidity/syntaxTests/bound/bound_no_call.sol new file mode 100644 index 00000000..dcb3c3c5 --- /dev/null +++ b/test/libsolidity/syntaxTests/bound/bound_no_call.sol @@ -0,0 +1,7 @@ +library D { function double(uint self) public pure returns (uint) { return 2*self; } } +contract C { + using D for uint; + function f(uint a) public pure { + a.double; + } +} diff --git a/test/libyul/Common.cpp b/test/libyul/Common.cpp index 8913483f..d7785287 100644 --- a/test/libyul/Common.cpp +++ b/test/libyul/Common.cpp @@ -23,25 +23,24 @@ #include <test/Options.h> +#include <libsolidity/interface/SourceReferenceFormatter.h> + #include <libyul/optimiser/Disambiguator.h> +#include <libyul/AsmParser.h> +#include <libyul/AsmAnalysis.h> +#include <libyul/AsmPrinter.h> #include <liblangutil/Scanner.h> - -#include <libsolidity/inlineasm/AsmParser.h> -#include <libsolidity/inlineasm/AsmAnalysis.h> -#include <libsolidity/inlineasm/AsmPrinter.h> - -#include <libsolidity/interface/SourceReferenceFormatter.h> #include <liblangutil/ErrorReporter.h> #include <boost/test/unit_test.hpp> using namespace std; using namespace langutil; -using namespace dev::yul; +using namespace yul; using namespace dev::solidity; -void dev::yul::test::printErrors(ErrorList const& _errors, Scanner const& _scanner) +void yul::test::printErrors(ErrorList const& _errors, Scanner const& _scanner) { SourceReferenceFormatter formatter(cout, [&](std::string const&) -> Scanner const& { return _scanner; }); @@ -53,18 +52,18 @@ void dev::yul::test::printErrors(ErrorList const& _errors, Scanner const& _scann } -pair<shared_ptr<Block>, shared_ptr<assembly::AsmAnalysisInfo>> dev::yul::test::parse(string const& _source, bool _yul) +pair<shared_ptr<Block>, shared_ptr<yul::AsmAnalysisInfo>> yul::test::parse(string const& _source, bool _yul) { - auto flavour = _yul ? assembly::AsmFlavour::Yul : assembly::AsmFlavour::Strict; + auto flavour = _yul ? yul::AsmFlavour::Yul : yul::AsmFlavour::Strict; ErrorList errors; ErrorReporter errorReporter(errors); auto scanner = make_shared<Scanner>(CharStream(_source), ""); - auto parserResult = assembly::Parser(errorReporter, flavour).parse(scanner, false); + auto parserResult = yul::Parser(errorReporter, flavour).parse(scanner, false); if (parserResult) { BOOST_REQUIRE(errorReporter.errors().empty()); - auto analysisInfo = make_shared<assembly::AsmAnalysisInfo>(); - assembly::AsmAnalyzer analyzer( + auto analysisInfo = make_shared<yul::AsmAnalysisInfo>(); + yul::AsmAnalyzer analyzer( *analysisInfo, errorReporter, dev::test::Options::get().evmVersion(), @@ -84,13 +83,13 @@ pair<shared_ptr<Block>, shared_ptr<assembly::AsmAnalysisInfo>> dev::yul::test::p return {}; } -assembly::Block dev::yul::test::disambiguate(string const& _source, bool _yul) +yul::Block yul::test::disambiguate(string const& _source, bool _yul) { auto result = parse(_source, _yul); return boost::get<Block>(Disambiguator(*result.second, {})(*result.first)); } -string dev::yul::test::format(string const& _source, bool _yul) +string yul::test::format(string const& _source, bool _yul) { - return assembly::AsmPrinter(_yul)(*parse(_source, _yul).first); + return yul::AsmPrinter(_yul)(*parse(_source, _yul).first); } diff --git a/test/libyul/Common.h b/test/libyul/Common.h index 390e214f..a1c64ca5 100644 --- a/test/libyul/Common.h +++ b/test/libyul/Common.h @@ -21,7 +21,7 @@ #pragma once -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> #include <string> #include <vector> @@ -34,26 +34,21 @@ class Error; using ErrorList = std::vector<std::shared_ptr<Error const>>; } -namespace dev -{ -namespace solidity -{ -namespace assembly +namespace yul { struct AsmAnalysisInfo; } -} + namespace yul { namespace test { void printErrors(langutil::ErrorList const& _errors, langutil::Scanner const& _scanner); -std::pair<std::shared_ptr<solidity::assembly::Block>, std::shared_ptr<solidity::assembly::AsmAnalysisInfo>> +std::pair<std::shared_ptr<Block>, std::shared_ptr<AsmAnalysisInfo>> parse(std::string const& _source, bool _yul = true); -solidity::assembly::Block disambiguate(std::string const& _source, bool _yul = true); +Block disambiguate(std::string const& _source, bool _yul = true); std::string format(std::string const& _source, bool _yul = true); } } -} diff --git a/test/libyul/Inliner.cpp b/test/libyul/Inliner.cpp index 66810298..631cda08 100644 --- a/test/libyul/Inliner.cpp +++ b/test/libyul/Inliner.cpp @@ -26,8 +26,7 @@ #include <libyul/optimiser/FullInliner.h> #include <libyul/optimiser/FunctionHoister.h> #include <libyul/optimiser/FunctionGrouper.h> - -#include <libsolidity/inlineasm/AsmPrinter.h> +#include <libyul/AsmPrinter.h> #include <boost/test/unit_test.hpp> @@ -36,8 +35,8 @@ using namespace std; using namespace dev; -using namespace dev::yul; -using namespace dev::yul::test; +using namespace yul; +using namespace yul::test; using namespace dev::solidity; namespace diff --git a/test/libyul/Parser.cpp b/test/libyul/Parser.cpp index 4aa3dd5c..6f946362 100644 --- a/test/libyul/Parser.cpp +++ b/test/libyul/Parser.cpp @@ -23,9 +23,9 @@ #include <test/libsolidity/ErrorCheck.h> -#include <libsolidity/inlineasm/AsmParser.h> -#include <libsolidity/inlineasm/AsmAnalysis.h> -#include <libsolidity/inlineasm/AsmAnalysisInfo.h> +#include <libyul/AsmParser.h> +#include <libyul/AsmAnalysis.h> +#include <libyul/AsmAnalysisInfo.h> #include <liblangutil/Scanner.h> #include <liblangutil/ErrorReporter.h> @@ -36,11 +36,10 @@ #include <memory> using namespace std; +using namespace dev; using namespace langutil; -namespace dev -{ -namespace solidity +namespace yul { namespace test { @@ -53,16 +52,16 @@ bool parse(string const& _source, ErrorReporter& errorReporter) try { auto scanner = make_shared<Scanner>(CharStream(_source)); - auto parserResult = assembly::Parser(errorReporter, assembly::AsmFlavour::Yul).parse(scanner, false); + auto parserResult = yul::Parser(errorReporter, yul::AsmFlavour::Yul).parse(scanner, false); if (parserResult) { - assembly::AsmAnalysisInfo analysisInfo; - return (assembly::AsmAnalyzer( + yul::AsmAnalysisInfo analysisInfo; + return (yul::AsmAnalyzer( analysisInfo, errorReporter, dev::test::Options::get().evmVersion(), boost::none, - assembly::AsmFlavour::Yul + yul::AsmFlavour::Yul )).analyze(*parserResult); } } @@ -117,7 +116,7 @@ do \ { \ Error err = expectError((text), false); \ BOOST_CHECK(err.type() == (Error::Type::typ)); \ - BOOST_CHECK(searchErrorMessage(err, (substring))); \ + BOOST_CHECK(dev::solidity::searchErrorMessage(err, (substring))); \ } while(0) BOOST_AUTO_TEST_SUITE(YulParser) @@ -303,5 +302,4 @@ BOOST_AUTO_TEST_CASE(if_statement_invalid) BOOST_AUTO_TEST_SUITE_END() } -} } // end namespaces diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp index 6b2b81c3..9c2da493 100644 --- a/test/libyul/YulOptimizerTest.cpp +++ b/test/libyul/YulOptimizerTest.cpp @@ -21,9 +21,6 @@ #include <test/Options.h> -#include <liblangutil/ErrorReporter.h> -#include <liblangutil/Scanner.h> - #include <libyul/optimiser/BlockFlattener.h> #include <libyul/optimiser/VarDeclPropagator.h> #include <libyul/optimiser/Disambiguator.h> @@ -43,12 +40,14 @@ #include <libyul/optimiser/SSATransform.h> #include <libyul/optimiser/RedundantAssignEliminator.h> #include <libyul/optimiser/Suite.h> - -#include <libsolidity/inlineasm/AsmPrinter.h> -#include <libsolidity/inlineasm/AsmParser.h> -#include <libsolidity/inlineasm/AsmAnalysis.h> +#include <libyul/AsmPrinter.h> +#include <libyul/AsmParser.h> +#include <libyul/AsmAnalysis.h> #include <libsolidity/interface/SourceReferenceFormatter.h> +#include <liblangutil/ErrorReporter.h> +#include <liblangutil/Scanner.h> + #include <boost/test/unit_test.hpp> #include <boost/algorithm/string.hpp> @@ -56,8 +55,8 @@ using namespace dev; using namespace langutil; -using namespace dev::yul; -using namespace dev::yul::test; +using namespace yul; +using namespace yul::test; using namespace dev::solidity; using namespace dev::solidity::test; using namespace std; @@ -93,9 +92,9 @@ YulOptimizerTest::YulOptimizerTest(string const& _filename) bool YulOptimizerTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted) { - assembly::AsmPrinter printer{m_yul}; + yul::AsmPrinter printer{m_yul}; shared_ptr<Block> ast; - shared_ptr<assembly::AsmAnalysisInfo> analysisInfo; + shared_ptr<yul::AsmAnalysisInfo> analysisInfo; if (!parse(_stream, _linePrefix, _formatted)) return false; @@ -257,19 +256,19 @@ void YulOptimizerTest::printIndented(ostream& _stream, string const& _output, st bool YulOptimizerTest::parse(ostream& _stream, string const& _linePrefix, bool const _formatted) { - assembly::AsmFlavour flavour = m_yul ? assembly::AsmFlavour::Yul : assembly::AsmFlavour::Strict; + yul::AsmFlavour flavour = m_yul ? yul::AsmFlavour::Yul : yul::AsmFlavour::Strict; ErrorList errors; ErrorReporter errorReporter(errors); shared_ptr<Scanner> scanner = make_shared<Scanner>(CharStream(m_source), ""); - m_ast = assembly::Parser(errorReporter, flavour).parse(scanner, false); + m_ast = yul::Parser(errorReporter, flavour).parse(scanner, false); if (!m_ast || !errorReporter.errors().empty()) { FormattedScope(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << endl; printErrors(_stream, errorReporter.errors(), *scanner); return false; } - m_analysisInfo = make_shared<assembly::AsmAnalysisInfo>(); - assembly::AsmAnalyzer analyzer( + m_analysisInfo = make_shared<yul::AsmAnalysisInfo>(); + yul::AsmAnalyzer analyzer( *m_analysisInfo, errorReporter, dev::test::Options::get().evmVersion(), diff --git a/test/libyul/YulOptimizerTest.h b/test/libyul/YulOptimizerTest.h index d11ff8fb..90026e24 100644 --- a/test/libyul/YulOptimizerTest.h +++ b/test/libyul/YulOptimizerTest.h @@ -17,7 +17,7 @@ #pragma once -#include <test/libsolidity/TestCase.h> +#include <test/TestCase.h> namespace langutil { @@ -26,22 +26,18 @@ class Error; using ErrorList = std::vector<std::shared_ptr<Error const>>; } -namespace dev -{ -namespace solidity -{ -namespace assembly +namespace yul { struct AsmAnalysisInfo; struct Block; } -} + namespace yul { namespace test { -class YulOptimizerTest: public solidity::test::TestCase +class YulOptimizerTest: public dev::solidity::test::TestCase { public: static std::unique_ptr<TestCase> create(std::string const& _filename) @@ -68,11 +64,10 @@ private: std::string m_optimizerStep; std::string m_expectation; - std::shared_ptr<solidity::assembly::Block> m_ast; - std::shared_ptr<solidity::assembly::AsmAnalysisInfo> m_analysisInfo; + std::shared_ptr<Block> m_ast; + std::shared_ptr<AsmAnalysisInfo> m_analysisInfo; std::string m_obtainedResult; }; } } -} diff --git a/test/tools/CMakeLists.txt b/test/tools/CMakeLists.txt index 19a1d958..736212fc 100644 --- a/test/tools/CMakeLists.txt +++ b/test/tools/CMakeLists.txt @@ -4,7 +4,7 @@ target_link_libraries(solfuzzer PRIVATE libsolc evmasm ${Boost_PROGRAM_OPTIONS_L add_executable(yulopti yulopti.cpp) target_link_libraries(yulopti PRIVATE solidity ${Boost_PROGRAM_OPTIONS_LIBRARIES} ${Boost_SYSTEM_LIBRARIES}) -add_executable(isoltest isoltest.cpp ../Options.cpp ../Common.cpp ../libsolidity/TestCase.cpp ../libsolidity/SyntaxTest.cpp +add_executable(isoltest isoltest.cpp ../Options.cpp ../Common.cpp ../TestCase.cpp ../libsolidity/SyntaxTest.cpp ../libsolidity/AnalysisFramework.cpp ../libsolidity/SolidityExecutionFramework.cpp ../ExecutionFramework.cpp - ../RPCSession.cpp ../libsolidity/ASTJSONTest.cpp ../libyul/YulOptimizerTest.cpp) + ../RPCSession.cpp ../libsolidity/ASTJSONTest.cpp ../libsolidity/SMTCheckerJSONTest.cpp ../libyul/YulOptimizerTest.cpp) target_link_libraries(isoltest PRIVATE libsolc solidity evmasm ${Boost_PROGRAM_OPTIONS_LIBRARIES} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES}) diff --git a/test/tools/isoltest.cpp b/test/tools/isoltest.cpp index 1b6fd54a..f8e2dc58 100644 --- a/test/tools/isoltest.cpp +++ b/test/tools/isoltest.cpp @@ -21,6 +21,7 @@ #include <test/libsolidity/AnalysisFramework.h> #include <test/libsolidity/SyntaxTest.h> #include <test/libsolidity/ASTJSONTest.h> +#include <test/libsolidity/SMTCheckerJSONTest.h> #include <test/libyul/YulOptimizerTest.h> #include <boost/algorithm/string.hpp> @@ -412,6 +413,17 @@ Allowed options)", global_stats += *stats; else return 1; + + if (auto stats = runTestSuite( + "SMT Checker JSON", + testPath / "libsolidity", + "smtCheckerTestsJSON", + SMTCheckerTest::create, + formatted + )) + global_stats += *stats; + else + return 1; } cout << endl << "Summary: "; diff --git a/test/tools/yulopti.cpp b/test/tools/yulopti.cpp index 8bc807d4..7a147137 100644 --- a/test/tools/yulopti.cpp +++ b/test/tools/yulopti.cpp @@ -21,12 +21,12 @@ #include <libdevcore/CommonIO.h> #include <liblangutil/ErrorReporter.h> #include <liblangutil/Scanner.h> -#include <libsolidity/inlineasm/AsmAnalysis.h> -#include <libsolidity/inlineasm/AsmAnalysisInfo.h> +#include <libyul/AsmAnalysis.h> +#include <libyul/AsmAnalysisInfo.h> #include <libsolidity/parsing/Parser.h> -#include <libsolidity/inlineasm/AsmData.h> -#include <libsolidity/inlineasm/AsmParser.h> -#include <libsolidity/inlineasm/AsmPrinter.h> +#include <libyul/AsmData.h> +#include <libyul/AsmParser.h> +#include <libyul/AsmPrinter.h> #include <libsolidity/interface/SourceReferenceFormatter.h> #include <libyul/optimiser/BlockFlattener.h> @@ -60,8 +60,7 @@ using namespace std; using namespace dev; using namespace langutil; using namespace dev::solidity; -using namespace dev::solidity::assembly; -using namespace dev::yul; +using namespace yul; namespace po = boost::program_options; @@ -83,14 +82,14 @@ public: { ErrorReporter errorReporter(m_errors); shared_ptr<Scanner> scanner = make_shared<Scanner>(CharStream(_input), ""); - m_ast = assembly::Parser(errorReporter, assembly::AsmFlavour::Strict).parse(scanner, false); + m_ast = yul::Parser(errorReporter, yul::AsmFlavour::Strict).parse(scanner, false); if (!m_ast || !errorReporter.errors().empty()) { cout << "Error parsing source." << endl; printErrors(*scanner); return false; } - m_analysisInfo = make_shared<assembly::AsmAnalysisInfo>(); + m_analysisInfo = make_shared<yul::AsmAnalysisInfo>(); AsmAnalyzer analyzer( *m_analysisInfo, errorReporter, @@ -118,7 +117,7 @@ public: return; if (!disambiguated) { - *m_ast = boost::get<assembly::Block>(Disambiguator(*m_analysisInfo)(*m_ast)); + *m_ast = boost::get<yul::Block>(Disambiguator(*m_analysisInfo)(*m_ast)); m_analysisInfo.reset(); m_nameDispenser = make_shared<NameDispenser>(*m_ast); disambiguated = true; @@ -187,7 +186,7 @@ public: private: ErrorList m_errors; - shared_ptr<assembly::Block> m_ast; + shared_ptr<yul::Block> m_ast; shared_ptr<AsmAnalysisInfo> m_analysisInfo; shared_ptr<NameDispenser> m_nameDispenser; }; |