From 151e63733639844a3841113e3d74177ed0542335 Mon Sep 17 00:00:00 2001 From: Alexander Arlt Date: Sat, 25 Apr 2020 19:18:10 -0500 Subject: [PATCH 01/89] [Sol - Yul] Add some built-in functions. - simplifications for GasLeft, Selfdestruct and BlockHash. - add support for addmod & mulmod. --- .../codegen/ir/IRGeneratorForStatements.cpp | 38 ++++++++++++++++--- .../arithmetics/addmod_mulmod_zero.sol | 2 + .../builtinFunctions/blockhash.sol | 17 +++++++++ 3 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 test/libsolidity/semanticTests/builtinFunctions/blockhash.sol diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 252ddffa7..0717d6540 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -584,7 +584,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) case FunctionType::Kind::Internal: { vector args; - for (unsigned i = 0; i < arguments.size(); ++i) + for (size_t i = 0; i < arguments.size(); ++i) if (functionType->takesArbitraryParameters()) args.emplace_back(IRVariable(*arguments[i]).commaSeparatedList()); else @@ -818,15 +818,43 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) { break; } - case FunctionType::Kind::GasLeft: + case FunctionType::Kind::AddMod: + case FunctionType::Kind::MulMod: { - define(_functionCall) << "gas()\n"; + static map functions = { + {FunctionType::Kind::AddMod, "addmod"}, + {FunctionType::Kind::MulMod, "mulmod"}, + }; + solAssert(functions.find(functionType->kind()) != functions.end(), ""); + solAssert(arguments.size() == 3 && parameterTypes.size() == 3, ""); + + IRVariable modulus(m_context.newYulVariable(), *(parameterTypes[2])); + define(modulus, *arguments[2]); + Whiskers templ("if iszero() { invalid() }\n"); + m_code << templ("modulus", modulus.name()).render(); + + string args; + for (size_t i = 0; i < 2; ++i) + args += expressionAsType(*arguments[i], *(parameterTypes[i])) + ", "; + args += modulus.name(); + define(_functionCall) << functions[functionType->kind()] << "(" << args << ")\n"; break; } + case FunctionType::Kind::GasLeft: case FunctionType::Kind::Selfdestruct: + case FunctionType::Kind::BlockHash: { - solAssert(arguments.size() == 1, ""); - define(_functionCall) << "selfdestruct(" << expressionAsType(*arguments.front(), *parameterTypes.front()) << ")\n"; + static map functions = { + {FunctionType::Kind::GasLeft, "gas"}, + {FunctionType::Kind::Selfdestruct, "selfdestruct"}, + {FunctionType::Kind::BlockHash, "blockhash"}, + }; + solAssert(functions.find(functionType->kind()) != functions.end(), ""); + + string args; + for (size_t i = 0; i < arguments.size(); ++i) + args += (args.empty() ? "" : ", ") + expressionAsType(*arguments[i], *(parameterTypes[i])); + define(_functionCall) << functions[functionType->kind()] << "(" << args << ")\n"; break; } case FunctionType::Kind::Log0: diff --git a/test/libsolidity/semanticTests/arithmetics/addmod_mulmod_zero.sol b/test/libsolidity/semanticTests/arithmetics/addmod_mulmod_zero.sol index 7585980e1..c70f195ba 100644 --- a/test/libsolidity/semanticTests/arithmetics/addmod_mulmod_zero.sol +++ b/test/libsolidity/semanticTests/arithmetics/addmod_mulmod_zero.sol @@ -18,6 +18,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint256): 0 -> FAILURE // g(uint256): 0 -> FAILURE diff --git a/test/libsolidity/semanticTests/builtinFunctions/blockhash.sol b/test/libsolidity/semanticTests/builtinFunctions/blockhash.sol new file mode 100644 index 000000000..075e6c395 --- /dev/null +++ b/test/libsolidity/semanticTests/builtinFunctions/blockhash.sol @@ -0,0 +1,17 @@ +contract C { + function f() public returns(bytes32) { + return blockhash(1); + } + function g() public returns(bytes32) { + return blockhash(2); + } + function h() public returns(bytes32) { + return blockhash(3); + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> 0x3737373737373737373737373737373737373737373737373737373737373738 +// g() -> 0x3737373737373737373737373737373737373737373737373737373737373739 +// h() -> 0x373737373737373737373737373737373737373737373737373737373737373a From debcc8c0564430938c5600629ce1208e080a3cff Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Tue, 14 Apr 2020 10:52:27 +0200 Subject: [PATCH 02/89] Add setimmutable and loadimmutable to dialect. --- libyul/AsmAnalysis.cpp | 14 ++-- libyul/backends/evm/AbstractAssembly.h | 5 ++ libyul/backends/evm/AsmCodeGen.cpp | 10 +++ libyul/backends/evm/AsmCodeGen.h | 3 + libyul/backends/evm/EVMAssembly.cpp | 10 +++ libyul/backends/evm/EVMAssembly.h | 3 + libyul/backends/evm/EVMCodeTransform.cpp | 8 +- libyul/backends/evm/EVMDialect.cpp | 83 +++++++++++++++---- libyul/backends/evm/EVMDialect.h | 7 +- libyul/backends/evm/NoOutputAssembly.cpp | 21 ++++- libyul/backends/evm/NoOutputAssembly.h | 3 + .../syntaxTests/inlineAssembly/immutables.sol | 11 +++ 12 files changed, 146 insertions(+), 32 deletions(-) create mode 100644 test/libsolidity/syntaxTests/inlineAssembly/immutables.sol diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index ca3f88c75..7858b70c4 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -306,11 +306,15 @@ vector AsmAnalyzer::operator()(FunctionCall const& _funCall) _funCall.functionName.location, "Function expects direct literals as arguments." ); - else if (!m_dataNames.count(std::get(arg).value)) - typeError( - _funCall.functionName.location, - "Unknown data object \"" + std::get(arg).value.str() + "\"." - ); + else if ( + _funCall.functionName.name.str() == "datasize" || + _funCall.functionName.name.str() == "dataoffset" + ) + if (!m_dataNames.count(std::get(arg).value)) + typeError( + _funCall.functionName.location, + "Unknown data object \"" + std::get(arg).value.str() + "\"." + ); } } std::reverse(argTypes.begin(), argTypes.end()); diff --git a/libyul/backends/evm/AbstractAssembly.h b/libyul/backends/evm/AbstractAssembly.h index 9187bb88d..2f86270b0 100644 --- a/libyul/backends/evm/AbstractAssembly.h +++ b/libyul/backends/evm/AbstractAssembly.h @@ -105,6 +105,11 @@ public: virtual void appendDataSize(SubID _sub) = 0; /// Appends the given data to the assembly and returns its ID. virtual SubID appendData(bytes const& _data) = 0; + + /// Appends loading an immutable variable. + virtual void appendImmutable(std::string const& _identifier) = 0; + /// Appends an assignment to an immutable variable. + virtual void appendImmutableAssignment(std::string const& _identifier) = 0; }; enum class IdentifierContext { LValue, RValue, VariableDeclaration }; diff --git a/libyul/backends/evm/AsmCodeGen.cpp b/libyul/backends/evm/AsmCodeGen.cpp index a864b0a09..eefff5b18 100644 --- a/libyul/backends/evm/AsmCodeGen.cpp +++ b/libyul/backends/evm/AsmCodeGen.cpp @@ -172,6 +172,16 @@ AbstractAssembly::SubID EthAssemblyAdapter::appendData(bytes const& _data) return subID; } +void EthAssemblyAdapter::appendImmutable(std::string const& _identifier) +{ + m_assembly.appendImmutable(_identifier); +} + +void EthAssemblyAdapter::appendImmutableAssignment(std::string const& _identifier) +{ + m_assembly.appendImmutableAssignment(_identifier); +} + EthAssemblyAdapter::LabelID EthAssemblyAdapter::assemblyTagToIdentifier(evmasm::AssemblyItem const& _tag) { u256 id = _tag.data(); diff --git a/libyul/backends/evm/AsmCodeGen.h b/libyul/backends/evm/AsmCodeGen.h index baab37b4c..e126ba2c0 100644 --- a/libyul/backends/evm/AsmCodeGen.h +++ b/libyul/backends/evm/AsmCodeGen.h @@ -61,6 +61,9 @@ public: void appendDataSize(SubID _sub) override; SubID appendData(bytes const& _data) override; + void appendImmutable(std::string const& _identifier) override; + void appendImmutableAssignment(std::string const& _identifier) override; + private: static LabelID assemblyTagToIdentifier(evmasm::AssemblyItem const& _tag); diff --git a/libyul/backends/evm/EVMAssembly.cpp b/libyul/backends/evm/EVMAssembly.cpp index 70711ffd6..47f7509a3 100644 --- a/libyul/backends/evm/EVMAssembly.cpp +++ b/libyul/backends/evm/EVMAssembly.cpp @@ -215,6 +215,16 @@ AbstractAssembly::SubID EVMAssembly::appendData(bytes const&) yulAssert(false, "Data not implemented."); } +void EVMAssembly::appendImmutable(std::string const&) +{ + yulAssert(false, "loadimmutable not implemented."); +} + +void EVMAssembly::appendImmutableAssignment(std::string const&) +{ + yulAssert(false, "setimmutable not implemented."); +} + void EVMAssembly::updateReference(size_t pos, size_t size, u256 value) { yulAssert(m_bytecode.size() >= size && pos <= m_bytecode.size() - size, ""); diff --git a/libyul/backends/evm/EVMAssembly.h b/libyul/backends/evm/EVMAssembly.h index 744d8738b..da4f5c037 100644 --- a/libyul/backends/evm/EVMAssembly.h +++ b/libyul/backends/evm/EVMAssembly.h @@ -83,6 +83,9 @@ public: void appendDataSize(SubID _sub) override; SubID appendData(bytes const& _data) override; + void appendImmutable(std::string const& _identifier) override; + void appendImmutableAssignment(std::string const& _identifier) override; + /// Resolves references inside the bytecode and returns the linker object. evmasm::LinkerObject finalize(); diff --git a/libyul/backends/evm/EVMCodeTransform.cpp b/libyul/backends/evm/EVMCodeTransform.cpp index 6ca55821d..b9c5cb0ee 100644 --- a/libyul/backends/evm/EVMCodeTransform.cpp +++ b/libyul/backends/evm/EVMCodeTransform.cpp @@ -257,13 +257,9 @@ void CodeTransform::operator()(FunctionCall const& _call) yulAssert(m_scope, ""); if (BuiltinFunctionForEVM const* builtin = m_dialect.builtin(_call.functionName.name)) - { - builtin->generateCode(_call, m_assembly, m_builtinContext, [&]() { - for (auto const& arg: _call.arguments | boost::adaptors::reversed) - visitExpression(arg); - m_assembly.setSourceLocation(_call.location); + builtin->generateCode(_call, m_assembly, m_builtinContext, [&](Expression const& _expression) { + visitExpression(_expression); }); - } else { m_assembly.setSourceLocation(_call.location); diff --git a/libyul/backends/evm/EVMDialect.cpp b/libyul/backends/evm/EVMDialect.cpp index 52cd1d23f..b5b5eda6e 100644 --- a/libyul/backends/evm/EVMDialect.cpp +++ b/libyul/backends/evm/EVMDialect.cpp @@ -41,6 +41,20 @@ using namespace solidity::util; namespace { + +void visitArguments( + AbstractAssembly& _assembly, + FunctionCall const& _call, + function _visitExpression +) +{ + for (auto const& arg: _call.arguments | boost::adaptors::reversed) + _visitExpression(arg); + + _assembly.setSourceLocation(_call.location); +} + + pair createEVMFunction( string const& _name, evmasm::Instruction _instruction @@ -58,12 +72,12 @@ pair createEVMFunction( f.literalArguments.reset(); f.instruction = _instruction; f.generateCode = [_instruction]( - FunctionCall const&, + FunctionCall const& _call, AbstractAssembly& _assembly, BuiltinContext&, - std::function _visitArguments + std::function _visitExpression ) { - _visitArguments(); + visitArguments(_assembly, _call, _visitExpression); _assembly.appendInstruction(_instruction); }; @@ -76,7 +90,7 @@ pair createFunction( size_t _returns, SideEffects _sideEffects, vector _literalArguments, - std::function)> _generateCode + std::function)> _generateCode ) { solAssert(_literalArguments.size() == _params || _literalArguments.empty(), ""); @@ -116,7 +130,7 @@ map createBuiltins(langutil::EVMVersion _evmVe FunctionCall const& _call, AbstractAssembly& _assembly, BuiltinContext& _context, - function + std::function ) { yulAssert(_context.currentObject, "No object available."); yulAssert(_call.arguments.size() == 1, ""); @@ -137,7 +151,7 @@ map createBuiltins(langutil::EVMVersion _evmVe FunctionCall const& _call, AbstractAssembly& _assembly, BuiltinContext& _context, - std::function + std::function ) { yulAssert(_context.currentObject, "No object available."); yulAssert(_call.arguments.size() == 1, ""); @@ -161,21 +175,58 @@ map createBuiltins(langutil::EVMVersion _evmVe SideEffects{false, false, false, false, true}, {}, []( - FunctionCall const&, + FunctionCall const& _call, AbstractAssembly& _assembly, BuiltinContext&, - std::function _visitArguments + std::function _visitExpression ) { - _visitArguments(); + visitArguments(_assembly, _call, _visitExpression); _assembly.appendInstruction(evmasm::Instruction::CODECOPY); } )); + builtins.emplace(createFunction( + "setimmutable", + 2, + 0, + SideEffects{false, false, false, false, true}, + {true, false}, + []( + FunctionCall const& _call, + AbstractAssembly& _assembly, + BuiltinContext&, + std::function _visitExpression + ) { + solAssert(_call.arguments.size() == 2, ""); + + _visitExpression(_call.arguments[1]); + _assembly.setSourceLocation(_call.location); + YulString identifier = std::get(_call.arguments.front()).value; + _assembly.appendImmutableAssignment(identifier.str()); + } + )); + builtins.emplace(createFunction( + "loadimmutable", + 1, + 1, + SideEffects{}, + {true}, + []( + FunctionCall const& _call, + AbstractAssembly& _assembly, + BuiltinContext&, + std::function + ) { + solAssert(_call.arguments.size() == 1, ""); + _assembly.appendImmutable(std::get(_call.arguments.front()).value.str()); + } + )); } return builtins; } } + EVMDialect::EVMDialect(langutil::EVMVersion _evmVersion, bool _objectAccess): m_objectAccess(_objectAccess), m_evmVersion(_evmVersion), @@ -268,23 +319,23 @@ EVMDialectTyped::EVMDialectTyped(langutil::EVMVersion _evmVersion, bool _objectA m_functions["popbool"_yulstring].name = "popbool"_yulstring; m_functions["popbool"_yulstring].parameters = {"bool"_yulstring}; m_functions.insert(createFunction("bool_to_u256", 1, 1, {}, {}, []( - FunctionCall const&, - AbstractAssembly&, + FunctionCall const& _call, + AbstractAssembly& _assembly, BuiltinContext&, - std::function _visitArguments + std::function _visitExpression ) { - _visitArguments(); + visitArguments(_assembly, _call, _visitExpression); })); m_functions["bool_to_u256"_yulstring].parameters = {"bool"_yulstring}; m_functions["bool_to_u256"_yulstring].returns = {"u256"_yulstring}; m_functions.insert(createFunction("u256_to_bool", 1, 1, {}, {}, []( - FunctionCall const&, + FunctionCall const& _call, AbstractAssembly& _assembly, BuiltinContext&, - std::function _visitArguments + std::function _visitExpression ) { // A value larger than 1 causes an invalid instruction. - _visitArguments(); + visitArguments(_assembly, _call, _visitExpression); _assembly.appendConstant(2); _assembly.appendInstruction(evmasm::Instruction::DUP2); _assembly.appendInstruction(evmasm::Instruction::LT); diff --git a/libyul/backends/evm/EVMDialect.h b/libyul/backends/evm/EVMDialect.h index 00852fe34..68f0b7046 100644 --- a/libyul/backends/evm/EVMDialect.h +++ b/libyul/backends/evm/EVMDialect.h @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -49,9 +50,9 @@ struct BuiltinFunctionForEVM: public BuiltinFunction { std::optional instruction; /// Function to generate code for the given function call and append it to the abstract - /// assembly. The fourth parameter is called to visit (and generate code for) the arguments - /// from right to left. - std::function)> generateCode; + /// assembly. The fourth parameter is called to visit (and generate code for) the given + /// argument. + std::function)> generateCode; }; diff --git a/libyul/backends/evm/NoOutputAssembly.cpp b/libyul/backends/evm/NoOutputAssembly.cpp index 8d01c2c5e..8e26014a9 100644 --- a/libyul/backends/evm/NoOutputAssembly.cpp +++ b/libyul/backends/evm/NoOutputAssembly.cpp @@ -19,10 +19,14 @@ */ #include + #include #include +#include + + using namespace std; using namespace solidity; using namespace solidity::yul; @@ -142,6 +146,17 @@ AbstractAssembly::SubID NoOutputAssembly::appendData(bytes const&) return 1; } + +void NoOutputAssembly::appendImmutable(std::string const&) +{ + yulAssert(false, "loadimmutable not implemented."); +} + +void NoOutputAssembly::appendImmutableAssignment(std::string const&) +{ + yulAssert(false, "setimmutable not implemented."); +} + NoOutputEVMDialect::NoOutputEVMDialect(EVMDialect const& _copyFrom): EVMDialect(_copyFrom.evmVersion(), _copyFrom.providesObjectAccess()) { @@ -149,9 +164,11 @@ NoOutputEVMDialect::NoOutputEVMDialect(EVMDialect const& _copyFrom): { size_t parameters = fun.second.parameters.size(); size_t returns = fun.second.returns.size(); - fun.second.generateCode = [=](FunctionCall const&, AbstractAssembly& _assembly, BuiltinContext&, std::function _visitArguments) + fun.second.generateCode = [=](FunctionCall const& _call, AbstractAssembly& _assembly, BuiltinContext&, std::function _visitExpression) { - _visitArguments(); + for (auto const& arg: _call.arguments | boost::adaptors::reversed) + _visitExpression(arg); + for (size_t i = 0; i < parameters; i++) _assembly.appendInstruction(evmasm::Instruction::POP); diff --git a/libyul/backends/evm/NoOutputAssembly.h b/libyul/backends/evm/NoOutputAssembly.h index d72f9ea66..7101a30f5 100644 --- a/libyul/backends/evm/NoOutputAssembly.h +++ b/libyul/backends/evm/NoOutputAssembly.h @@ -71,6 +71,9 @@ public: void appendDataSize(SubID _sub) override; SubID appendData(bytes const& _data) override; + void appendImmutable(std::string const& _identifier) override; + void appendImmutableAssignment(std::string const& _identifier) override; + private: bool m_evm15 = false; ///< if true, switch to evm1.5 mode int m_stackHeight = 0; diff --git a/test/libsolidity/syntaxTests/inlineAssembly/immutables.sol b/test/libsolidity/syntaxTests/inlineAssembly/immutables.sol new file mode 100644 index 000000000..17b30b8d8 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/immutables.sol @@ -0,0 +1,11 @@ +contract C { + function f() public pure { + assembly { + setimmutable("abc", 0) + loadimmutable("abc") + } + } +} +// ---- +// DeclarationError: (63-75): Function not found. +// DeclarationError: (92-105): Function not found. From 51ccb1519fdb454ef9b4dc88d14da0b9a77d0f0e Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 2 Apr 2020 20:06:52 +0200 Subject: [PATCH 03/89] Yul codegen for immutables. --- .../codegen/ir/IRGenerationContext.cpp | 31 ++++++++ libsolidity/codegen/ir/IRGenerationContext.h | 17 +++++ libsolidity/codegen/ir/IRGenerator.cpp | 76 +++++++++++++++---- .../codegen/ir/IRGeneratorForStatements.cpp | 53 +++++++++---- libsolidity/codegen/ir/IRLValue.h | 8 +- .../immutable/assign_at_declaration.sol | 2 + .../semanticTests/immutable/getter.sol | 2 + .../semanticTests/immutable/inheritance.sol | 2 + .../immutable/internal_function_pointer.sol | 2 + .../semanticTests/immutable/stub.sol | 2 + .../semanticTests/immutable/use_scratch.sol | 2 + 11 files changed, 166 insertions(+), 31 deletions(-) diff --git a/libsolidity/codegen/ir/IRGenerationContext.cpp b/libsolidity/codegen/ir/IRGenerationContext.cpp index 43e9f95e2..ed3b989d0 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.cpp +++ b/libsolidity/codegen/ir/IRGenerationContext.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -76,6 +77,36 @@ IRVariable const& IRGenerationContext::localVariable(VariableDeclaration const& return m_localVariables.at(&_varDecl); } +void IRGenerationContext::registerImmutableVariable(VariableDeclaration const& _variable) +{ + solAssert(_variable.immutable(), "Attempted to register a non-immutable variable as immutable."); + solUnimplementedAssert( + _variable.annotation().type->isValueType(), + "Only immutable variables of value type are supported." + ); + solAssert(m_reservedMemory.has_value(), "Reserved memory has already been reset."); + m_immutableVariables[&_variable] = CompilerUtils::generalPurposeMemoryStart + *m_reservedMemory; + solAssert(_variable.annotation().type->memoryHeadSize() == 32, "Memory writes might overlap."); + *m_reservedMemory += _variable.annotation().type->memoryHeadSize(); +} + +size_t IRGenerationContext::immutableMemoryOffset(VariableDeclaration const& _variable) const +{ + solAssert( + m_immutableVariables.count(&_variable), + "Unknown immutable variable: " + _variable.name() + ); + return m_immutableVariables.at(&_variable); +} + +size_t IRGenerationContext::reservedMemory() +{ + solAssert(m_reservedMemory.has_value(), "Reserved memory was used before."); + size_t reservedMemory = *m_reservedMemory; + m_reservedMemory = std::nullopt; + return reservedMemory; +} + void IRGenerationContext::addStateVariable( VariableDeclaration const& _declaration, u256 _storageOffset, diff --git a/libsolidity/codegen/ir/IRGenerationContext.h b/libsolidity/codegen/ir/IRGenerationContext.h index 0a07f2f29..a7eab7ceb 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.h +++ b/libsolidity/codegen/ir/IRGenerationContext.h @@ -81,6 +81,17 @@ public: bool isLocalVariable(VariableDeclaration const& _varDecl) const { return m_localVariables.count(&_varDecl); } IRVariable const& localVariable(VariableDeclaration const& _varDecl); + /// Registers an immutable variable of the contract. + /// Should only be called at construction time. + void registerImmutableVariable(VariableDeclaration const& _varDecl); + /// @returns the reserved memory for storing the value of the + /// immutable @a _variable during contract creation. + size_t immutableMemoryOffset(VariableDeclaration const& _variable) const; + /// @returns the reserved memory and resets it to mark it as used. + /// Intended to be used only once for initializing the free memory pointer + /// to after the area used for immutables. + size_t reservedMemory(); + void addStateVariable(VariableDeclaration const& _varDecl, u256 _storageOffset, unsigned _byteOffset); bool isStateVariable(VariableDeclaration const& _varDecl) const { return m_stateVariables.count(&_varDecl); } std::pair storageLocationOfVariable(VariableDeclaration const& _varDecl) const @@ -123,6 +134,12 @@ private: OptimiserSettings m_optimiserSettings; ContractDefinition const* m_mostDerivedContract = nullptr; std::map m_localVariables; + /// Memory offsets reserved for the values of immutable variables during contract creation. + /// This map is empty in the runtime context. + std::map m_immutableVariables; + /// Total amount of reserved memory. Reserved memory is used to store + /// immutable variables during contract creation. + std::optional m_reservedMemory = {0}; /// Storage offsets of state variables std::map> m_stateVariables; MultiUseYulFunctionCollector m_functions; diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index aed373c10..fb466f3ba 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -114,6 +114,8 @@ string IRGenerator::generate( )"); resetContext(_contract); + for (VariableDeclaration const* var: ContractType(_contract).immutableVariables()) + m_context.registerImmutableVariable(*var); t("CreationObject", m_context.creationObjectName(_contract)); t("memoryInit", memoryInit()); @@ -142,6 +144,7 @@ string IRGenerator::generate( t("subObjects", subObjectSources(m_context.subObjectsCreated())); resetContext(_contract); + // Do not register immutables to avoid assignment. t("RuntimeObject", m_context.runtimeObjectName(_contract)); t("dispatch", dispatchRoutine(_contract)); generateQueuedFunctions(); @@ -200,7 +203,6 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) Type const* type = _varDecl.annotation().type; solAssert(!_varDecl.isConstant(), ""); - solAssert(!_varDecl.immutable(), ""); solAssert(_varDecl.isStateVariable(), ""); if (auto const* mappingType = dynamic_cast(type)) @@ -254,17 +256,32 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) solUnimplementedAssert(type->isValueType(), ""); return m_context.functionCollector().createFunction(functionName, [&]() { - pair slot_offset = m_context.storageLocationOfVariable(_varDecl); + if (_varDecl.immutable()) + { + solUnimplementedAssert(type->sizeOnStack() == 1, ""); + return Whiskers(R"( + function () -> rval { + rval := loadimmutable("") + } + )") + ("functionName", functionName) + ("id", to_string(_varDecl.id())) + .render(); + } + else + { + pair slot_offset = m_context.storageLocationOfVariable(_varDecl); - return Whiskers(R"( - function () -> rval { - rval := () - } - )") - ("functionName", functionName) - ("readStorage", m_utils.readFromStorage(*type, slot_offset.second, false)) - ("slot", slot_offset.first.str()) - .render(); + return Whiskers(R"( + function () -> rval { + rval := () + } + )") + ("functionName", functionName) + ("readStorage", m_utils.readFromStorage(*type, slot_offset.second, false)) + ("slot", slot_offset.first.str()) + .render(); + } }); } } @@ -325,7 +342,7 @@ string IRGenerator::initStateVariables(ContractDefinition const& _contract) { IRGeneratorForStatements generator{m_context, m_utils}; for (VariableDeclaration const* variable: _contract.stateVariables()) - if (!variable->isConstant() && !variable->immutable()) + if (!variable->isConstant()) generator.initializeStateVar(*variable); return generator.code(); @@ -391,10 +408,41 @@ void IRGenerator::generateImplicitConstructors(ContractDefinition const& _contra string IRGenerator::deployCode(ContractDefinition const& _contract) { Whiskers t(R"X( + <#loadImmutables> + let := mload() + + codecopy(0, dataoffset(""), datasize("")) + + <#storeImmutables> + setimmutable("", ) + + return(0, datasize("")) )X"); t("object", m_context.runtimeObjectName(_contract)); + + vector> loadImmutables; + vector> storeImmutables; + + for (VariableDeclaration const* immutable: ContractType(_contract).immutableVariables()) + { + solUnimplementedAssert(immutable->type()->isValueType(), ""); + solUnimplementedAssert(immutable->type()->sizeOnStack() == 1, ""); + string yulVar = m_context.newYulVariable(); + loadImmutables.emplace_back(map{ + {"var"s, yulVar}, + {"memoryOffset"s, to_string(m_context.immutableMemoryOffset(*immutable))} + }); + storeImmutables.emplace_back(map{ + {"var"s, yulVar}, + {"immutableName"s, to_string(immutable->id())} + }); + } + t("loadImmutables", std::move(loadImmutables)); + // reverse order to ease stack strain + reverse(storeImmutables.begin(), storeImmutables.end()); + t("storeImmutables", std::move(storeImmutables)); return t.render(); } @@ -489,9 +537,9 @@ string IRGenerator::memoryInit() // and thus can assume all memory to be zero, including the contents of // the "zero memory area" (the position CompilerUtils::zeroPointer points to). return - Whiskers{"mstore(, )"} + Whiskers{"mstore(, )"} ("memPtr", to_string(CompilerUtils::freeMemoryPointer)) - ("generalPurposeStart", to_string(CompilerUtils::generalPurposeMemoryStart)) + ("freeMemoryStart", to_string(CompilerUtils::generalPurposeMemoryStart + m_context.reservedMemory())) .render(); } diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 755110c27..84cf53cd2 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -140,20 +140,21 @@ string IRGeneratorForStatements::code() const void IRGeneratorForStatements::initializeStateVar(VariableDeclaration const& _varDecl) { - solAssert(m_context.isStateVariable(_varDecl), "Must be a state variable."); + solAssert(_varDecl.immutable() || m_context.isStateVariable(_varDecl), "Must be immutable or a state variable."); solAssert(!_varDecl.isConstant(), ""); - solAssert(!_varDecl.immutable(), ""); - if (_varDecl.value()) - { - _varDecl.value()->accept(*this); - writeToLValue(IRLValue{ - *_varDecl.annotation().type, - IRLValue::Storage{ - util::toCompactHexWithPrefix(m_context.storageLocationOfVariable(_varDecl).first), - m_context.storageLocationOfVariable(_varDecl).second - } - }, *_varDecl.value()); - } + if (!_varDecl.value()) + return; + + _varDecl.value()->accept(*this); + writeToLValue( + _varDecl.immutable() ? + IRLValue{*_varDecl.annotation().type, IRLValue::Immutable{&_varDecl}} : + IRLValue{*_varDecl.annotation().type, IRLValue::Storage{ + util::toCompactHexWithPrefix(m_context.storageLocationOfVariable(_varDecl).first), + m_context.storageLocationOfVariable(_varDecl).second + }}, + *_varDecl.value() + ); } void IRGeneratorForStatements::initializeLocalVar(VariableDeclaration const& _varDecl) @@ -1517,8 +1518,12 @@ void IRGeneratorForStatements::handleVariableReference( // If the value is visited twice, `defineExpression` is called twice on // the same expression. solUnimplementedAssert(!_variable.isConstant(), ""); - solUnimplementedAssert(!_variable.immutable(), ""); - if (m_context.isLocalVariable(_variable)) + if (_variable.isStateVariable() && _variable.immutable()) + setLValue(_referencingExpression, IRLValue{ + *_variable.annotation().type, + IRLValue::Immutable{&_variable} + }); + else if (m_context.isLocalVariable(_variable)) setLValue(_referencingExpression, IRLValue{ *_variable.annotation().type, IRLValue::Stack{m_context.localVariable(_variable)} @@ -1939,6 +1944,18 @@ void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable } }, [&](IRLValue::Stack const& _stack) { assign(_stack.variable, _value); }, + [&](IRLValue::Immutable const& _immutable) + { + solUnimplementedAssert(_lvalue.type.isValueType(), ""); + solUnimplementedAssert(_lvalue.type.sizeOnStack() == 1, ""); + solAssert(_lvalue.type == *_immutable.variable->type(), ""); + size_t memOffset = m_context.immutableMemoryOffset(*_immutable.variable); + + IRVariable prepared(m_context.newYulVariable(), _lvalue.type); + define(prepared, _value); + + m_code << "mstore(" << to_string(memOffset) << ", " << prepared.commaSeparatedList() << ")\n"; + }, [&](IRLValue::Tuple const& _tuple) { auto components = std::move(_tuple.components); for (size_t i = 0; i < components.size(); i++) @@ -1994,6 +2011,12 @@ IRVariable IRGeneratorForStatements::readFromLValue(IRLValue const& _lvalue) [&](IRLValue::Stack const& _stack) { define(result, _stack.variable); }, + [&](IRLValue::Immutable const& _immutable) { + solUnimplementedAssert(_lvalue.type.isValueType(), ""); + solUnimplementedAssert(_lvalue.type.sizeOnStack() == 1, ""); + solAssert(_lvalue.type == *_immutable.variable->type(), ""); + define(result) << "loadimmutable(\"" << to_string(_immutable.variable->id()) << "\")\n"; + }, [&](IRLValue::Tuple const&) { solAssert(false, "Attempted to read from tuple lvalue."); } diff --git a/libsolidity/codegen/ir/IRLValue.h b/libsolidity/codegen/ir/IRLValue.h index 02d46b6e4..c5eadc9b2 100644 --- a/libsolidity/codegen/ir/IRLValue.h +++ b/libsolidity/codegen/ir/IRLValue.h @@ -35,6 +35,10 @@ struct IRLValue { IRVariable variable; }; + struct Immutable + { + VariableDeclaration const* variable = nullptr; + }; struct Storage { std::string const slot; @@ -59,7 +63,7 @@ struct IRLValue { std::vector> components; }; - std::variant kind; + std::variant kind; }; -} \ No newline at end of file +} diff --git a/test/libsolidity/semanticTests/immutable/assign_at_declaration.sol b/test/libsolidity/semanticTests/immutable/assign_at_declaration.sol index 3f71a31e0..030a3544c 100644 --- a/test/libsolidity/semanticTests/immutable/assign_at_declaration.sol +++ b/test/libsolidity/semanticTests/immutable/assign_at_declaration.sol @@ -4,5 +4,7 @@ contract A { return a; } } +// ==== +// compileViaYul: also // ---- // f() -> 2 diff --git a/test/libsolidity/semanticTests/immutable/getter.sol b/test/libsolidity/semanticTests/immutable/getter.sol index bb4b191cf..c0997744e 100644 --- a/test/libsolidity/semanticTests/immutable/getter.sol +++ b/test/libsolidity/semanticTests/immutable/getter.sol @@ -1,5 +1,7 @@ contract C { uint immutable public x = 1; } +// ==== +// compileViaYul: also // ---- // x() -> 1 diff --git a/test/libsolidity/semanticTests/immutable/inheritance.sol b/test/libsolidity/semanticTests/immutable/inheritance.sol index f61009f60..bca0ee889 100644 --- a/test/libsolidity/semanticTests/immutable/inheritance.sol +++ b/test/libsolidity/semanticTests/immutable/inheritance.sol @@ -26,5 +26,7 @@ contract D is B, C { return (a, b, c, d); } } +// ==== +// compileViaYul: also // ---- // f() -> 4, 3, 2, 1 diff --git a/test/libsolidity/semanticTests/immutable/internal_function_pointer.sol b/test/libsolidity/semanticTests/immutable/internal_function_pointer.sol index 0673aafb5..0119a90a2 100644 --- a/test/libsolidity/semanticTests/immutable/internal_function_pointer.sol +++ b/test/libsolidity/semanticTests/immutable/internal_function_pointer.sol @@ -10,6 +10,8 @@ contract C { return z(); } } +// ==== +// compileViaYul: also // ---- // f() -> 7 // callZ() -> 7 diff --git a/test/libsolidity/semanticTests/immutable/stub.sol b/test/libsolidity/semanticTests/immutable/stub.sol index 387541066..a800ab904 100644 --- a/test/libsolidity/semanticTests/immutable/stub.sol +++ b/test/libsolidity/semanticTests/immutable/stub.sol @@ -9,5 +9,7 @@ contract C { return (x+x,y); } } +// ==== +// compileViaYul: also // ---- // f() -> 84, 23 diff --git a/test/libsolidity/semanticTests/immutable/use_scratch.sol b/test/libsolidity/semanticTests/immutable/use_scratch.sol index d83da476d..442ef5636 100644 --- a/test/libsolidity/semanticTests/immutable/use_scratch.sol +++ b/test/libsolidity/semanticTests/immutable/use_scratch.sol @@ -13,6 +13,8 @@ contract C { return (x+x,y); } } +// ==== +// compileViaYul: also // ---- // constructor(): 3 -> // f() -> 84, 23 From 3738cff6e6b7a011df48830358e247fbd6a7e346 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 27 Apr 2020 19:35:35 +0200 Subject: [PATCH 04/89] Test updates. --- test/cmdlineTests/standard_ir_requested/output.json | 1 + test/cmdlineTests/yul_string_format_ascii/output.json | 1 + test/cmdlineTests/yul_string_format_ascii_bytes32/output.json | 1 + .../yul_string_format_ascii_bytes32_from_number/output.json | 1 + test/cmdlineTests/yul_string_format_ascii_long/output.json | 1 + test/cmdlineTests/yul_string_format_hex/output.json | 1 + 6 files changed, 6 insertions(+) diff --git a/test/cmdlineTests/standard_ir_requested/output.json b/test/cmdlineTests/standard_ir_requested/output.json index bf9b20ed8..69b95a683 100644 --- a/test/cmdlineTests/standard_ir_requested/output.json +++ b/test/cmdlineTests/standard_ir_requested/output.json @@ -14,6 +14,7 @@ object \"C_6\" { constructor_C_6() codecopy(0, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\")) + return(0, datasize(\"C_6_deployed\")) function constructor_C_6() { diff --git a/test/cmdlineTests/yul_string_format_ascii/output.json b/test/cmdlineTests/yul_string_format_ascii/output.json index 81fa10ca7..215146d1d 100644 --- a/test/cmdlineTests/yul_string_format_ascii/output.json +++ b/test/cmdlineTests/yul_string_format_ascii/output.json @@ -14,6 +14,7 @@ object \"C_10\" { constructor_C_10() codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\")) + return(0, datasize(\"C_10_deployed\")) function constructor_C_10() { diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json index a171f87b5..7b2291843 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json @@ -14,6 +14,7 @@ object \"C_10\" { constructor_C_10() codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\")) + return(0, datasize(\"C_10_deployed\")) function constructor_C_10() { diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json index 3dccf690d..ef647f39e 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json @@ -14,6 +14,7 @@ object \"C_10\" { constructor_C_10() codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\")) + return(0, datasize(\"C_10_deployed\")) function constructor_C_10() { diff --git a/test/cmdlineTests/yul_string_format_ascii_long/output.json b/test/cmdlineTests/yul_string_format_ascii_long/output.json index 77360e5a4..8243cd93e 100644 --- a/test/cmdlineTests/yul_string_format_ascii_long/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_long/output.json @@ -14,6 +14,7 @@ object \"C_10\" { constructor_C_10() codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\")) + return(0, datasize(\"C_10_deployed\")) function constructor_C_10() { diff --git a/test/cmdlineTests/yul_string_format_hex/output.json b/test/cmdlineTests/yul_string_format_hex/output.json index 81853dadb..70f2fc3de 100644 --- a/test/cmdlineTests/yul_string_format_hex/output.json +++ b/test/cmdlineTests/yul_string_format_hex/output.json @@ -14,6 +14,7 @@ object \"C_10\" { constructor_C_10() codecopy(0, dataoffset(\"C_10_deployed\"), datasize(\"C_10_deployed\")) + return(0, datasize(\"C_10_deployed\")) function constructor_C_10() { From ea7e751750c7387b300613a15df25748058bbaf8 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 4 May 2020 15:05:14 +0200 Subject: [PATCH 05/89] Documentation. --- docs/yul.rst | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/docs/yul.rst b/docs/yul.rst index 2fcae1175..6e8654ff5 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -885,13 +885,6 @@ the ``dup`` and ``swap`` instructions as well as ``jump`` instructions, labels a | gaslimit() | | F | block gas limit of the current block | +-------------------------+-----+---+-----------------------------------------------------------------+ -There are three additional functions, ``datasize(x)``, ``dataoffset(x)`` and ``datacopy(t, f, l)``, -which are used to access other parts of a Yul object. - -``datasize`` and ``dataoffset`` can only take string literals (the names of other objects) -as arguments and return the size and offset in the data area, respectively. -For the EVM, the ``datacopy`` function is equivalent to ``codecopy``. - .. _yul-call-return-area: .. note:: @@ -903,6 +896,32 @@ For the EVM, the ``datacopy`` function is equivalent to ``codecopy``. The remaining bytes will retain their values as of before the call. If the call fails (it returns ``0``), nothing is written to that area, but you can still retrieve the failure data using ``returndatacopy``. + +In some internal dialects, there are additional functions: + +datasize, dataoffset, datacopy +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The functions ``datasize(x)``, ``dataoffset(x)`` and ``datacopy(t, f, l)``, +are used to access other parts of a Yul object. + +``datasize`` and ``dataoffset`` can only take string literals (the names of other objects) +as arguments and return the size and offset in the data area, respectively. +For the EVM, the ``datacopy`` function is equivalent to ``codecopy``. + + +setimmutable, loadimmutable +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The functions ``setimmutable("name", value)`` and ``loadimmutable("name")`` are +used for the immutable mechanism in Solidity and do not nicely map to pur Yul. +The function ``setimmutable`` assumes that the runtime code of a contract +is currently copied to memory at offsot zero. The call to ``setimmutable("name", value)`` +will store ``value`` at all points in memory that contain a call to +``loadimmutable("name")``. + + + .. _yul-object: Specification of Yul Object From d037f7a3c599c04e1909107f019c43b30b162644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 4 May 2020 15:45:08 +0200 Subject: [PATCH 06/89] docs: Info about --yul-optimizations and optimizer steps in Yul section --- docs/yul.rst | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/docs/yul.rst b/docs/yul.rst index 6e8654ff5..b99dd18c1 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -1034,3 +1034,56 @@ If you want to use Solidity in stand-alone Yul mode, you activate the optimizer solc --strict-assembly --optimize In Solidity mode, the Yul optimizer is activated together with the regular optimizer. + +Optimization step sequence +-------------------------- + +By default the Yul optimizer applies its predefined sequence of optimization steps to the generated assembly. +You can override this sequence and supply your own using the `--yul-optimizations` option when compiling +in Solidity mode: + +.. code-block:: sh + + solc --optimize --ir-optimized --yul-optimizations 'dhfoD[xarrscLMcCTU]uljmul' + +By enclosing part of the sequence in square brackets (`[]`) you tell the optimizer to repeatedly +apply that part until it no longer improves the size of the resulting assembly. +You can use brackets multiple times in a single sequence but they cannot be nested. + +The following optimization steps are available: + +============ =============================== +Abbreviation Full name +============ =============================== +f `BlockFlattener` +l `CircularReferencesPruner` +c `CommonSubexpressionEliminator` +C `ConditionalSimplifier` +U `ConditionalUnsimplifier` +n `ControlFlowSimplifier` +D `DeadCodeEliminator` +v `EquivalentFunctionCombiner` +e `ExpressionInliner` +j `ExpressionJoiner` +s `ExpressionSimplifier` +x `ExpressionSplitter` +I `ForLoopConditionIntoBody` +O `ForLoopConditionOutOfBody` +o `ForLoopInitRewriter` +i `FullInliner` +g `FunctionGrouper` +h `FunctionHoister` +T `LiteralRematerialiser` +L `LoadResolver` +M `LoopInvariantCodeMotion` +r `RedundantAssignEliminator` +m `Rematerialiser` +V `SSAReverser` +a `SSATransform` +t `StructuralSimplifier` +u `UnusedPruner` +d `VarDeclInitializer` +============ =============================== + +Some steps depend on properties ensured by `BlockFlattener`, `FunctionGrouper`, `ForLoopInitRewriter`. +For this reason the Yul optimizer always applies them before applying any steps supplied by the user. From 457cc754d02d54bf4c4a576d5e32b6a79b633047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 4 May 2020 15:45:44 +0200 Subject: [PATCH 07/89] docs: Info about optimizerSteps field in Standard JSON input and metadata listings --- docs/metadata.rst | 8 ++++++-- docs/using-the-compiler.rst | 5 ++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/metadata.rst b/docs/metadata.rst index 0c8ae47f1..96a02c43a 100644 --- a/docs/metadata.rst +++ b/docs/metadata.rst @@ -82,8 +82,12 @@ explanatory purposes. deduplicate: false, cse: false, constantOptimizer: false, - yul: false, - yulDetails: {} + yul: true, + // Optional: Only present if "yul" is "true" + yulDetails: { + stackAllocation: false, + optimizerSteps: "dhfoDgvulfnTUtnIf..." + } } }, metadata: { diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index ea573ed70..84b4ef9d7 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -231,7 +231,10 @@ Input Description "yulDetails": { // Improve allocation of stack slots for variables, can free up stack slots early. // Activated by default if the Yul optimizer is activated. - "stackAllocation": true + "stackAllocation": true, + // Select optimization steps to be applied. + // Optional, the optimizer will use the default sequence if omitted. + "optimizerSteps": "dhfoDgvulfnTUtnIf..." } } }, From 14ba31f64c73d4156469d333c0b8de4a68d26e8a Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 4 May 2020 18:09:10 +0200 Subject: [PATCH 08/89] Set version to 0.6.8. --- CMakeLists.txt | 2 +- Changelog.md | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a5026bad..ee698a715 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ include(EthPolicy) eth_policy() # project name and version should be set after cmake_policy CMP0048 -set(PROJECT_VERSION "0.6.7") +set(PROJECT_VERSION "0.6.8") # OSX target needed in order to support std::visit set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14") project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX) diff --git a/Changelog.md b/Changelog.md index 21d45156c..0b3749be9 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,18 @@ +### 0.6.8 (unreleased) + +Language Features: + + + +Compiler Features: + + + +Bugfixes: + + + + ### 0.6.7 (2020-05-04) Language Features: From 38486f47a760a9541f646fef1e9a2be8fd1db2a5 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 16 Apr 2020 11:57:07 +0200 Subject: [PATCH 09/89] Example ERC20 contract in Yul. --- docs/yul.rst | 197 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) diff --git a/docs/yul.rst b/docs/yul.rst index b99dd18c1..c200558b0 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -104,6 +104,8 @@ less-than comparison. } } +At the :ref:`end of the section `, a complete implementation of +the ERC-20 standard can be found. @@ -1087,3 +1089,198 @@ d `VarDeclInitializer` Some steps depend on properties ensured by `BlockFlattener`, `FunctionGrouper`, `ForLoopInitRewriter`. For this reason the Yul optimizer always applies them before applying any steps supplied by the user. + + +.. _erc20yul: + +Complete ERC20 Example +====================== + +.. code-block:: yul + + object "Token" { + code { + // Store the creator in slot zero. + sstore(0, caller()) + + // Deploy the contract + datacopy(0, dataoffset("runtime"), datasize("runtime")) + return(0, datasize("runtime")) + } + object "runtime" { + code { + // Protection against sending Ether + require(iszero(callvalue())) + + // Dispatcher + switch selector() + case 0x70a08231 /* "balanceOf(address)" */ { + returnUint(balanceOf(decodeAsAddress(0))) + } + case 0x18160ddd /* "totalSupply()" */ { + returnUint(totalSupply()) + } + case 0xa9059cbb /* "transfer(address,uint256)" */ { + transfer(decodeAsAddress(0), decodeAsUint(1)) + returnTrue() + } + case 0x23b872dd /* "transferFrom(address,address,uint256)" */ { + transferFrom(decodeAsAddress(0), decodeAsAddress(1), decodeAsUint(2)) + returnTrue() + } + case 0x095ea7b3 /* "approve(address,uint256)" */ { + approve(decodeAsAddress(0), decodeAsUint(1)) + returnTrue() + } + case 0xdd62ed3e /* "allowance(address,address)" */ { + returnUint(allowance(decodeAsAddress(0), decodeAsAddress(1))) + } + case 0x40c10f19 /* "mint(address,uint256)" */ { + mint(decodeAsAddress(0), decodeAsUint(1)) + returnTrue() + } + default { + revert(0, 0) + } + + function mint(account, amount) { + require(calledByOwner()) + + mintTokens(amount) + addToBalance(account, amount) + emitTransfer(0, account, amount) + } + function transfer(to, amount) { + executeTransfer(caller(), to, amount) + } + function approve(spender, amount) { + revertIfZeroAddress(spender) + setAllowance(caller(), spender, amount) + emitApproval(caller(), spender, amount) + } + function transferFrom(from, to, amount) { + decreaseAllowanceBy(from, caller(), amount) + executeTransfer(from, to, amount) + } + + function executeTransfer(from, to, amount) { + revertIfZeroAddress(to) + deductFromBalance(from, amount) + addToBalance(to, amount) + emitTransfer(from, to, amount) + } + + + /* ---------- calldata decoding functions ----------- */ + function selector() -> s { + s := div(calldataload(0), 0x100000000000000000000000000000000000000000000000000000000) + } + + function decodeAsAddress(offset) -> v { + v := decodeAsUint(offset) + if iszero(iszero(and(v, not(0xffffffffffffffffffffffffffffffffffffffff)))) { + revert(0, 0) + } + } + function decodeAsUint(offset) -> v { + let pos := add(4, mul(offset, 0x20)) + if lt(calldatasize(), add(pos, 0x20)) { + revert(0, 0) + } + v := calldataload(pos) + } + /* ---------- calldata encoding functions ---------- */ + function returnUint(v) { + mstore(0, v) + return(0, 0x20) + } + function returnTrue() { + returnUint(1) + } + + /* -------- events ---------- */ + function emitTransfer(from, to, amount) { + let signatureHash := 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef + emitEvent(signatureHash, from, to, amount) + } + function emitApproval(from, spender, amount) { + let signatureHash := 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925 + emitEvent(signatureHash, from, spender, amount) + } + function emitEvent(signatureHash, indexed1, indexed2, nonIndexed) { + mstore(0, nonIndexed) + log3(0, 0x20, signatureHash, indexed1, indexed2) + } + + /* -------- storage layout ---------- */ + function ownerPos() -> p { p := 0 } + function totalSupplyPos() -> p { p := 1 } + function accountToStorageOffset(account) -> offset { + offset := add(0x1000, account) + } + function allowanceStorageOffset(account, spender) -> offset { + offset := accountToStorageOffset(account) + mstore(0, offset) + mstore(0x20, spender) + offset := keccak256(0, 0x40) + } + + /* -------- storage access ---------- */ + function owner() -> o { + o := sload(ownerPos()) + } + function totalSupply() -> supply { + supply := sload(totalSupplyPos()) + } + function mintTokens(amount) { + sstore(totalSupplyPos(), safeAdd(totalSupply(), amount)) + } + function balanceOf(account) -> bal { + bal := sload(accountToStorageOffset(account)) + } + function addToBalance(account, amount) { + let offset := accountToStorageOffset(account) + sstore(offset, safeAdd(sload(offset), amount)) + } + function deductFromBalance(account, amount) { + let offset := accountToStorageOffset(account) + let bal := sload(offset) + require(lte(amount, bal)) + sstore(offset, sub(bal, amount)) + } + function allowance(account, spender) -> amount { + amount := sload(allowanceStorageOffset(account, spender)) + } + function setAllowance(account, spender, amount) { + sstore(allowanceStorageOffset(account, spender), amount) + } + function decreaseAllowanceBy(account, spender, amount) { + let offset := allowanceStorageOffset(account, spender) + let currentAllowance := sload(offset) + require(lte(amount, currentAllowance)) + sstore(offset, sub(currentAllowance, amount)) + } + + /* ---------- utility functions ---------- */ + function lte(a, b) -> r { + r := iszero(gt(a, b)) + } + function gte(a, b) -> r { + r := iszero(lt(a, b)) + } + function safeAdd(a, b) -> r { + r := add(a, b) + if or(lt(r, a), lt(r, b)) { revert(0, 0) } + } + function calledByOwner() -> cbo { + cbo := eq(owner(), caller()) + } + function revertIfZeroAddress(addr) { + require(addr) + } + function require(condition) { + if iszero(condition) { revert(0, 0) } + } + } + } + } From cf607aa8870695ac96914cee9c274693ea3b9432 Mon Sep 17 00:00:00 2001 From: Djordje Mijovic Date: Mon, 4 May 2020 20:38:22 +0200 Subject: [PATCH 10/89] [Sol->Yul] Checking if there is base contract when calling base constructror via modifier invocation. --- libsolidity/codegen/ir/IRGenerator.cpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index fb466f3ba..620daa86e 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -302,22 +302,26 @@ pair> IRGenerator::evaluateConstr for (ASTPointer const& base: _contract.baseContracts()) if (FunctionDefinition const* baseConstructor = dynamic_cast( - base->name().annotation().referencedDeclaration + base->name().annotation().referencedDeclaration )->constructor(); baseConstructor && base->arguments()) baseConstructorArguments.emplace_back( - dynamic_cast(baseConstructor->scope()), - base->arguments() + dynamic_cast(baseConstructor->scope()), + base->arguments() ); if (FunctionDefinition const* constructor = _contract.constructor()) - for (auto const& modifier: constructor->modifiers()) - if (FunctionDefinition const* baseConstructor = dynamic_cast( + for (ASTPointer const& modifier: constructor->modifiers()) + if (auto const* baseContract = dynamic_cast( modifier->name()->annotation().referencedDeclaration - )->constructor(); baseConstructor && modifier->arguments()) - baseConstructorArguments.emplace_back( - dynamic_cast(baseConstructor->scope()), - modifier->arguments() - ); + )) + if ( + FunctionDefinition const* baseConstructor = baseContract->constructor(); + baseConstructor && modifier->arguments() + ) + baseConstructorArguments.emplace_back( + dynamic_cast(baseConstructor->scope()), + modifier->arguments() + ); IRGeneratorForStatements generator{m_context, m_utils}; for (auto&& [baseContract, arguments]: baseConstructorArguments) From 8b7f87eed5710e19116acd665dda07e6048c8bb6 Mon Sep 17 00:00:00 2001 From: Djordje Mijovic Date: Fri, 17 Apr 2020 22:24:33 +0200 Subject: [PATCH 11/89] [isoltest] Enforcing compileViaYul to be set if test can pass via yul --- .circleci/config.yml | 18 ++ test/Common.cpp | 1 + test/Common.h | 1 + test/TestCase.cpp | 5 + test/TestCase.h | 3 + test/boostTest.cpp | 11 +- test/libsolidity/SemanticTest.cpp | 236 +++++++++++------- test/libsolidity/SemanticTest.h | 7 +- ...data_array_dynamic_static_short_decode.sol | 2 + .../abiEncoderV2/cleanup/address.sol | 2 + .../abiEncoderV2/cleanup/bool.sol | 2 + .../abiEncoderV2/cleanup/bytesx.sol | 2 + .../abiEncoderV2/cleanup/intx.sol | 2 + .../abiEncoderV2/cleanup/uintx.sol | 2 + .../arithmetics/divisiod_by_zero.sol | 3 +- .../semanticTests/array/array_pop.sol | 3 +- .../array/array_pop_empty_exception.sol | 3 +- .../array/array_pop_isolated.sol | 3 +- .../semanticTests/array/array_push.sol | 3 +- .../array/byte_array_pop_empty_exception.sol | 1 - .../array/byte_array_pop_isolated.sol | 3 +- .../semanticTests/array/calldata_array.sol | 3 +- .../array/calldata_array_dynamic_invalid.sol | 3 +- ...ta_array_dynamic_invalid_static_middle.sol | 3 +- .../create_dynamic_array_with_zero_length.sol | 3 +- .../array/create_multiple_dynamic_arrays.sol | 3 +- .../evm_exceptions_out_of_band_access.sol | 3 +- .../array/fixed_arrays_in_constructors.sol | 3 +- .../array/fixed_bytes_length_access.sol | 3 +- .../memory_arrays_index_access_write.sol | 2 + .../array/memory_arrays_of_various_sizes.sol | 3 +- .../semanticTests/array/push_no_args_1d.sol | 2 + .../cleanup/bool_conversion_v2.sol | 2 + .../cleanup/cleanup_address_types_v2.sol | 2 + .../cleanup/cleanup_bytes_types_v2.sol | 2 + .../cleanup/cleanup_in_compound_assign.sol | 3 +- .../base_constructor_arguments.sol | 2 + .../constructor_arguments_external.sol | 3 +- ...unction_usage_in_constructor_arguments.sol | 2 + ...r_init_inheritence_without_constructor.sol | 3 +- ...conditional_expression_different_types.sol | 2 + .../conditional_expression_false_literal.sol | 2 + .../conditional_expression_functions.sol | 2 + .../conditional_expression_multiple.sol | 2 + .../conditional_expression_true_literal.sol | 2 + .../conditional_expression_tuples.sol | 2 + ...ditional_expression_with_return_values.sol | 2 + .../fallback/fallback_or_receive.sol | 2 + .../semanticTests/fallback/inherited.sol | 2 + .../fallback/short_data_calls_fallback.sol | 2 + .../array_multiple_local_vars.sol | 2 + .../functionCall/call_unimplemented_base.sol | 2 + .../calling_uninitialized_function.sol | 3 +- ...g_uninitialized_function_through_array.sol | 3 +- .../mapping_array_internal_argument.sol | 2 + .../mapping_internal_argument.sol | 2 + .../functionCall/multiple_functions.sol | 1 + .../semanticTests/functionCall/named_args.sol | 2 + .../functionCall/send_zero_ether.sol | 2 + .../functionCall/transaction_status.sol | 2 + .../semanticTests/functionCall/value_test.sol | 2 + .../pass_function_types_internally.sol | 3 +- ...e_function_in_construction_and_runtime.sol | 3 +- .../immutable/multi_creation.sol | 2 + .../inline_assembly_storage_access.sol | 3 +- ...ssembly_storage_access_inside_function.sol | 3 +- .../semanticTests/inlineAssembly/leave.sol | 2 + .../interfaceID/homer_interfaceId.sol | 2 + .../interfaceID/lisa_interfaceId.sol | 2 + .../inherited_function_calldata_memory.sol | 3 +- .../pass_dynamic_arguments_to_the_base.sol | 2 + ...ass_dynamic_arguments_to_the_base_base.sol | 2 + ...ic_arguments_to_the_base_base_with_gap.sol | 2 + .../library_enum_as_an_expression.sol | 2 + .../library_struct_as_an_expression.sol | 2 + .../literals/hex_string_with_underscore.sol | 2 + .../modifiers/break_in_modifier.sol | 3 +- .../stacked_return_with_modifiers.sol | 3 +- .../receive/empty_calldata_calls_receive.sol | 2 + .../semanticTests/receive/ether_and_data.sol | 2 + .../semanticTests/receive/inherited.sol | 2 + .../revertStrings/array_slices.sol | 1 + .../calldata_array_dynamic_invalid.sol | 1 + ...data_array_dynamic_static_short_decode.sol | 1 + ...ta_array_dynamic_static_short_reencode.sol | 1 + .../calldata_array_invalid_length.sol | 1 + .../calldata_arrays_too_large.sol | 1 + .../revertStrings/calldata_tail_short.sol | 1 + .../revertStrings/short_input_array.sol | 1 + .../revertStrings/short_input_bytes.sol | 1 + .../reverts/invalid_enum_as_external_arg.sol | 3 +- .../semanticTests/reverts/revert.sol | 2 + .../semanticTests/reverts/simple_throw.sol | 2 + .../salted_create_with_value.sol | 1 + .../shifts/shift_constant_left.sol | 3 +- .../shifts/shift_constant_right.sol | 3 +- .../shifts/shift_negative_constant_left.sol | 3 +- .../shifts/shift_negative_constant_right.sol | 3 +- .../semanticTests/smoke/bytes_and_strings.sol | 2 + .../semanticTests/smoke/constructor.sol | 2 + .../abi_functions_member_access.sol | 2 + .../storage/complex_accessors.sol | 2 + .../semanticTests/storage/simple_accessor.sol | 2 + .../semanticTests/tryCatch/assert.sol | 2 + .../semanticTests/tryCatch/trivial.sol | 2 + .../types/assign_calldata_value_type.sol | 2 + .../types/external_function_to_address.sol | 2 + .../types/mapping_contract_key_getter.sol | 2 + .../types/mapping_enum_key_getter_v2.sol | 2 + .../types/packing_signed_types.sol | 2 + .../types/packing_unpacking_types.sol | 2 + .../variables/mapping_local_assignment.sol | 2 + .../mapping_local_compound_assignment.sol | 2 + .../variables/public_state_overridding.sol | 4 +- .../semanticTests/various/decayed_tuple.sol | 3 +- .../various/inline_member_init.sol | 3 +- .../inline_member_init_inheritence.sol | 3 +- .../various/literal_empty_string.sol | 2 + .../various/multi_variable_declaration.sol | 3 +- .../various/positive_integers_to_signed.sol | 3 +- .../various/skip_dynamic_types.sol | 3 +- ...string_as_mapping_key_without_variable.sol | 3 +- .../semanticTests/various/string_tuples.sol | 3 +- .../various/test_underscore_in_hex.sol | 2 + .../semanticTests/various/tuples.sol | 3 +- ...unction_usage_in_constructor_arguments.sol | 2 + test/tools/isoltest.cpp | 8 +- 127 files changed, 412 insertions(+), 145 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 063e11bb5..e1161e432 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -617,6 +617,23 @@ jobs: t_ubu_soltest: &t_ubu_soltest <<: *test_ubuntu1904 + t_ubu_soltest_enforce_yul: &t_ubu_soltest_enforce_yul + docker: + - image: ethereum/solidity-buildpack-deps:ubuntu1904-<< pipeline.parameters.ubuntu-1904-docker-image-rev >> + environment: + EVM: constantinople + SOLTEST_FLAGS: --enforce-via-yul + OPTIMIZE: 0 + TERM: xterm + steps: + - checkout + - attach_workspace: + at: build + - run: *run_soltest + - store_test_results: *store_test_results + - store_artifacts: *artifacts_test_results + + t_ubu_clang_soltest: &t_ubu_clang_soltest <<: *test_ubuntu1904_clang environment: @@ -818,6 +835,7 @@ workflows: - b_ubu18: *workflow_trigger_on_tags - t_ubu_cli: *workflow_ubuntu1904 - t_ubu_soltest: *workflow_ubuntu1904 + - t_ubu_soltest_enforce_yul: *workflow_ubuntu1904 - b_ubu_clang: *workflow_trigger_on_tags - t_ubu_clang_soltest: *workflow_ubuntu1904_clang diff --git a/test/Common.cpp b/test/Common.cpp index 0ed7c9881..b65555ba1 100644 --- a/test/Common.cpp +++ b/test/Common.cpp @@ -95,6 +95,7 @@ CommonOptions::CommonOptions(std::string _caption): ("no-smt", po::bool_switch(&disableSMT), "disable SMT checker") ("optimize", po::bool_switch(&optimize), "enables optimization") ("optimize-yul", po::bool_switch(&optimizeYul), "enables Yul optimization") + ("enforce-via-yul", po::bool_switch(&enforceViaYul), "Enforce compiling all tests via yul to see if additional tests can be activated.") ("abiencoderv2", po::bool_switch(&useABIEncoderV2), "enables abi encoder v2") ("show-messages", po::bool_switch(&showMessages), "enables message output") ("show-metadata", po::bool_switch(&showMetadata), "enables metadata output"); diff --git a/test/Common.h b/test/Common.h index 513e7154b..128d23ee5 100644 --- a/test/Common.h +++ b/test/Common.h @@ -47,6 +47,7 @@ struct CommonOptions: boost::noncopyable boost::filesystem::path testPath; bool optimize = false; bool optimizeYul = false; + bool enforceViaYul = false; bool disableSMT = false; bool useABIEncoderV2 = false; bool showMessages = false; diff --git a/test/TestCase.cpp b/test/TestCase.cpp index e0897ae47..23f23ac73 100644 --- a/test/TestCase.cpp +++ b/test/TestCase.cpp @@ -40,6 +40,11 @@ void TestCase::printSettings(ostream& _stream, const string& _linePrefix, const _stream << _linePrefix << "// " << setting.first << ": " << setting.second << endl; } +void TestCase::printUpdatedSettings(std::ostream& _stream, std::string const& _linePrefix) +{ + printSettings(_stream, _linePrefix); +} + bool TestCase::isTestFilename(boost::filesystem::path const& _filename) { string extension = _filename.extension().string(); diff --git a/test/TestCase.h b/test/TestCase.h index 8ec3086fe..442b4fd5f 100644 --- a/test/TestCase.h +++ b/test/TestCase.h @@ -38,6 +38,7 @@ public: { std::string filename; langutil::EVMVersion evmVersion; + bool enforceCompileViaYul; }; enum class TestResult { Success, Failure, FatalError }; @@ -59,6 +60,8 @@ public: virtual void printSource(std::ostream &_stream, std::string const &_linePrefix = "", bool const _formatted = false) const = 0; /// Outputs settings. virtual void printSettings(std::ostream &_stream, std::string const &_linePrefix = "", bool const _formatted = false); + /// Outputs updated settings + virtual void printUpdatedSettings(std::ostream& _stream, std::string const& _linePrefix = ""); /// Outputs test expectations to @arg _stream that match the actual results of the test. /// Each line of output is prefixed with @arg _linePrefix. virtual void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const = 0; diff --git a/test/boostTest.cpp b/test/boostTest.cpp index fd7bca132..eb55ead89 100644 --- a/test/boostTest.cpp +++ b/test/boostTest.cpp @@ -64,12 +64,13 @@ int registerTests( boost::unit_test::test_suite& _suite, boost::filesystem::path const& _basepath, boost::filesystem::path const& _path, + bool _enforceViaYul, TestCase::TestCaseCreator _testCaseCreator ) { int numTestsAdded = 0; fs::path fullpath = _basepath / _path; - TestCase::Config config{fullpath.string(), solidity::test::CommonOptions::get().evmVersion()}; + TestCase::Config config{fullpath.string(), solidity::test::CommonOptions::get().evmVersion(), _enforceViaYul}; if (fs::is_directory(fullpath)) { test_suite* sub_suite = BOOST_TEST_SUITE(_path.filename().string()); @@ -78,7 +79,12 @@ int registerTests( fs::directory_iterator() )) if (fs::is_directory(entry.path()) || TestCase::isTestFilename(entry.path().filename())) - numTestsAdded += registerTests(*sub_suite, _basepath, _path / entry.path().filename(), _testCaseCreator); + numTestsAdded += registerTests( + *sub_suite, + _basepath, _path / entry.path().filename(), + _enforceViaYul, + _testCaseCreator + ); _suite.add(sub_suite); } else @@ -164,6 +170,7 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] ) master, options.testPath / ts.path, ts.subpath, + options.enforceViaYul, ts.testCaseCreator ) > 0, std::string("no ") + ts.title + " tests found"); } diff --git a/test/libsolidity/SemanticTest.cpp b/test/libsolidity/SemanticTest.cpp index ded01f8dd..ab454cb28 100644 --- a/test/libsolidity/SemanticTest.cpp +++ b/test/libsolidity/SemanticTest.cpp @@ -36,9 +36,10 @@ using namespace boost::unit_test; namespace fs = boost::filesystem; -SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVersion): +SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVersion, bool enforceViaYul): SolidityExecutionFramework(_evmVersion), - EVMVersionRestrictedTestCase(_filename) + EVMVersionRestrictedTestCase(_filename), + m_enforceViaYul(enforceViaYul) { m_source = m_reader.source(); m_lineOffset = m_reader.lineNumber(); @@ -78,112 +79,145 @@ SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVer TestCase::TestResult SemanticTest::run(ostream& _stream, string const& _linePrefix, bool _formatted) { - for(bool compileViaYul: set{!m_runWithoutYul, m_runWithYul}) + + for (bool compileViaYul: set{!m_runWithoutYul, m_runWithYul || m_enforceViaYul}) { - reset(); - bool success = true; - - m_compileViaYul = compileViaYul; - if (compileViaYul) - AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Running via Yul:" << endl; - - for (auto& test: m_tests) - test.reset(); - - map libraries; - - bool constructed = false; - - for (auto& test: m_tests) + try { - if (constructed) - { - soltestAssert(!test.call().isLibrary, "Libraries have to be deployed before any other call."); - soltestAssert(!test.call().isConstructor, "Constructor has to be the first function call expect for library deployments."); - } - else if (test.call().isLibrary) - { - soltestAssert( - deploy(test.call().signature, 0, {}, libraries) && m_transactionSuccessful, - "Failed to deploy library " + test.call().signature - ); - libraries[test.call().signature] = m_contractAddress; - continue; - } - else - { - if (test.call().isConstructor) - deploy("", test.call().value.value, test.call().arguments.rawBytes(), libraries); - else - soltestAssert(deploy("", 0, bytes(), libraries), "Failed to deploy contract."); - constructed = true; - } + reset(); + bool success = true; - if (test.call().isConstructor) - { - if (m_transactionSuccessful == test.call().expectations.failure) - success = false; + m_compileViaYul = compileViaYul; + m_compileViaYulCanBeSet = false; - test.setFailure(!m_transactionSuccessful); - test.setRawBytes(bytes()); - } - else + if (compileViaYul) + AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Running via Yul:" << endl; + + for (auto& test: m_tests) + test.reset(); + + map libraries; + + bool constructed = false; + + for (auto& test: m_tests) { - bytes output; - if (test.call().useCallWithoutSignature) - output = callLowLevel(test.call().arguments.rawBytes(), test.call().value.value); - else + if (constructed) + { + soltestAssert(!test.call().isLibrary, "Libraries have to be deployed before any other call."); + soltestAssert(!test.call().isConstructor, "Constructor has to be the first function call expect for library deployments."); + } + else if (test.call().isLibrary) { soltestAssert( - m_allowNonExistingFunctions || m_compiler.methodIdentifiers(m_compiler.lastContractName()).isMember(test.call().signature), - "The function " + test.call().signature + " is not known to the compiler" - ); - - output = callContractFunctionWithValueNoEncoding( - test.call().signature, - test.call().value.value, - test.call().arguments.rawBytes() + deploy(test.call().signature, 0, {}, libraries) && m_transactionSuccessful, + "Failed to deploy library " + test.call().signature ); + libraries[test.call().signature] = m_contractAddress; + continue; + } + else + { + if (test.call().isConstructor) + deploy("", test.call().value.value, test.call().arguments.rawBytes(), libraries); + else + soltestAssert(deploy("", 0, bytes(), libraries), "Failed to deploy contract."); + constructed = true; } - if ((m_transactionSuccessful == test.call().expectations.failure) || (output != test.call().expectations.rawBytes())) - success = false; + if (test.call().isConstructor) + { + if (m_transactionSuccessful == test.call().expectations.failure) + success = false; - test.setFailure(!m_transactionSuccessful); - test.setRawBytes(std::move(output)); - test.setContractABI(m_compiler.contractABI(m_compiler.lastContractName())); + test.setFailure(!m_transactionSuccessful); + test.setRawBytes(bytes()); + } + else + { + bytes output; + if (test.call().useCallWithoutSignature) + output = callLowLevel(test.call().arguments.rawBytes(), test.call().value.value); + else + { + soltestAssert( + m_allowNonExistingFunctions || m_compiler.methodIdentifiers(m_compiler.lastContractName()).isMember(test.call().signature), + "The function " + test.call().signature + " is not known to the compiler" + ); + + output = callContractFunctionWithValueNoEncoding( + test.call().signature, + test.call().value.value, + test.call().arguments.rawBytes() + ); + } + + if ((m_transactionSuccessful == test.call().expectations.failure) || (output != test.call().expectations.rawBytes())) + success = false; + + test.setFailure(!m_transactionSuccessful); + test.setRawBytes(std::move(output)); + test.setContractABI(m_compiler.contractABI(m_compiler.lastContractName())); + } + } + + if (success && !m_runWithYul && compileViaYul) + { + m_compileViaYulCanBeSet = true; + AnsiColorized(_stream, _formatted, {BOLD, YELLOW}) << _linePrefix << endl << _linePrefix + << "Test can pass via Yul and marked with compileViaYul: false." << endl; + return TestResult::Failure; + } + + if (!success && (m_runWithYul || !compileViaYul)) + { + AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Expected result:" << endl; + for (auto const& test: m_tests) + { + ErrorReporter errorReporter; + _stream << test.format(errorReporter, _linePrefix, false, _formatted) << endl; + _stream << errorReporter.format(_linePrefix, _formatted); + } + _stream << endl; + AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:" << endl; + for (auto const& test: m_tests) + { + ErrorReporter errorReporter; + _stream << test.format(errorReporter, _linePrefix, true, _formatted) << endl; + _stream << errorReporter.format(_linePrefix, _formatted); + } + AnsiColorized(_stream, _formatted, {BOLD, RED}) << _linePrefix << endl << _linePrefix + << "Attention: Updates on the test will apply the detected format displayed." << endl; + if (compileViaYul && m_runWithoutYul) + { + _stream << _linePrefix << endl << _linePrefix; + AnsiColorized(_stream, _formatted, {RED_BACKGROUND}) + << "Note that the test passed without Yul."; + _stream << endl; + } + else if (!compileViaYul && m_runWithYul) + AnsiColorized(_stream, _formatted, {BOLD, YELLOW}) << _linePrefix << endl << _linePrefix + << "Note that the test also has to pass via Yul." << endl; + return TestResult::Failure; } } - - if (!success) + catch (boost::exception const&) { - AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Expected result:" << endl; - for (auto const& test: m_tests) - { - ErrorReporter errorReporter; - _stream << test.format(errorReporter, _linePrefix, false, _formatted) << endl; - _stream << errorReporter.format(_linePrefix, _formatted); - } - _stream << endl; - AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:" << endl; - for (auto const& test: m_tests) - { - ErrorReporter errorReporter; - _stream << test.format(errorReporter, _linePrefix, true, _formatted) << endl; - _stream << errorReporter.format(_linePrefix, _formatted); - } - AnsiColorized(_stream, _formatted, {BOLD, RED}) << _linePrefix << endl << _linePrefix - << "Attention: Updates on the test will apply the detected format displayed." << endl; - if (compileViaYul && m_runWithoutYul) - { - _stream << _linePrefix << endl << _linePrefix; - AnsiColorized(_stream, _formatted, {RED_BACKGROUND}) << "Note that the test passed without Yul."; - _stream << endl; - } - else if (!compileViaYul && m_runWithYul) - AnsiColorized(_stream, _formatted, {BOLD, YELLOW}) << _linePrefix << endl << _linePrefix - << "Note that the test also has to pass via Yul." << endl; - return TestResult::Failure; + if (compileViaYul && !m_runWithYul) + continue; + throw; + } + catch (std::exception const&) + { + if (compileViaYul && !m_runWithYul) + continue; + throw; + } + catch (...) + { + if (compileViaYul && !m_runWithYul) + continue; + throw; } } @@ -204,6 +238,20 @@ void SemanticTest::printUpdatedExpectations(ostream& _stream, string const&) con _stream << test.format("", true, false) << endl; } +void SemanticTest::printUpdatedSettings(ostream& _stream, string const& _linePrefix) +{ + auto& settings = m_reader.settings(); + if (settings.empty() && !m_compileViaYulCanBeSet) + return; + + _stream << _linePrefix << "// ====" << endl; + if (m_compileViaYulCanBeSet) + _stream << _linePrefix << "// compileViaYul: also\n"; + for (auto const& setting: settings) + if (!m_compileViaYulCanBeSet || setting.first != "compileViaYul") + _stream << _linePrefix << "// " << setting.first << ": " << setting.second << endl; +} + void SemanticTest::parseExpectations(istream& _stream) { TestFileParser parser{_stream}; diff --git a/test/libsolidity/SemanticTest.h b/test/libsolidity/SemanticTest.h index 94c29e193..870d61d56 100644 --- a/test/libsolidity/SemanticTest.h +++ b/test/libsolidity/SemanticTest.h @@ -40,13 +40,14 @@ class SemanticTest: public SolidityExecutionFramework, public EVMVersionRestrict { public: static std::unique_ptr create(Config const& _options) - { return std::make_unique(_options.filename, _options.evmVersion); } + { return std::make_unique(_options.filename, _options.evmVersion, _options.enforceCompileViaYul); } - explicit SemanticTest(std::string const& _filename, langutil::EVMVersion _evmVersion); + explicit SemanticTest(std::string const& _filename, langutil::EVMVersion _evmVersion, bool _enforceViaYul = false); TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool _formatted = false) override; void printSource(std::ostream &_stream, std::string const& _linePrefix = "", bool _formatted = false) const override; void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix = "") const override; + void printUpdatedSettings(std::ostream& _stream, std::string const& _linePrefix = "") override; /// Instantiates a test file parser that parses the additional comment section at the end of /// the input stream \param _stream. Each function call is represented using a `FunctionCallTest` @@ -64,8 +65,10 @@ private: std::vector m_tests; bool m_runWithYul = false; bool m_runWithoutYul = true; + bool m_enforceViaYul = false; bool m_runWithABIEncoderV1Only = false; bool m_allowNonExistingFunctions = false; + bool m_compileViaYulCanBeSet = false; }; } diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_static_short_decode.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_static_short_decode.sol index a89b6336a..0ded29feb 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_static_short_decode.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_static_short_decode.sol @@ -5,6 +5,8 @@ contract C { return 23; } } +// ==== +// compileViaYul: also // ---- // f(uint256[][2][]): 0x20, 0x01, 0x20, 0x40, 0x60, 0x00, 0x00 -> 23 # this is the common encoding for x.length == 1 && x[0][0].length == 0 && x[0][1].length == 0 # // f(uint256[][2][]): 0x20, 0x01, 0x20, 0x00, 0x00 -> 23 # exotic, but still valid encoding # diff --git a/test/libsolidity/semanticTests/abiEncoderV2/cleanup/address.sol b/test/libsolidity/semanticTests/abiEncoderV2/cleanup/address.sol index 4bd9c2f77..efb5045fc 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/cleanup/address.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/cleanup/address.sol @@ -10,6 +10,8 @@ contract C { return this.g(x); } } +// ==== +// compileViaYul: also // ---- // f(uint256): 0 -> 0 // g(address): 0 -> 0 # test validation as well as sanity check # diff --git a/test/libsolidity/semanticTests/abiEncoderV2/cleanup/bool.sol b/test/libsolidity/semanticTests/abiEncoderV2/cleanup/bool.sol index 94d4dbb11..eb9ce5962 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/cleanup/bool.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/cleanup/bool.sol @@ -10,6 +10,8 @@ contract C { return this.gggg(x); } } +// ==== +// compileViaYul: also // ---- // f(uint256): 0 -> false // gggg(bool): 0 -> false # test validation as well as sanity check # diff --git a/test/libsolidity/semanticTests/abiEncoderV2/cleanup/bytesx.sol b/test/libsolidity/semanticTests/abiEncoderV2/cleanup/bytesx.sol index f8824e271..294a666e9 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/cleanup/bytesx.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/cleanup/bytesx.sol @@ -42,6 +42,8 @@ contract C { return this.g16(x); } } +// ==== +// compileViaYul: also // ---- // f1(bytes32): left(0) -> left(0) // gg1(bytes1): left(0) -> left(0) # test validation as well as sanity check # diff --git a/test/libsolidity/semanticTests/abiEncoderV2/cleanup/intx.sol b/test/libsolidity/semanticTests/abiEncoderV2/cleanup/intx.sol index 51ecd3432..15cd07d49 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/cleanup/intx.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/cleanup/intx.sol @@ -42,6 +42,8 @@ contract C { return this.g128(x); } } +// ==== +// compileViaYul: also // ---- // f8(int256): 0 -> 0 // ggg8(int8): 0 -> 0 # test validation as well as sanity check # diff --git a/test/libsolidity/semanticTests/abiEncoderV2/cleanup/uintx.sol b/test/libsolidity/semanticTests/abiEncoderV2/cleanup/uintx.sol index ee0ec362e..9788431e1 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/cleanup/uintx.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/cleanup/uintx.sol @@ -42,6 +42,8 @@ contract C { return this.g128(x); } } +// ==== +// compileViaYul: also // ---- // f8(uint256): 0 -> 0 // ggg8(uint8): 0 -> 0 # test validation as well as sanity check # diff --git a/test/libsolidity/semanticTests/arithmetics/divisiod_by_zero.sol b/test/libsolidity/semanticTests/arithmetics/divisiod_by_zero.sol index 127320fc6..0ccc0acb5 100644 --- a/test/libsolidity/semanticTests/arithmetics/divisiod_by_zero.sol +++ b/test/libsolidity/semanticTests/arithmetics/divisiod_by_zero.sol @@ -7,7 +7,8 @@ contract C { return a % b; } } - +// ==== +// compileViaYul: also // ---- // div(uint256,uint256): 7, 2 -> 3 // div(uint256,uint256): 7, 0 -> FAILURE # throws # diff --git a/test/libsolidity/semanticTests/array/array_pop.sol b/test/libsolidity/semanticTests/array/array_pop.sol index 5667b61d4..9e64119e9 100644 --- a/test/libsolidity/semanticTests/array/array_pop.sol +++ b/test/libsolidity/semanticTests/array/array_pop.sol @@ -11,6 +11,7 @@ contract c { l = data.length; } } - +// ==== +// compileViaYul: also // ---- // test() -> 1, 0 diff --git a/test/libsolidity/semanticTests/array/array_pop_empty_exception.sol b/test/libsolidity/semanticTests/array/array_pop_empty_exception.sol index 8fc018d72..9f436d2d2 100644 --- a/test/libsolidity/semanticTests/array/array_pop_empty_exception.sol +++ b/test/libsolidity/semanticTests/array/array_pop_empty_exception.sol @@ -6,6 +6,7 @@ contract c { return true; } } - +// ==== +// compileViaYul: also // ---- // test() -> FAILURE diff --git a/test/libsolidity/semanticTests/array/array_pop_isolated.sol b/test/libsolidity/semanticTests/array/array_pop_isolated.sol index 2e6eac83e..58c56adc9 100644 --- a/test/libsolidity/semanticTests/array/array_pop_isolated.sol +++ b/test/libsolidity/semanticTests/array/array_pop_isolated.sol @@ -8,6 +8,7 @@ contract c { x = 3; } } - +// ==== +// compileViaYul: also // ---- // test() -> 3 diff --git a/test/libsolidity/semanticTests/array/array_push.sol b/test/libsolidity/semanticTests/array/array_push.sol index bd8200a37..5923580fa 100644 --- a/test/libsolidity/semanticTests/array/array_push.sol +++ b/test/libsolidity/semanticTests/array/array_push.sol @@ -14,6 +14,7 @@ contract c { z = data[2]; } } - +// ==== +// compileViaYul: also // ---- // test() -> 5, 4, 3, 3 diff --git a/test/libsolidity/semanticTests/array/byte_array_pop_empty_exception.sol b/test/libsolidity/semanticTests/array/byte_array_pop_empty_exception.sol index 30ffa3a4c..08aea4254 100644 --- a/test/libsolidity/semanticTests/array/byte_array_pop_empty_exception.sol +++ b/test/libsolidity/semanticTests/array/byte_array_pop_empty_exception.sol @@ -9,6 +9,5 @@ contract c { return true; } } - // ---- // test() -> FAILURE diff --git a/test/libsolidity/semanticTests/array/byte_array_pop_isolated.sol b/test/libsolidity/semanticTests/array/byte_array_pop_isolated.sol index a9e3fd383..1635071c5 100644 --- a/test/libsolidity/semanticTests/array/byte_array_pop_isolated.sol +++ b/test/libsolidity/semanticTests/array/byte_array_pop_isolated.sol @@ -8,6 +8,7 @@ contract c { x = 3; } } - +// ==== +// compileViaYul: also // ---- // test() -> 3 diff --git a/test/libsolidity/semanticTests/array/calldata_array.sol b/test/libsolidity/semanticTests/array/calldata_array.sol index c9c6dbda0..9fdd8b44b 100644 --- a/test/libsolidity/semanticTests/array/calldata_array.sol +++ b/test/libsolidity/semanticTests/array/calldata_array.sol @@ -11,6 +11,7 @@ contract C { b = s[1]; } } - +// ==== +// compileViaYul: also // ---- // f(uint256[2]): 42, 23 -> 42, 23 diff --git a/test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid.sol b/test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid.sol index d643d3973..cab938d6c 100644 --- a/test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid.sol +++ b/test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid.sol @@ -11,7 +11,8 @@ contract C { return 42; } } - +// ==== +// compileViaYul: also // ---- // f(uint256[][]): 0x20, 0x0 -> 42 # valid access stub # // f(uint256[][]): 0x20, 0x1 -> FAILURE # invalid on argument decoding # diff --git a/test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid_static_middle.sol b/test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid_static_middle.sol index 3efd177b2..d4c02df5e 100644 --- a/test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid_static_middle.sol +++ b/test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid_static_middle.sol @@ -16,7 +16,8 @@ contract C { return 42; } } - +// ==== +// compileViaYul: also // ---- // f(uint256[][1][]): 0x20, 0x0 -> 42 # valid access stub # // f(uint256[][1][]): 0x20, 0x1 -> FAILURE # invalid on argument decoding # diff --git a/test/libsolidity/semanticTests/array/create_dynamic_array_with_zero_length.sol b/test/libsolidity/semanticTests/array/create_dynamic_array_with_zero_length.sol index 7c2ccde6e..a529a767d 100644 --- a/test/libsolidity/semanticTests/array/create_dynamic_array_with_zero_length.sol +++ b/test/libsolidity/semanticTests/array/create_dynamic_array_with_zero_length.sol @@ -4,6 +4,7 @@ contract C { return 7; } } - +// ==== +// compileViaYul: also // ---- // f() -> 7 diff --git a/test/libsolidity/semanticTests/array/create_multiple_dynamic_arrays.sol b/test/libsolidity/semanticTests/array/create_multiple_dynamic_arrays.sol index 731fb4312..9e57f251c 100644 --- a/test/libsolidity/semanticTests/array/create_multiple_dynamic_arrays.sol +++ b/test/libsolidity/semanticTests/array/create_multiple_dynamic_arrays.sol @@ -29,6 +29,7 @@ contract C { return 0; } } - +// ==== +// compileViaYul: also // ---- // f() -> 7 diff --git a/test/libsolidity/semanticTests/array/evm_exceptions_out_of_band_access.sol b/test/libsolidity/semanticTests/array/evm_exceptions_out_of_band_access.sol index af14b48b4..2ac334c17 100644 --- a/test/libsolidity/semanticTests/array/evm_exceptions_out_of_band_access.sol +++ b/test/libsolidity/semanticTests/array/evm_exceptions_out_of_band_access.sol @@ -12,7 +12,8 @@ contract A { return true; } } - +// ==== +// compileViaYul: also // ---- // test() -> false // testIt() -> FAILURE diff --git a/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol b/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol index ff13db5be..e85cb599e 100644 --- a/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol +++ b/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol @@ -7,7 +7,8 @@ contract Creator { ch = s[2]; } } - +// ==== +// compileViaYul: also // ---- // constructor(): 1, 2, 3, 4 -> // r() -> 4 diff --git a/test/libsolidity/semanticTests/array/fixed_bytes_length_access.sol b/test/libsolidity/semanticTests/array/fixed_bytes_length_access.sol index 7a6afbae7..ffeab647f 100644 --- a/test/libsolidity/semanticTests/array/fixed_bytes_length_access.sol +++ b/test/libsolidity/semanticTests/array/fixed_bytes_length_access.sol @@ -5,6 +5,7 @@ contract C { return (x.length, bytes16(uint128(2)).length, a.length + 7); } } - +// ==== +// compileViaYul: also // ---- // f(bytes32): "789" -> 32, 16, 8 diff --git a/test/libsolidity/semanticTests/array/memory_arrays_index_access_write.sol b/test/libsolidity/semanticTests/array/memory_arrays_index_access_write.sol index 7a8a18670..7de7f49be 100644 --- a/test/libsolidity/semanticTests/array/memory_arrays_index_access_write.sol +++ b/test/libsolidity/semanticTests/array/memory_arrays_index_access_write.sol @@ -10,5 +10,7 @@ contract Test { return data; } } +// ==== +// compileViaYul: also // ---- // f() -> 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07 diff --git a/test/libsolidity/semanticTests/array/memory_arrays_of_various_sizes.sol b/test/libsolidity/semanticTests/array/memory_arrays_of_various_sizes.sol index b641ec1da..fd1fba0a1 100644 --- a/test/libsolidity/semanticTests/array/memory_arrays_of_various_sizes.sol +++ b/test/libsolidity/semanticTests/array/memory_arrays_of_various_sizes.sol @@ -11,7 +11,8 @@ contract C { return rows[n][k - 1]; } } - +// ==== +// compileViaYul: also // ---- // f(uint256,uint256): 3, 1 -> 1 // f(uint256,uint256): 9, 5 -> 70 diff --git a/test/libsolidity/semanticTests/array/push_no_args_1d.sol b/test/libsolidity/semanticTests/array/push_no_args_1d.sol index cf6f0687d..daf8d43b1 100644 --- a/test/libsolidity/semanticTests/array/push_no_args_1d.sol +++ b/test/libsolidity/semanticTests/array/push_no_args_1d.sol @@ -19,6 +19,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // l() -> 0 // lv(uint256): 42 -> diff --git a/test/libsolidity/semanticTests/cleanup/bool_conversion_v2.sol b/test/libsolidity/semanticTests/cleanup/bool_conversion_v2.sol index a8fd89833..69b590828 100644 --- a/test/libsolidity/semanticTests/cleanup/bool_conversion_v2.sol +++ b/test/libsolidity/semanticTests/cleanup/bool_conversion_v2.sol @@ -11,6 +11,8 @@ contract C { _out = _in; } } +// ==== +// compileViaYul: also // ---- // f(bool): 0x0 -> 0x0 // f(bool): 0x1 -> 0x1 diff --git a/test/libsolidity/semanticTests/cleanup/cleanup_address_types_v2.sol b/test/libsolidity/semanticTests/cleanup/cleanup_address_types_v2.sol index beff156f7..ce6ff4fe2 100644 --- a/test/libsolidity/semanticTests/cleanup/cleanup_address_types_v2.sol +++ b/test/libsolidity/semanticTests/cleanup/cleanup_address_types_v2.sol @@ -13,6 +13,8 @@ contract C { return 0; } } +// ==== +// compileViaYul: also // ---- // f(address): 0xffff1234567890123456789012345678901234567890 -> FAILURE # We input longer data on purpose.# // g(address): 0xffff1234567890123456789012345678901234567890 -> FAILURE diff --git a/test/libsolidity/semanticTests/cleanup/cleanup_bytes_types_v2.sol b/test/libsolidity/semanticTests/cleanup/cleanup_bytes_types_v2.sol index 5adc97378..2ca882c9f 100644 --- a/test/libsolidity/semanticTests/cleanup/cleanup_bytes_types_v2.sol +++ b/test/libsolidity/semanticTests/cleanup/cleanup_bytes_types_v2.sol @@ -10,5 +10,7 @@ contract C { return 0; } } +// ==== +// compileViaYul: also // ---- // f(bytes2,uint16): "abc", 0x40102 -> FAILURE # We input longer data on purpose. # diff --git a/test/libsolidity/semanticTests/cleanup/cleanup_in_compound_assign.sol b/test/libsolidity/semanticTests/cleanup/cleanup_in_compound_assign.sol index c1901c738..7cd496818 100644 --- a/test/libsolidity/semanticTests/cleanup/cleanup_in_compound_assign.sol +++ b/test/libsolidity/semanticTests/cleanup/cleanup_in_compound_assign.sol @@ -8,6 +8,7 @@ contract C { return (x, y); } } - +// ==== +// compileViaYul: also // ---- // test() -> 0xff, 0xff diff --git a/test/libsolidity/semanticTests/constructor/base_constructor_arguments.sol b/test/libsolidity/semanticTests/constructor/base_constructor_arguments.sol index 2384c061f..ffb98ada1 100644 --- a/test/libsolidity/semanticTests/constructor/base_constructor_arguments.sol +++ b/test/libsolidity/semanticTests/constructor/base_constructor_arguments.sol @@ -20,5 +20,7 @@ contract Derived is Base { } } +// ==== +// compileViaYul: also // ---- // getA() -> 49 diff --git a/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol b/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol index ec30bacf6..fe6a4c59b 100644 --- a/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol +++ b/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol @@ -15,7 +15,8 @@ contract Main { return flag; } } - +// ==== +// compileViaYul: also // ---- // constructor(): "abc", true // getFlag() -> true diff --git a/test/libsolidity/semanticTests/constructor/function_usage_in_constructor_arguments.sol b/test/libsolidity/semanticTests/constructor/function_usage_in_constructor_arguments.sol index e92a37b19..6f2f41428 100644 --- a/test/libsolidity/semanticTests/constructor/function_usage_in_constructor_arguments.sol +++ b/test/libsolidity/semanticTests/constructor/function_usage_in_constructor_arguments.sol @@ -20,5 +20,7 @@ contract Derived is Base { } } +// ==== +// compileViaYul: also // ---- // getA() -> 2 diff --git a/test/libsolidity/semanticTests/constructor/inline_member_init_inheritence_without_constructor.sol b/test/libsolidity/semanticTests/constructor/inline_member_init_inheritence_without_constructor.sol index 0aea44e6a..1e8f9bc78 100644 --- a/test/libsolidity/semanticTests/constructor/inline_member_init_inheritence_without_constructor.sol +++ b/test/libsolidity/semanticTests/constructor/inline_member_init_inheritence_without_constructor.sol @@ -14,7 +14,8 @@ contract Derived is Base { return m_derived; } } - +// ==== +// compileViaYul: also // ---- // getBMember() -> 5 // getDMember() -> 6 diff --git a/test/libsolidity/semanticTests/expressions/conditional_expression_different_types.sol b/test/libsolidity/semanticTests/expressions/conditional_expression_different_types.sol index df07364b3..4f3828f3a 100644 --- a/test/libsolidity/semanticTests/expressions/conditional_expression_different_types.sol +++ b/test/libsolidity/semanticTests/expressions/conditional_expression_different_types.sol @@ -5,6 +5,8 @@ contract test { return cond ? x : y; } } +// ==== +// compileViaYul: also // ---- // f(bool): true -> 0xcd // f(bool): false -> 0xabab diff --git a/test/libsolidity/semanticTests/expressions/conditional_expression_false_literal.sol b/test/libsolidity/semanticTests/expressions/conditional_expression_false_literal.sol index 3915c7b8d..456b1902c 100644 --- a/test/libsolidity/semanticTests/expressions/conditional_expression_false_literal.sol +++ b/test/libsolidity/semanticTests/expressions/conditional_expression_false_literal.sol @@ -3,5 +3,7 @@ contract test { return false ? 5 : 10; } } +// ==== +// compileViaYul: also // ---- // f() -> 10 diff --git a/test/libsolidity/semanticTests/expressions/conditional_expression_functions.sol b/test/libsolidity/semanticTests/expressions/conditional_expression_functions.sol index bff9122b1..482849648 100644 --- a/test/libsolidity/semanticTests/expressions/conditional_expression_functions.sol +++ b/test/libsolidity/semanticTests/expressions/conditional_expression_functions.sol @@ -7,6 +7,8 @@ contract test { return z(); } } +// ==== +// compileViaYul: also // ---- // f(bool): true -> 1 // f(bool): false -> 2 diff --git a/test/libsolidity/semanticTests/expressions/conditional_expression_multiple.sol b/test/libsolidity/semanticTests/expressions/conditional_expression_multiple.sol index 2a9d6de80..c8a335384 100644 --- a/test/libsolidity/semanticTests/expressions/conditional_expression_multiple.sol +++ b/test/libsolidity/semanticTests/expressions/conditional_expression_multiple.sol @@ -6,6 +6,8 @@ contract test { x > 50 ? 50 : 10; } } +// ==== +// compileViaYul: also // ---- // f(uint256): 1001 -> 1000 // f(uint256): 500 -> 100 diff --git a/test/libsolidity/semanticTests/expressions/conditional_expression_true_literal.sol b/test/libsolidity/semanticTests/expressions/conditional_expression_true_literal.sol index 06247f0dc..651455079 100644 --- a/test/libsolidity/semanticTests/expressions/conditional_expression_true_literal.sol +++ b/test/libsolidity/semanticTests/expressions/conditional_expression_true_literal.sol @@ -3,5 +3,7 @@ contract test { return true ? 5 : 10; } } +// ==== +// compileViaYul: also // ---- // f() -> 5 diff --git a/test/libsolidity/semanticTests/expressions/conditional_expression_tuples.sol b/test/libsolidity/semanticTests/expressions/conditional_expression_tuples.sol index d27d06bac..53eba3f1d 100644 --- a/test/libsolidity/semanticTests/expressions/conditional_expression_tuples.sol +++ b/test/libsolidity/semanticTests/expressions/conditional_expression_tuples.sol @@ -3,6 +3,8 @@ contract test { return cond ? (1, 2) : (3, 4); } } +// ==== +// compileViaYul: also // ---- // f(bool): true -> 1, 2 // f(bool): false -> 3, 4 diff --git a/test/libsolidity/semanticTests/expressions/conditional_expression_with_return_values.sol b/test/libsolidity/semanticTests/expressions/conditional_expression_with_return_values.sol index bbaf051bd..df6cdb344 100644 --- a/test/libsolidity/semanticTests/expressions/conditional_expression_with_return_values.sol +++ b/test/libsolidity/semanticTests/expressions/conditional_expression_with_return_values.sol @@ -3,6 +3,8 @@ contract test { cond ? a = v : b = v; } } +// ==== +// compileViaYul: also // ---- // f(bool,uint256): true, 20 -> 20, 0 // f(bool,uint256): false, 20 -> 0, 20 diff --git a/test/libsolidity/semanticTests/fallback/fallback_or_receive.sol b/test/libsolidity/semanticTests/fallback/fallback_or_receive.sol index 9b5319ae0..90efa8fda 100644 --- a/test/libsolidity/semanticTests/fallback/fallback_or_receive.sol +++ b/test/libsolidity/semanticTests/fallback/fallback_or_receive.sol @@ -5,6 +5,8 @@ contract C { receive () payable external { ++y; } function f() external returns (uint, uint) { return (x, y); } } +// ==== +// compileViaYul: also // ---- // f() -> 0, 0 // () -> diff --git a/test/libsolidity/semanticTests/fallback/inherited.sol b/test/libsolidity/semanticTests/fallback/inherited.sol index a4ee55419..1e0cdc407 100644 --- a/test/libsolidity/semanticTests/fallback/inherited.sol +++ b/test/libsolidity/semanticTests/fallback/inherited.sol @@ -4,6 +4,8 @@ contract A { function getData() public returns (uint r) { return data; } } contract B is A {} +// ==== +// compileViaYul: also // ---- // getData() -> 0 // (): 42 -> diff --git a/test/libsolidity/semanticTests/fallback/short_data_calls_fallback.sol b/test/libsolidity/semanticTests/fallback/short_data_calls_fallback.sol index dd97f4c03..57dbb37bb 100644 --- a/test/libsolidity/semanticTests/fallback/short_data_calls_fallback.sol +++ b/test/libsolidity/semanticTests/fallback/short_data_calls_fallback.sol @@ -4,6 +4,8 @@ contract A { function fow() public { x = 3; } fallback () external { x = 2; } } +// ==== +// compileViaYul: also // ---- // (): hex"d88e0b" // x() -> 2 diff --git a/test/libsolidity/semanticTests/functionCall/array_multiple_local_vars.sol b/test/libsolidity/semanticTests/functionCall/array_multiple_local_vars.sol index 4dbfe91f1..52ddfff98 100644 --- a/test/libsolidity/semanticTests/functionCall/array_multiple_local_vars.sol +++ b/test/libsolidity/semanticTests/functionCall/array_multiple_local_vars.sol @@ -22,6 +22,8 @@ contract test { return sum; } } +// ==== +// compileViaYul: also // ---- // f(uint256[]): 32, 3, 1000, 1, 2 -> 3 // f(uint256[]): 32, 3, 100, 500, 300 -> 600 diff --git a/test/libsolidity/semanticTests/functionCall/call_unimplemented_base.sol b/test/libsolidity/semanticTests/functionCall/call_unimplemented_base.sol index 3041f0e4b..862f37f8d 100644 --- a/test/libsolidity/semanticTests/functionCall/call_unimplemented_base.sol +++ b/test/libsolidity/semanticTests/functionCall/call_unimplemented_base.sol @@ -10,5 +10,7 @@ contract C is V { function a() internal view override returns (uint256) { return 42;} } +// ==== +// compileViaYul: also // ---- // b() -> 42 diff --git a/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function.sol b/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function.sol index e1cab8fe8..c074d8598 100644 --- a/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function.sol +++ b/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function.sol @@ -11,7 +11,8 @@ contract C { return 7; } } - +// ==== +// compileViaYul: also // ---- // intern() -> FAILURE # This should throw exceptions # // extern() -> FAILURE diff --git a/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function_through_array.sol b/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function_through_array.sol index 26a2a79f4..44af5be40 100644 --- a/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function_through_array.sol +++ b/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function_through_array.sol @@ -15,6 +15,7 @@ contract C { return 2; } } - +// ==== +// compileViaYul: also // ---- // t() -> FAILURE diff --git a/test/libsolidity/semanticTests/functionCall/mapping_array_internal_argument.sol b/test/libsolidity/semanticTests/functionCall/mapping_array_internal_argument.sol index 54baa4572..4fcc640f6 100644 --- a/test/libsolidity/semanticTests/functionCall/mapping_array_internal_argument.sol +++ b/test/libsolidity/semanticTests/functionCall/mapping_array_internal_argument.sol @@ -16,6 +16,8 @@ contract test { return (a[0][key], a[1][key], b[0][key], b[1][key]); } } +// ==== +// compileViaYul: also // ---- // set(uint8,uint8,uint8,uint8,uint8): 1, 21, 22, 42, 43 -> 0, 0, 0, 0 // get(uint8): 1 -> 21, 22, 42, 43 diff --git a/test/libsolidity/semanticTests/functionCall/mapping_internal_argument.sol b/test/libsolidity/semanticTests/functionCall/mapping_internal_argument.sol index 728be2c09..4154baa9b 100644 --- a/test/libsolidity/semanticTests/functionCall/mapping_internal_argument.sol +++ b/test/libsolidity/semanticTests/functionCall/mapping_internal_argument.sol @@ -14,6 +14,8 @@ contract test { return (a[key], b[key]); } } +// ==== +// compileViaYul: also // ---- // set(uint8,uint8,uint8): 1, 21, 42 -> 0, 0 // get(uint8): 1 -> 21, 42 diff --git a/test/libsolidity/semanticTests/functionCall/multiple_functions.sol b/test/libsolidity/semanticTests/functionCall/multiple_functions.sol index 3c60a13f1..e72922d7b 100644 --- a/test/libsolidity/semanticTests/functionCall/multiple_functions.sol +++ b/test/libsolidity/semanticTests/functionCall/multiple_functions.sol @@ -6,6 +6,7 @@ contract test { } // ==== // allowNonExistingFunctions: true +// compileViaYul: also // ---- // a() -> 0 // b() -> 1 diff --git a/test/libsolidity/semanticTests/functionCall/named_args.sol b/test/libsolidity/semanticTests/functionCall/named_args.sol index 132139b99..e959eba44 100644 --- a/test/libsolidity/semanticTests/functionCall/named_args.sol +++ b/test/libsolidity/semanticTests/functionCall/named_args.sol @@ -2,5 +2,7 @@ contract test { function a(uint a, uint b, uint c) public returns (uint r) { r = a * 100 + b * 10 + c * 1; } function b() public returns (uint r) { r = a({a: 1, b: 2, c: 3}); } } +// ==== +// compileViaYul: also // ---- // b() -> 123 diff --git a/test/libsolidity/semanticTests/functionCall/send_zero_ether.sol b/test/libsolidity/semanticTests/functionCall/send_zero_ether.sol index e0c6ff5e0..07f6ff51d 100644 --- a/test/libsolidity/semanticTests/functionCall/send_zero_ether.sol +++ b/test/libsolidity/semanticTests/functionCall/send_zero_ether.sol @@ -14,6 +14,8 @@ contract Main { } } +// ==== +// compileViaYul: also // ---- // constructor(), 20 wei -> // s() -> true diff --git a/test/libsolidity/semanticTests/functionCall/transaction_status.sol b/test/libsolidity/semanticTests/functionCall/transaction_status.sol index 6651630d5..449ebacbe 100644 --- a/test/libsolidity/semanticTests/functionCall/transaction_status.sol +++ b/test/libsolidity/semanticTests/functionCall/transaction_status.sol @@ -3,6 +3,8 @@ contract test { function g() public { revert(); } function h() public { assert(false); } } +// ==== +// compileViaYul: also // ---- // f() -> // g() -> FAILURE diff --git a/test/libsolidity/semanticTests/functionCall/value_test.sol b/test/libsolidity/semanticTests/functionCall/value_test.sol index 582cda9f6..9cd1fd9ef 100644 --- a/test/libsolidity/semanticTests/functionCall/value_test.sol +++ b/test/libsolidity/semanticTests/functionCall/value_test.sol @@ -3,6 +3,8 @@ contract C { return msg.value; } } +// ==== +// compileViaYul: also // ---- // f(), 1 ether -> 1000000000000000000 // f(), 1 wei -> 1 \ No newline at end of file diff --git a/test/libsolidity/semanticTests/functionTypes/pass_function_types_internally.sol b/test/libsolidity/semanticTests/functionTypes/pass_function_types_internally.sol index 6fb4f5f6e..0acbcc585 100644 --- a/test/libsolidity/semanticTests/functionTypes/pass_function_types_internally.sol +++ b/test/libsolidity/semanticTests/functionTypes/pass_function_types_internally.sol @@ -7,10 +7,9 @@ contract C { return x(a); } - function g(uint256 x) public returns (uint256) { + function g(uint256 x) public pure returns (uint256) { return x + 1; } } - // ---- // f(uint256): 7 -> 8 diff --git a/test/libsolidity/semanticTests/functionTypes/same_function_in_construction_and_runtime.sol b/test/libsolidity/semanticTests/functionTypes/same_function_in_construction_and_runtime.sol index a79cb2d76..d829c1554 100644 --- a/test/libsolidity/semanticTests/functionTypes/same_function_in_construction_and_runtime.sol +++ b/test/libsolidity/semanticTests/functionTypes/same_function_in_construction_and_runtime.sol @@ -13,7 +13,8 @@ contract C { return double(_arg); } } - +// ==== +// compileViaYul: also // ---- // runtime(uint256): 3 -> 6 // initial() -> 4 diff --git a/test/libsolidity/semanticTests/immutable/multi_creation.sol b/test/libsolidity/semanticTests/immutable/multi_creation.sol index b9e362dbd..970ea9155 100644 --- a/test/libsolidity/semanticTests/immutable/multi_creation.sol +++ b/test/libsolidity/semanticTests/immutable/multi_creation.sol @@ -25,6 +25,8 @@ contract C { return (a, (new A()).f(), (new B()).f()); } } +// ==== +// compileViaYul: also // ---- // f() -> 3, 7, 5 // x() -> 7 diff --git a/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access.sol index 823afe2bd..8e42595d4 100644 --- a/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access.sol +++ b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access.sol @@ -16,7 +16,8 @@ contract C { return true; } } - +// ==== +// compileViaYul: also // ---- // f() -> true // z() -> 7 diff --git a/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access_inside_function.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access_inside_function.sol index ce56dbaa1..8f48f2f52 100644 --- a/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access_inside_function.sol +++ b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access_inside_function.sol @@ -17,7 +17,8 @@ contract C { return true; } } - +// ==== +// compileViaYul: also // ---- // f() -> true // z() -> 7 diff --git a/test/libsolidity/semanticTests/inlineAssembly/leave.sol b/test/libsolidity/semanticTests/inlineAssembly/leave.sol index 40add273e..b8c0ccda2 100644 --- a/test/libsolidity/semanticTests/inlineAssembly/leave.sol +++ b/test/libsolidity/semanticTests/inlineAssembly/leave.sol @@ -10,5 +10,7 @@ contract C { } } } +// ==== +// compileViaYul: also // ---- // f() -> 2 diff --git a/test/libsolidity/semanticTests/interfaceID/homer_interfaceId.sol b/test/libsolidity/semanticTests/interfaceID/homer_interfaceId.sol index d2fa2e821..855ca4d40 100644 --- a/test/libsolidity/semanticTests/interfaceID/homer_interfaceId.sol +++ b/test/libsolidity/semanticTests/interfaceID/homer_interfaceId.sol @@ -29,6 +29,8 @@ contract Homer is ERC165, Simpson { } } +// ==== +// compileViaYul: also // ---- // supportsInterface(bytes4): left(0x01ffc9a0) -> false // supportsInterface(bytes4): left(0x01ffc9a7) -> true diff --git a/test/libsolidity/semanticTests/interfaceID/lisa_interfaceId.sol b/test/libsolidity/semanticTests/interfaceID/lisa_interfaceId.sol index 9c9dd5eb7..96f1a4742 100644 --- a/test/libsolidity/semanticTests/interfaceID/lisa_interfaceId.sol +++ b/test/libsolidity/semanticTests/interfaceID/lisa_interfaceId.sol @@ -40,6 +40,8 @@ contract Lisa is ERC165MappingImplementation, Simpson { } } +// ==== +// compileViaYul: also // ---- // supportsInterface(bytes4): left(0x01ffc9a0) -> false // supportsInterface(bytes4): left(0x01ffc9a7) -> true diff --git a/test/libsolidity/semanticTests/intheritance/inherited_function_calldata_memory.sol b/test/libsolidity/semanticTests/intheritance/inherited_function_calldata_memory.sol index 0fd02e8f3..a9956cc80 100644 --- a/test/libsolidity/semanticTests/intheritance/inherited_function_calldata_memory.sol +++ b/test/libsolidity/semanticTests/intheritance/inherited_function_calldata_memory.sol @@ -17,6 +17,7 @@ contract B is A { return A(this).f(m); } } - +// ==== +// compileViaYul: also // ---- // g() -> 23 diff --git a/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base.sol b/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base.sol index 26de9ce70..98922c389 100644 --- a/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base.sol +++ b/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base.sol @@ -14,5 +14,7 @@ contract Derived is Base { contract Final is Derived(4) {} +// ==== +// compileViaYul: also // ---- // m_i() -> 4 diff --git a/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base.sol b/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base.sol index 6349bd814..cab918567 100644 --- a/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base.sol +++ b/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base.sol @@ -19,5 +19,7 @@ contract Derived is Base, Base1 { contract Final is Derived(4) {} +// ==== +// compileViaYul: also // ---- // m_i() -> 4 diff --git a/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base_with_gap.sol b/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base_with_gap.sol index 4556cf5c4..ab7bada38 100644 --- a/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base_with_gap.sol +++ b/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base_with_gap.sol @@ -19,5 +19,7 @@ contract Derived is Base, Base1 { contract Final is Derived(4) {} +// ==== +// compileViaYul: also // ---- // m_i() -> 4 diff --git a/test/libsolidity/semanticTests/libraries/library_enum_as_an_expression.sol b/test/libsolidity/semanticTests/libraries/library_enum_as_an_expression.sol index f24d93c2d..31a64ce20 100644 --- a/test/libsolidity/semanticTests/libraries/library_enum_as_an_expression.sol +++ b/test/libsolidity/semanticTests/libraries/library_enum_as_an_expression.sol @@ -10,5 +10,7 @@ contract Tsra { } } +// ==== +// compileViaYul: also // ---- // f() -> 1 diff --git a/test/libsolidity/semanticTests/libraries/library_struct_as_an_expression.sol b/test/libsolidity/semanticTests/libraries/library_struct_as_an_expression.sol index d7df52434..9965a3815 100644 --- a/test/libsolidity/semanticTests/libraries/library_struct_as_an_expression.sol +++ b/test/libsolidity/semanticTests/libraries/library_struct_as_an_expression.sol @@ -13,5 +13,7 @@ contract Tsra { } } +// ==== +// compileViaYul: also // ---- // f() -> 1 diff --git a/test/libsolidity/semanticTests/literals/hex_string_with_underscore.sol b/test/libsolidity/semanticTests/literals/hex_string_with_underscore.sol index db7f70f83..3194d7ee9 100644 --- a/test/libsolidity/semanticTests/literals/hex_string_with_underscore.sol +++ b/test/libsolidity/semanticTests/literals/hex_string_with_underscore.sol @@ -3,5 +3,7 @@ contract C { return hex"12_34_5678_9A"; } } +// ==== +// compileViaYul: also // ---- // f() -> 32, 5, left(0x123456789A) diff --git a/test/libsolidity/semanticTests/modifiers/break_in_modifier.sol b/test/libsolidity/semanticTests/modifiers/break_in_modifier.sol index 1d1036c2c..27a9550cf 100644 --- a/test/libsolidity/semanticTests/modifiers/break_in_modifier.sol +++ b/test/libsolidity/semanticTests/modifiers/break_in_modifier.sol @@ -13,7 +13,8 @@ contract C { x = t; } } - +// ==== +// compileViaYul: also // ---- // x() -> 0 // f() -> diff --git a/test/libsolidity/semanticTests/modifiers/stacked_return_with_modifiers.sol b/test/libsolidity/semanticTests/modifiers/stacked_return_with_modifiers.sol index 1d1036c2c..27a9550cf 100644 --- a/test/libsolidity/semanticTests/modifiers/stacked_return_with_modifiers.sol +++ b/test/libsolidity/semanticTests/modifiers/stacked_return_with_modifiers.sol @@ -13,7 +13,8 @@ contract C { x = t; } } - +// ==== +// compileViaYul: also // ---- // x() -> 0 // f() -> diff --git a/test/libsolidity/semanticTests/receive/empty_calldata_calls_receive.sol b/test/libsolidity/semanticTests/receive/empty_calldata_calls_receive.sol index ce04cd737..b6e9416a7 100644 --- a/test/libsolidity/semanticTests/receive/empty_calldata_calls_receive.sol +++ b/test/libsolidity/semanticTests/receive/empty_calldata_calls_receive.sol @@ -2,6 +2,8 @@ contract A { uint public x; receive () external payable { ++x; } } +// ==== +// compileViaYul: also // ---- // x() -> 0 // () diff --git a/test/libsolidity/semanticTests/receive/ether_and_data.sol b/test/libsolidity/semanticTests/receive/ether_and_data.sol index 4c48df8d4..44af7ab91 100644 --- a/test/libsolidity/semanticTests/receive/ether_and_data.sol +++ b/test/libsolidity/semanticTests/receive/ether_and_data.sol @@ -1,6 +1,8 @@ contract C { receive () payable external { } } +// ==== +// compileViaYul: also // ---- // (), 1 ether // (), 1 ether: 1 -> FAILURE diff --git a/test/libsolidity/semanticTests/receive/inherited.sol b/test/libsolidity/semanticTests/receive/inherited.sol index 36273068a..a71322983 100644 --- a/test/libsolidity/semanticTests/receive/inherited.sol +++ b/test/libsolidity/semanticTests/receive/inherited.sol @@ -4,6 +4,8 @@ contract A { function getData() public returns (uint r) { return data; } } contract B is A {} +// ==== +// compileViaYul: also // ---- // getData() -> 0 // () -> diff --git a/test/libsolidity/semanticTests/revertStrings/array_slices.sol b/test/libsolidity/semanticTests/revertStrings/array_slices.sol index dec3e916d..5d2cebb87 100644 --- a/test/libsolidity/semanticTests/revertStrings/array_slices.sol +++ b/test/libsolidity/semanticTests/revertStrings/array_slices.sol @@ -6,6 +6,7 @@ contract C { // ==== // EVMVersion: >=byzantium // revertStrings: debug +// compileViaYul: also // ---- // f(uint256,uint256,uint256[]): 2, 1, 0x80, 3, 1, 2, 3 -> FAILURE, hex"08c379a0", 0x20, 22, "Slice starts after end" // f(uint256,uint256,uint256[]): 1, 5, 0x80, 3, 1, 2, 3 -> FAILURE, hex"08c379a0", 0x20, 28, "Slice is greater than length" diff --git a/test/libsolidity/semanticTests/revertStrings/calldata_array_dynamic_invalid.sol b/test/libsolidity/semanticTests/revertStrings/calldata_array_dynamic_invalid.sol index 2538a2175..e91f08a03 100644 --- a/test/libsolidity/semanticTests/revertStrings/calldata_array_dynamic_invalid.sol +++ b/test/libsolidity/semanticTests/revertStrings/calldata_array_dynamic_invalid.sol @@ -7,5 +7,6 @@ contract C { // ==== // EVMVersion: >=byzantium // revertStrings: debug +// compileViaYul: also // ---- // f(uint256[][]): 0x20, 1 -> FAILURE, hex"08c379a0", 0x20, 43, "ABI decoding: invalid calldata a", "rray stride" diff --git a/test/libsolidity/semanticTests/revertStrings/calldata_array_dynamic_static_short_decode.sol b/test/libsolidity/semanticTests/revertStrings/calldata_array_dynamic_static_short_decode.sol index 9f9296d2a..d39b3f4fb 100644 --- a/test/libsolidity/semanticTests/revertStrings/calldata_array_dynamic_static_short_decode.sol +++ b/test/libsolidity/semanticTests/revertStrings/calldata_array_dynamic_static_short_decode.sol @@ -8,5 +8,6 @@ contract C { // ==== // EVMVersion: >=byzantium // revertStrings: debug +// compileViaYul: also // ---- // f(uint256[][2][]): 0x20, 0x01, 0x20, 0x00 -> FAILURE, hex"08c379a0", 0x20, 28, "Invalid calldata tail offset" diff --git a/test/libsolidity/semanticTests/revertStrings/calldata_array_dynamic_static_short_reencode.sol b/test/libsolidity/semanticTests/revertStrings/calldata_array_dynamic_static_short_reencode.sol index 7aac0f7f8..0e2ba94b1 100644 --- a/test/libsolidity/semanticTests/revertStrings/calldata_array_dynamic_static_short_reencode.sol +++ b/test/libsolidity/semanticTests/revertStrings/calldata_array_dynamic_static_short_reencode.sol @@ -10,5 +10,6 @@ contract C { // ==== // EVMVersion: >=byzantium // revertStrings: debug +// compileViaYul: also // ---- // g(uint256[][2][]): 0x20, 0x01, 0x20, 0x00 -> FAILURE, hex"08c379a0", 0x20, 30, "Invalid calldata access offset" diff --git a/test/libsolidity/semanticTests/revertStrings/calldata_array_invalid_length.sol b/test/libsolidity/semanticTests/revertStrings/calldata_array_invalid_length.sol index 3b68bacea..f54a47d73 100644 --- a/test/libsolidity/semanticTests/revertStrings/calldata_array_invalid_length.sol +++ b/test/libsolidity/semanticTests/revertStrings/calldata_array_invalid_length.sol @@ -7,5 +7,6 @@ contract C { // ==== // EVMVersion: >=byzantium // revertStrings: debug +// compileViaYul: also // ---- // f(uint256[][]): 0x20, 1, 0x20, 0x0100000000000000000000 -> FAILURE, hex"08c379a0", 0x20, 28, "Invalid calldata tail length" diff --git a/test/libsolidity/semanticTests/revertStrings/calldata_arrays_too_large.sol b/test/libsolidity/semanticTests/revertStrings/calldata_arrays_too_large.sol index 52809a0b2..c19538d0a 100644 --- a/test/libsolidity/semanticTests/revertStrings/calldata_arrays_too_large.sol +++ b/test/libsolidity/semanticTests/revertStrings/calldata_arrays_too_large.sol @@ -7,5 +7,6 @@ contract C { // ==== // EVMVersion: >=byzantium // revertStrings: debug +// compileViaYul: also // ---- // f(uint256,uint256[],uint256): 6, 0x60, 9, 0x1000000000000000000000000000000000000000000000000000000000000002, 1, 2 -> FAILURE, hex"08c379a0", 0x20, 43, "ABI decoding: invalid calldata a", "rray length" diff --git a/test/libsolidity/semanticTests/revertStrings/calldata_tail_short.sol b/test/libsolidity/semanticTests/revertStrings/calldata_tail_short.sol index b6cc5800d..c3fcece1b 100644 --- a/test/libsolidity/semanticTests/revertStrings/calldata_tail_short.sol +++ b/test/libsolidity/semanticTests/revertStrings/calldata_tail_short.sol @@ -5,5 +5,6 @@ contract C { // ==== // EVMVersion: >=byzantium // revertStrings: debug +// compileViaYul: also // ---- // f(uint256[][]): 0x20, 1, 0x20, 2, 0x42 -> FAILURE, hex"08c379a0", 0x20, 23, "Calldata tail too short" diff --git a/test/libsolidity/semanticTests/revertStrings/short_input_array.sol b/test/libsolidity/semanticTests/revertStrings/short_input_array.sol index 1a80acc26..4c83b79ff 100644 --- a/test/libsolidity/semanticTests/revertStrings/short_input_array.sol +++ b/test/libsolidity/semanticTests/revertStrings/short_input_array.sol @@ -5,5 +5,6 @@ contract C { // ==== // EVMVersion: >=byzantium // revertStrings: debug +// compileViaYul: also // ---- // f(uint256[]): 0x20, 1 -> FAILURE, hex"08c379a0", 0x20, 43, "ABI decoding: invalid calldata a", "rray stride" diff --git a/test/libsolidity/semanticTests/revertStrings/short_input_bytes.sol b/test/libsolidity/semanticTests/revertStrings/short_input_bytes.sol index f361da7b6..b8bb0493a 100644 --- a/test/libsolidity/semanticTests/revertStrings/short_input_bytes.sol +++ b/test/libsolidity/semanticTests/revertStrings/short_input_bytes.sol @@ -5,5 +5,6 @@ contract C { // ==== // EVMVersion: >=byzantium // revertStrings: debug +// compileViaYul: also // ---- // e(bytes): 0x20, 7 -> FAILURE, hex"08c379a0", 0x20, 39, "ABI decoding: invalid byte array", " length" diff --git a/test/libsolidity/semanticTests/reverts/invalid_enum_as_external_arg.sol b/test/libsolidity/semanticTests/reverts/invalid_enum_as_external_arg.sol index d0adf2785..1d240813a 100644 --- a/test/libsolidity/semanticTests/reverts/invalid_enum_as_external_arg.sol +++ b/test/libsolidity/semanticTests/reverts/invalid_enum_as_external_arg.sol @@ -15,6 +15,7 @@ contract C { return this.tested(garbled); } } - +// ==== +// compileViaYul: also // ---- // test() -> FAILURE # should throw # diff --git a/test/libsolidity/semanticTests/reverts/revert.sol b/test/libsolidity/semanticTests/reverts/revert.sol index eae49c799..02496ef94 100644 --- a/test/libsolidity/semanticTests/reverts/revert.sol +++ b/test/libsolidity/semanticTests/reverts/revert.sol @@ -14,6 +14,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> FAILURE // a() -> 42 diff --git a/test/libsolidity/semanticTests/reverts/simple_throw.sol b/test/libsolidity/semanticTests/reverts/simple_throw.sol index ad88deca6..bf9df114c 100644 --- a/test/libsolidity/semanticTests/reverts/simple_throw.sol +++ b/test/libsolidity/semanticTests/reverts/simple_throw.sol @@ -6,6 +6,8 @@ contract Test { } } +// ==== +// compileViaYul: also // ---- // f(uint256): 11 -> 21 // f(uint256): 1 -> FAILURE diff --git a/test/libsolidity/semanticTests/salted_create/salted_create_with_value.sol b/test/libsolidity/semanticTests/salted_create/salted_create_with_value.sol index f8b02693d..4e62acc5e 100644 --- a/test/libsolidity/semanticTests/salted_create/salted_create_with_value.sol +++ b/test/libsolidity/semanticTests/salted_create/salted_create_with_value.sol @@ -18,6 +18,7 @@ contract A { } } // ==== +// compileViaYul: also // EVMVersion: >=constantinople // ---- // f(), 10 ether -> 3007, 3008, 3009 diff --git a/test/libsolidity/semanticTests/shifts/shift_constant_left.sol b/test/libsolidity/semanticTests/shifts/shift_constant_left.sol index 4c6f3737f..4e43cae37 100644 --- a/test/libsolidity/semanticTests/shifts/shift_constant_left.sol +++ b/test/libsolidity/semanticTests/shifts/shift_constant_left.sol @@ -1,6 +1,7 @@ contract C { uint256 public a = 0x42 << 8; } - +// ==== +// compileViaYul: also // ---- // a() -> 0x4200 diff --git a/test/libsolidity/semanticTests/shifts/shift_constant_right.sol b/test/libsolidity/semanticTests/shifts/shift_constant_right.sol index 766a8522e..8278e045c 100644 --- a/test/libsolidity/semanticTests/shifts/shift_constant_right.sol +++ b/test/libsolidity/semanticTests/shifts/shift_constant_right.sol @@ -1,6 +1,7 @@ contract C { uint256 public a = 0x4200 >> 8; } - +// ==== +// compileViaYul: also // ---- // a() -> 0x42 diff --git a/test/libsolidity/semanticTests/shifts/shift_negative_constant_left.sol b/test/libsolidity/semanticTests/shifts/shift_negative_constant_left.sol index b92fb2229..964b6543b 100644 --- a/test/libsolidity/semanticTests/shifts/shift_negative_constant_left.sol +++ b/test/libsolidity/semanticTests/shifts/shift_negative_constant_left.sol @@ -1,6 +1,7 @@ contract C { int256 public a = -0x42 << 8; } - +// ==== +// compileViaYul: also // ---- // a() -> -16896 diff --git a/test/libsolidity/semanticTests/shifts/shift_negative_constant_right.sol b/test/libsolidity/semanticTests/shifts/shift_negative_constant_right.sol index b08463333..993fae441 100644 --- a/test/libsolidity/semanticTests/shifts/shift_negative_constant_right.sol +++ b/test/libsolidity/semanticTests/shifts/shift_negative_constant_right.sol @@ -1,6 +1,7 @@ contract C { int256 public a = -0x4200 >> 8; } - +// ==== +// compileViaYul: also // ---- // a() -> -66 diff --git a/test/libsolidity/semanticTests/smoke/bytes_and_strings.sol b/test/libsolidity/semanticTests/smoke/bytes_and_strings.sol index db6f35497..6bfc1da0a 100644 --- a/test/libsolidity/semanticTests/smoke/bytes_and_strings.sol +++ b/test/libsolidity/semanticTests/smoke/bytes_and_strings.sol @@ -12,6 +12,8 @@ contract C { return "any"; } } +// ==== +// compileViaYul: also // ---- // e(bytes): 32, 3, hex"AB33BB" -> 32, 3, left(0xAB33BB) // e(bytes): 32, 32, 0x20 -> 32, 32, 0x20 diff --git a/test/libsolidity/semanticTests/smoke/constructor.sol b/test/libsolidity/semanticTests/smoke/constructor.sol index e3bee950f..27e26f1eb 100644 --- a/test/libsolidity/semanticTests/smoke/constructor.sol +++ b/test/libsolidity/semanticTests/smoke/constructor.sol @@ -10,6 +10,8 @@ contract C { state = _state; } } +// ==== +// compileViaYul: also // ---- // constructor(), 2 wei: 3 -> // state() -> 3 diff --git a/test/libsolidity/semanticTests/specialFunctions/abi_functions_member_access.sol b/test/libsolidity/semanticTests/specialFunctions/abi_functions_member_access.sol index b255b1880..5d18cf32d 100644 --- a/test/libsolidity/semanticTests/specialFunctions/abi_functions_member_access.sol +++ b/test/libsolidity/semanticTests/specialFunctions/abi_functions_member_access.sol @@ -7,5 +7,7 @@ contract C { abi.decode; } } +// ==== +// compileViaYul: also // ---- // f() -> diff --git a/test/libsolidity/semanticTests/storage/complex_accessors.sol b/test/libsolidity/semanticTests/storage/complex_accessors.sol index 1169e4ea5..9b3fa7a3c 100644 --- a/test/libsolidity/semanticTests/storage/complex_accessors.sol +++ b/test/libsolidity/semanticTests/storage/complex_accessors.sol @@ -10,6 +10,8 @@ contract test { to_multiple_map[42][23] = 31; } } +// ==== +// compileViaYul: also // ---- // to_string_map(uint256): 42 -> "24" // to_bool_map(uint256): 42 -> false diff --git a/test/libsolidity/semanticTests/storage/simple_accessor.sol b/test/libsolidity/semanticTests/storage/simple_accessor.sol index 23bcfbfac..aacfb93a0 100644 --- a/test/libsolidity/semanticTests/storage/simple_accessor.sol +++ b/test/libsolidity/semanticTests/storage/simple_accessor.sol @@ -4,5 +4,7 @@ contract test { data = 8; } } +// ==== +// compileViaYul: also // ---- // data() -> 8 diff --git a/test/libsolidity/semanticTests/tryCatch/assert.sol b/test/libsolidity/semanticTests/tryCatch/assert.sol index 8b6a7b996..be475a3f2 100644 --- a/test/libsolidity/semanticTests/tryCatch/assert.sol +++ b/test/libsolidity/semanticTests/tryCatch/assert.sol @@ -11,6 +11,8 @@ contract C { } } } +// ==== +// compileViaYul: also // ---- // f(bool): true -> 1 // f(bool): false -> 2 diff --git a/test/libsolidity/semanticTests/tryCatch/trivial.sol b/test/libsolidity/semanticTests/tryCatch/trivial.sol index d43477e99..567b4b714 100644 --- a/test/libsolidity/semanticTests/tryCatch/trivial.sol +++ b/test/libsolidity/semanticTests/tryCatch/trivial.sol @@ -11,6 +11,8 @@ contract C { } } } +// ==== +// compileViaYul: also // ---- // f(bool): true -> 1 // f(bool): false -> 2 diff --git a/test/libsolidity/semanticTests/types/assign_calldata_value_type.sol b/test/libsolidity/semanticTests/types/assign_calldata_value_type.sol index 8350628e4..c7d2d8bf8 100644 --- a/test/libsolidity/semanticTests/types/assign_calldata_value_type.sol +++ b/test/libsolidity/semanticTests/types/assign_calldata_value_type.sol @@ -5,5 +5,7 @@ contract C { return (x, b); } } +// ==== +// compileViaYul: also // ---- // f(uint256): 23 -> 42, 23 diff --git a/test/libsolidity/semanticTests/types/external_function_to_address.sol b/test/libsolidity/semanticTests/types/external_function_to_address.sol index fb938d37a..8ae544855 100644 --- a/test/libsolidity/semanticTests/types/external_function_to_address.sol +++ b/test/libsolidity/semanticTests/types/external_function_to_address.sol @@ -6,6 +6,8 @@ contract C { return cb.address; } } +// ==== +// compileViaYul: also // ---- // f() -> true // g(function): hex"00000000000000000000000000000000000004226121ff00000000000000000" -> 0x42 diff --git a/test/libsolidity/semanticTests/types/mapping_contract_key_getter.sol b/test/libsolidity/semanticTests/types/mapping_contract_key_getter.sol index ee916a63d..8e29ad63e 100644 --- a/test/libsolidity/semanticTests/types/mapping_contract_key_getter.sol +++ b/test/libsolidity/semanticTests/types/mapping_contract_key_getter.sol @@ -8,6 +8,8 @@ contract test { return this.table(k); } } +// ==== +// compileViaYul: also // ---- // table(address): 0 -> 0 // table(address): 0x01 -> 0 diff --git a/test/libsolidity/semanticTests/types/mapping_enum_key_getter_v2.sol b/test/libsolidity/semanticTests/types/mapping_enum_key_getter_v2.sol index f1fd184ed..f822a9395 100644 --- a/test/libsolidity/semanticTests/types/mapping_enum_key_getter_v2.sol +++ b/test/libsolidity/semanticTests/types/mapping_enum_key_getter_v2.sol @@ -9,6 +9,8 @@ contract test { return this.table(k); } } +// ==== +// compileViaYul: also // ---- // table(uint8): 0 -> 0 // table(uint8): 0x01 -> 0 diff --git a/test/libsolidity/semanticTests/types/packing_signed_types.sol b/test/libsolidity/semanticTests/types/packing_signed_types.sol index 2d2e0e16e..3a10fd336 100644 --- a/test/libsolidity/semanticTests/types/packing_signed_types.sol +++ b/test/libsolidity/semanticTests/types/packing_signed_types.sol @@ -4,5 +4,7 @@ contract test { return int8(x); } } +// ==== +// compileViaYul: also // ---- // run() -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa diff --git a/test/libsolidity/semanticTests/types/packing_unpacking_types.sol b/test/libsolidity/semanticTests/types/packing_unpacking_types.sol index 8b500cca1..ea2ed58f2 100644 --- a/test/libsolidity/semanticTests/types/packing_unpacking_types.sol +++ b/test/libsolidity/semanticTests/types/packing_unpacking_types.sol @@ -5,6 +5,8 @@ contract test { y = y * 0x10000000000000000 | ~c; } } +// ==== +// compileViaYul: also // ---- // run(bool,uint32,uint64): true, 0x0f0f0f0f, 0xf0f0f0f0f0f0f0f0 // -> 0x0000000000000000000000000000000000000001f0f0f0f00f0f0f0f0f0f0f0f diff --git a/test/libsolidity/semanticTests/variables/mapping_local_assignment.sol b/test/libsolidity/semanticTests/variables/mapping_local_assignment.sol index b99385823..b4b158f62 100644 --- a/test/libsolidity/semanticTests/variables/mapping_local_assignment.sol +++ b/test/libsolidity/semanticTests/variables/mapping_local_assignment.sol @@ -11,5 +11,7 @@ contract test { return (m1[1], m1[2], m2[1], m2[2]); } } +// ==== +// compileViaYul: also // ---- // f() -> 42, 0, 0, 21 diff --git a/test/libsolidity/semanticTests/variables/mapping_local_compound_assignment.sol b/test/libsolidity/semanticTests/variables/mapping_local_compound_assignment.sol index df3ee2f54..5e237ae17 100644 --- a/test/libsolidity/semanticTests/variables/mapping_local_compound_assignment.sol +++ b/test/libsolidity/semanticTests/variables/mapping_local_compound_assignment.sol @@ -10,5 +10,7 @@ contract test { return (m1[1], m1[2], m2[1], m2[2]); } } +// ==== +// compileViaYul: also // ---- // f() -> 42, 0, 0, 21 diff --git a/test/libsolidity/semanticTests/variables/public_state_overridding.sol b/test/libsolidity/semanticTests/variables/public_state_overridding.sol index 2921f1a4a..bff486eaa 100644 --- a/test/libsolidity/semanticTests/variables/public_state_overridding.sol +++ b/test/libsolidity/semanticTests/variables/public_state_overridding.sol @@ -11,8 +11,8 @@ contract X is A function set() public { test = 2; } } - - +// ==== +// compileViaYul: also // ---- // test() -> 0 // set() -> diff --git a/test/libsolidity/semanticTests/various/decayed_tuple.sol b/test/libsolidity/semanticTests/various/decayed_tuple.sol index b00942cb3..2f1122f6a 100644 --- a/test/libsolidity/semanticTests/various/decayed_tuple.sol +++ b/test/libsolidity/semanticTests/various/decayed_tuple.sol @@ -5,6 +5,7 @@ contract C { return x; } } - +// ==== +// compileViaYul: also // ---- // f() -> 2 diff --git a/test/libsolidity/semanticTests/various/inline_member_init.sol b/test/libsolidity/semanticTests/various/inline_member_init.sol index 5dca66d80..cac10c786 100644 --- a/test/libsolidity/semanticTests/various/inline_member_init.sol +++ b/test/libsolidity/semanticTests/various/inline_member_init.sol @@ -14,6 +14,7 @@ contract test { c = m_c; } } - +// ==== +// compileViaYul: also // ---- // get() -> 5, 6, 8 diff --git a/test/libsolidity/semanticTests/various/inline_member_init_inheritence.sol b/test/libsolidity/semanticTests/various/inline_member_init_inheritence.sol index 53f5b3718..7ee1028c9 100644 --- a/test/libsolidity/semanticTests/various/inline_member_init_inheritence.sol +++ b/test/libsolidity/semanticTests/various/inline_member_init_inheritence.sol @@ -18,7 +18,8 @@ contract Derived is Base { return m_derived; } } - +// ==== +// compileViaYul: also // ---- // getBMember() -> 5 // getDMember() -> 6 diff --git a/test/libsolidity/semanticTests/various/literal_empty_string.sol b/test/libsolidity/semanticTests/various/literal_empty_string.sol index bf4da5409..ab916ae8c 100644 --- a/test/libsolidity/semanticTests/various/literal_empty_string.sol +++ b/test/libsolidity/semanticTests/various/literal_empty_string.sol @@ -12,6 +12,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // x() -> 0 // a() -> 0 diff --git a/test/libsolidity/semanticTests/various/multi_variable_declaration.sol b/test/libsolidity/semanticTests/various/multi_variable_declaration.sol index 6f79442e7..75f3fa724 100644 --- a/test/libsolidity/semanticTests/various/multi_variable_declaration.sol +++ b/test/libsolidity/semanticTests/various/multi_variable_declaration.sol @@ -42,6 +42,7 @@ contract C { return f1() && f2(); } } - +// ==== +// compileViaYul: also // ---- // f() -> true diff --git a/test/libsolidity/semanticTests/various/positive_integers_to_signed.sol b/test/libsolidity/semanticTests/various/positive_integers_to_signed.sol index 9ba67b198..bc5e546ca 100644 --- a/test/libsolidity/semanticTests/various/positive_integers_to_signed.sol +++ b/test/libsolidity/semanticTests/various/positive_integers_to_signed.sol @@ -3,7 +3,8 @@ contract test { int8 public y = 127; int16 public q = 250; } - +// ==== +// compileViaYul: also // ---- // x() -> 2 // y() -> 127 diff --git a/test/libsolidity/semanticTests/various/skip_dynamic_types.sol b/test/libsolidity/semanticTests/various/skip_dynamic_types.sol index 350ea2622..a0231678f 100644 --- a/test/libsolidity/semanticTests/various/skip_dynamic_types.sol +++ b/test/libsolidity/semanticTests/various/skip_dynamic_types.sol @@ -10,6 +10,7 @@ contract C { return (a, b); } } - +// ==== +// compileViaYul: also // ---- // g() -> 7, 8 diff --git a/test/libsolidity/semanticTests/various/storage_string_as_mapping_key_without_variable.sol b/test/libsolidity/semanticTests/various/storage_string_as_mapping_key_without_variable.sol index 7a8a2c276..d5f53c120 100644 --- a/test/libsolidity/semanticTests/various/storage_string_as_mapping_key_without_variable.sol +++ b/test/libsolidity/semanticTests/various/storage_string_as_mapping_key_without_variable.sol @@ -6,6 +6,7 @@ contract Test { return data["abc"]; } } - +// ==== +// compileViaYul: also // ---- // f() -> 2 diff --git a/test/libsolidity/semanticTests/various/string_tuples.sol b/test/libsolidity/semanticTests/various/string_tuples.sol index 3269d97c0..0a7a38b8b 100644 --- a/test/libsolidity/semanticTests/various/string_tuples.sol +++ b/test/libsolidity/semanticTests/various/string_tuples.sol @@ -11,7 +11,8 @@ contract C { return ("abc"); } } - +// ==== +// compileViaYul: also // ---- // f() -> 0x40, 0x8, 0x3, "abc" // g() -> 0x40, 0x80, 0x3, "abc", 0x3, "def" diff --git a/test/libsolidity/semanticTests/various/test_underscore_in_hex.sol b/test/libsolidity/semanticTests/various/test_underscore_in_hex.sol index 1f12ba390..fae85cd34 100644 --- a/test/libsolidity/semanticTests/various/test_underscore_in_hex.sol +++ b/test/libsolidity/semanticTests/various/test_underscore_in_hex.sol @@ -5,6 +5,8 @@ contract test { return cond ? x : y; } } +// ==== +// compileViaYul: also // ---- // f(bool): true -> 0x1234ab // f(bool): false -> 0x1234abcd1234 diff --git a/test/libsolidity/semanticTests/various/tuples.sol b/test/libsolidity/semanticTests/various/tuples.sol index 00fcd6f9a..b89928a72 100644 --- a/test/libsolidity/semanticTests/various/tuples.sol +++ b/test/libsolidity/semanticTests/various/tuples.sol @@ -25,6 +25,7 @@ contract C { if (a != 8 || b != 10) return 4; } } - +// ==== +// compileViaYul: also // ---- // f() -> 0 diff --git a/test/libsolidity/semanticTests/virtualFunctions/virtual_function_usage_in_constructor_arguments.sol b/test/libsolidity/semanticTests/virtualFunctions/virtual_function_usage_in_constructor_arguments.sol index 590294f15..e66b8ad4f 100644 --- a/test/libsolidity/semanticTests/virtualFunctions/virtual_function_usage_in_constructor_arguments.sol +++ b/test/libsolidity/semanticTests/virtualFunctions/virtual_function_usage_in_constructor_arguments.sol @@ -28,5 +28,7 @@ contract Derived is Base { } } +// ==== +// compileViaYul: also // ---- // getA() -> 2 diff --git a/test/tools/isoltest.cpp b/test/tools/isoltest.cpp index 7a3c63cff..846a54415 100644 --- a/test/tools/isoltest.cpp +++ b/test/tools/isoltest.cpp @@ -161,7 +161,11 @@ TestTool::Result TestTool::process() { (AnsiColorized(cout, formatted, {BOLD}) << m_name << ": ").flush(); - m_test = m_testCaseCreator(TestCase::Config{m_path.string(), m_options.evmVersion()}); + m_test = m_testCaseCreator(TestCase::Config{ + m_path.string(), + m_options.evmVersion(), + m_options.enforceViaYul + }); if (m_test->shouldRun()) switch (TestCase::TestResult result = m_test->run(outputMessages, " ", formatted)) { @@ -232,7 +236,7 @@ TestTool::Request TestTool::handleResponse(bool _exception) cout << endl; ofstream file(m_path.string(), ios::trunc); m_test->printSource(file); - m_test->printSettings(file); + m_test->printUpdatedSettings(file); file << "// ----" << endl; m_test->printUpdatedExpectations(file, "// "); return Request::Rerun; From e8f6f63e77c829066c20a754d2919d10c3f0e6c9 Mon Sep 17 00:00:00 2001 From: Djordje Mijovic Date: Mon, 4 May 2020 23:04:03 +0200 Subject: [PATCH 12/89] [Sol2Yul] Adding support for builtin revert(string) --- .../codegen/ir/IRGeneratorForStatements.cpp | 36 ++++++++++++++++++- .../semanticTests/revertStrings/bubble.sol | 1 + .../semanticTests/revertStrings/transfer.sol | 1 + .../semanticTests/smoke/failure.sol | 5 +-- 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 572ef925f..f8c8b2956 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -737,7 +737,41 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) if (arguments.empty()) m_code << "revert(0, 0)\n"; else - solUnimplementedAssert(false, ""); + { + solAssert(arguments.size() == 1, ""); + + if (m_context.revertStrings() == RevertStrings::Strip) + m_code << "revert(0, 0)\n"; + else + { + solAssert(type(*arguments.front()).isImplicitlyConvertibleTo(*TypeProvider::stringMemory()),""); + + Whiskers templ(R"({ + let := () + mstore(, ) + let := (add(, 4) ) + revert(, sub(, )) + })"); + templ("pos", m_context.newYulVariable()); + templ("end", m_context.newYulVariable()); + templ( + "hash", + (u256(util::FixedHash<4>::Arith(util::FixedHash<4>(util::keccak256("Error(string)")))) << (256 - 32)).str() + ); + templ("allocateTemporary", m_utils.allocationTemporaryMemoryFunction()); + templ( + "argumentVars", + (type(*arguments.front()).sizeOnStack() > 0 ? ", " : "") + + IRVariable{*arguments.front()}.commaSeparatedList() + ); + templ("encode", m_context.abiFunctions().tupleEncoder( + {&type(*arguments.front())}, + {TypeProvider::stringMemory()} + )); + + m_code << templ.render(); + } + } break; } diff --git a/test/libsolidity/semanticTests/revertStrings/bubble.sol b/test/libsolidity/semanticTests/revertStrings/bubble.sol index 5e9a0730d..24eceaba3 100644 --- a/test/libsolidity/semanticTests/revertStrings/bubble.sol +++ b/test/libsolidity/semanticTests/revertStrings/bubble.sol @@ -9,6 +9,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >=byzantium // revertStrings: debug // ---- diff --git a/test/libsolidity/semanticTests/revertStrings/transfer.sol b/test/libsolidity/semanticTests/revertStrings/transfer.sol index 0d766bd1e..5d13f7d72 100644 --- a/test/libsolidity/semanticTests/revertStrings/transfer.sol +++ b/test/libsolidity/semanticTests/revertStrings/transfer.sol @@ -18,6 +18,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >=byzantium // revertStrings: debug // ---- diff --git a/test/libsolidity/semanticTests/smoke/failure.sol b/test/libsolidity/semanticTests/smoke/failure.sol index e693a8459..95b8c9109 100644 --- a/test/libsolidity/semanticTests/smoke/failure.sol +++ b/test/libsolidity/semanticTests/smoke/failure.sol @@ -14,11 +14,12 @@ contract C { } } // ==== -// allowNonExistingFunctions: true +// compileViaYul: also // EVMVersion: >homestead +// allowNonExistingFunctions: true // ---- // _() -> FAILURE // e() -> FAILURE, hex"08c379a0", 0x20, 19, "Transaction failed." // f(bool): false -> FAILURE, hex"08c379a0", 0x20, 0 // g(bool): false -> FAILURE, hex"08c379a0", 0x20, 15, "Value is false." -// h() -> FAILURE \ No newline at end of file +// h() -> FAILURE From 7ad319687d3465c5032bf691f5aa0b4700c44491 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Tue, 5 May 2020 13:06:01 +0200 Subject: [PATCH 13/89] Sol->Yul: Add cleanup to operations. --- libsolidity/codegen/YulUtilFunctions.cpp | 51 +++++++++++++------ .../codegen/ir/IRGeneratorForStatements.cpp | 13 +++-- .../codegen/ir/IRGeneratorForStatements.h | 3 +- 3 files changed, 47 insertions(+), 20 deletions(-) diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 75d297b34..481fbc479 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -393,6 +393,8 @@ string YulUtilFunctions::overflowCheckedIntAddFunction(IntegerType const& _type) return Whiskers(R"( function (x, y) -> sum { + x := (x) + y := (y) // overflow, if x >= 0 and y > (maxValue - x) if and(iszero(slt(x, 0)), sgt(y, sub(, x))) { revert(0, 0) } @@ -409,6 +411,7 @@ string YulUtilFunctions::overflowCheckedIntAddFunction(IntegerType const& _type) ("signed", _type.isSigned()) ("maxValue", toCompactHexWithPrefix(u256(_type.maxValue()))) ("minValue", toCompactHexWithPrefix(u256(_type.minValue()))) + ("cleanupFunction", cleanupFunction(_type)) .render(); }); } @@ -421,6 +424,8 @@ string YulUtilFunctions::overflowCheckedIntMulFunction(IntegerType const& _type) // Multiplication by zero could be treated separately and directly return zero. Whiskers(R"( function (x, y) -> product { + x := (x) + y := (y) // overflow, if x > 0, y > 0 and x > (maxValue / y) if and(and(sgt(x, 0), sgt(y, 0)), gt(x, div(, y))) { revert(0, 0) } @@ -441,6 +446,7 @@ string YulUtilFunctions::overflowCheckedIntMulFunction(IntegerType const& _type) ("signed", _type.isSigned()) ("maxValue", toCompactHexWithPrefix(u256(_type.maxValue()))) ("minValue", toCompactHexWithPrefix(u256(_type.minValue()))) + ("cleanupFunction", cleanupFunction(_type)) .render(); }); } @@ -452,6 +458,8 @@ string YulUtilFunctions::overflowCheckedIntDivFunction(IntegerType const& _type) return Whiskers(R"( function (x, y) -> r { + x := (x) + y := (y) if iszero(y) { revert(0, 0) } // overflow for minVal / -1 @@ -466,6 +474,7 @@ string YulUtilFunctions::overflowCheckedIntDivFunction(IntegerType const& _type) ("functionName", functionName) ("signed", _type.isSigned()) ("minVal", toCompactHexWithPrefix(u256(_type.minValue()))) + ("cleanupFunction", cleanupFunction(_type)) .render(); }); } @@ -477,12 +486,15 @@ string YulUtilFunctions::checkedIntModFunction(IntegerType const& _type) return Whiskers(R"( function (x, y) -> r { + x := (x) + y := (y) if iszero(y) { revert(0, 0) } r := smod(x, y) } )") ("functionName", functionName) ("signed", _type.isSigned()) + ("cleanupFunction", cleanupFunction(_type)) .render(); }); } @@ -494,6 +506,8 @@ string YulUtilFunctions::overflowCheckedIntSubFunction(IntegerType const& _type) return Whiskers(R"( function (x, y) -> diff { + x := (x) + y := (y) // underflow, if y >= 0 and x < (minValue + y) if and(iszero(slt(y, 0)), slt(x, add(, y))) { revert(0, 0) } @@ -509,6 +523,7 @@ string YulUtilFunctions::overflowCheckedIntSubFunction(IntegerType const& _type) ("signed", _type.isSigned()) ("maxValue", toCompactHexWithPrefix(u256(_type.maxValue()))) ("minValue", toCompactHexWithPrefix(u256(_type.minValue()))) + ("cleanupFunction", cleanupFunction(_type)) .render(); }); } @@ -1938,14 +1953,16 @@ std::string YulUtilFunctions::decrementCheckedFunction(Type const& _type) return Whiskers(R"( function (value) -> ret { + value := (value) if (value, ) { revert(0,0) } ret := sub(value, 1) } )") - ("functionName", functionName) - ("minval", toCompactHexWithPrefix(minintval)) - ("lt", type.isSigned() ? "slt" : "lt") - .render(); + ("functionName", functionName) + ("minval", toCompactHexWithPrefix(minintval)) + ("lt", type.isSigned() ? "slt" : "lt") + ("cleanupFunction", cleanupFunction(_type)) + .render(); }); } @@ -1966,14 +1983,16 @@ std::string YulUtilFunctions::incrementCheckedFunction(Type const& _type) return Whiskers(R"( function (value) -> ret { + value := (value) if (value, ) { revert(0,0) } ret := add(value, 1) } )") - ("functionName", functionName) - ("maxval", toCompactHexWithPrefix(maxintval)) - ("gt", type.isSigned() ? "sgt" : "gt") - .render(); + ("functionName", functionName) + ("maxval", toCompactHexWithPrefix(maxintval)) + ("gt", type.isSigned() ? "sgt" : "gt") + ("cleanupFunction", cleanupFunction(_type)) + .render(); }); } @@ -1988,15 +2007,17 @@ string YulUtilFunctions::negateNumberCheckedFunction(Type const& _type) return m_functionCollector.createFunction(functionName, [&]() { return Whiskers(R"( - function (_value) -> ret { - if slt(_value, ) { revert(0,0) } - ret := sub(0, _value) + function (value) -> ret { + value := (value) + if slt(value, ) { revert(0,0) } + ret := sub(0, value) } )") - ("functionName", functionName) - ("minval", toCompactHexWithPrefix(minintval)) - .render(); - }); + ("functionName", functionName) + ("minval", toCompactHexWithPrefix(minintval)) + ("cleanupFunction", cleanupFunction(_type)) + .render(); + }); } string YulUtilFunctions::zeroValueFunction(Type const& _type, bool _splitFunctionTypes) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index f8c8b2956..f795e0e98 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -496,9 +496,9 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp) isSigned = type->isSigned(); string args = - expressionAsType(_binOp.leftExpression(), *commonType) + + expressionAsType(_binOp.leftExpression(), *commonType, true) + ", " + - expressionAsType(_binOp.rightExpression(), *commonType); + expressionAsType(_binOp.rightExpression(), *commonType, true); string expr; if (op == Token::Equal) @@ -1811,11 +1811,16 @@ IRVariable IRGeneratorForStatements::convert(IRVariable const& _from, Type const } } -std::string IRGeneratorForStatements::expressionAsType(Expression const& _expression, Type const& _to) +std::string IRGeneratorForStatements::expressionAsType(Expression const& _expression, Type const& _to, bool _forceCleanup) { IRVariable from(_expression); if (from.type() == _to) - return from.commaSeparatedList(); + { + if (_forceCleanup) + return m_utils.cleanupFunction(_to) + "(" + from.commaSeparatedList() + ")"; + else + return from.commaSeparatedList(); + } else return m_utils.conversionFunction(from.type(), _to) + "(" + from.commaSeparatedList() + ")"; } diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.h b/libsolidity/codegen/ir/IRGeneratorForStatements.h index b8fafd8b6..e4282c2b3 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.h +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.h @@ -112,7 +112,8 @@ private: /// @returns a Yul expression representing the current value of @a _expression, /// converted to type @a _to if it does not yet have that type. - std::string expressionAsType(Expression const& _expression, Type const& _to); + /// If @a _forceCleanup is set to true, it also cleans the value, in case it already has type @a _to. + std::string expressionAsType(Expression const& _expression, Type const& _to, bool _forceCleanup = false); /// @returns an output stream that can be used to define @a _var using a function call or /// single stack slot expression. From 4d739b16a45347dc3e825846ad3a38857944c920 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Tue, 5 May 2020 13:07:10 +0200 Subject: [PATCH 14/89] Cleanup function for internal function pointers. --- libsolidity/codegen/YulUtilFunctions.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 481fbc479..78af6306e 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -1779,8 +1779,18 @@ string YulUtilFunctions::cleanupFunction(Type const& _type) solUnimplemented("Fixed point types not implemented."); break; case Type::Category::Function: - solAssert(dynamic_cast(_type).kind() == FunctionType::Kind::External, ""); - templ("body", "cleaned := " + cleanupFunction(FixedBytesType(24)) + "(value)"); + switch (dynamic_cast(_type).kind()) + { + case FunctionType::Kind::External: + templ("body", "cleaned := " + cleanupFunction(FixedBytesType(24)) + "(value)"); + break; + case FunctionType::Kind::Internal: + templ("body", "cleaned := value"); + break; + default: + solAssert(false, ""); + break; + } break; case Type::Category::Array: case Type::Category::Struct: From 28d25afab1a27618320a33438fca36ad1f6c2dea Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Tue, 5 May 2020 13:25:53 +0200 Subject: [PATCH 15/89] Cleanup tests for Sol->Yul arithmetic and comparison. --- .../viaYul/cleanup/checked_arithmetic.sol | 65 +++++++++++++++++++ .../viaYul/cleanup/comparison.sol | 41 ++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 test/libsolidity/semanticTests/viaYul/cleanup/checked_arithmetic.sol create mode 100644 test/libsolidity/semanticTests/viaYul/cleanup/comparison.sol diff --git a/test/libsolidity/semanticTests/viaYul/cleanup/checked_arithmetic.sol b/test/libsolidity/semanticTests/viaYul/cleanup/checked_arithmetic.sol new file mode 100644 index 000000000..cc9e44938 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/cleanup/checked_arithmetic.sol @@ -0,0 +1,65 @@ +contract C { + function add() public pure returns (uint8, uint8) { + uint8 x; uint8 y = 0; + assembly { x := 0x0101 } + return (x + y, y + x); + } + function sub() public pure returns (uint8, uint8) { + uint8 x; uint8 y = 1; + assembly { x := 0x0101 } + return (x - y, y - x); + } + function mul() public pure returns (uint8, uint8) { + uint8 x; uint8 y = 1; + assembly { x := 0x0101 } + return (x * y, y * x); + } + function div() public pure returns (uint8, uint8) { + uint8 x; uint8 y = 1; + assembly { x := 0x0101 } + return (x / y, y / x); + } + function mod() public pure returns (uint8, uint8) { + uint8 x; uint8 y = 2; + assembly { x := 0x0101 } + return (x % y, y % x); + } + function inc_pre() public pure returns (uint8) { + uint8 x; + assembly { x := 0x0100 } + return ++x; + } + function inc_post() public pure returns (uint8) { + uint8 x; + assembly { x := 0x0100 } + return x++; + } + function dec_pre() public pure returns (uint8) { + uint8 x; + assembly { x := not(0xFF) } + return --x; + } + function dec_post() public pure returns (uint8) { + uint8 x; + assembly { x := not(0xFF) } + return x--; + } + function neg() public pure returns (int8) { + int8 x; + assembly { x := 0x80 } + return -x; + } +} +// ==== +// compileViaYul: true +// ---- +// add() -> 1, 1 +// sub() -> 0, 0 +// mul() -> 1, 1 +// div() -> 1, 1 +// mod() -> 1, 0 +// inc_pre() -> 1 +// inc_post() -> 0 +// dec_pre() -> FAILURE +// dec_post() -> FAILURE +// neg() -> FAILURE diff --git a/test/libsolidity/semanticTests/viaYul/cleanup/comparison.sol b/test/libsolidity/semanticTests/viaYul/cleanup/comparison.sol new file mode 100644 index 000000000..86bd8ede7 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/cleanup/comparison.sol @@ -0,0 +1,41 @@ +contract C { + function eq() public pure returns (bool) { + uint8 x = 1; uint8 y; + assembly { y := 0x0101 } + return (x == y); + } + function neq() public pure returns (bool) { + uint8 x = 1; uint8 y; + assembly { y := 0x0101 } + return (x != y); + } + function geq() public pure returns (bool) { + uint8 x = 1; uint8 y; + assembly { y := 0x0101 } + return (x >= y); + } + function leq() public pure returns (bool) { + uint8 x = 2; uint8 y; + assembly { y := 0x0101 } + return (x <= y); + } + function gt() public pure returns (bool) { + uint8 x = 2; uint8 y; + assembly { y := 0x0101 } + return (x > y); + } + function lt() public pure returns (bool) { + uint8 x = 1; uint8 y; + assembly { y := 0x0101 } + return (x < y); + } +} +// ==== +// compileViaYul: also +// ---- +// eq() -> true +// neq() -> false +// geq() -> true +// leq() -> false +// gt() -> true +// lt() -> false From 7b48c120b590f94006c907722bb4ee2a486a02b5 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Tue, 5 May 2020 14:05:11 +0200 Subject: [PATCH 16/89] Always enforce via yul for isoltest runs. --- test/tools/IsolTestOptions.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/tools/IsolTestOptions.cpp b/test/tools/IsolTestOptions.cpp index b8ae70a63..28552a86a 100644 --- a/test/tools/IsolTestOptions.cpp +++ b/test/tools/IsolTestOptions.cpp @@ -69,6 +69,7 @@ bool IsolTestOptions::parse(int _argc, char const* const* _argv) std::cout << options << std::endl; return false; } + enforceViaYul = true; return res; } From 02c20698c9fa50c31d008ed8af7af3c330053e20 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 20 Apr 2020 23:05:14 +0200 Subject: [PATCH 17/89] IR generation for constants. --- libsolidity/codegen/ir/IRGenerator.cpp | 12 +++++++- .../codegen/ir/IRGeneratorForStatements.cpp | 30 +++++++++++++++---- .../codegen/ir/IRGeneratorForStatements.h | 4 +++ .../accessor_for_const_state_variable.sol | 3 +- ...signment_to_const_var_involving_keccak.sol | 2 ++ .../constants/constant_string.sol | 2 ++ .../simple_constant_variables_test.sol | 2 ++ .../inherited_constant_state_var.sol | 2 ++ ...ment_to_const_var_involving_expression.sol | 2 ++ 9 files changed, 52 insertions(+), 7 deletions(-) diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 620daa86e..bac4fea66 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -202,11 +202,11 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) Type const* type = _varDecl.annotation().type; - solAssert(!_varDecl.isConstant(), ""); solAssert(_varDecl.isStateVariable(), ""); if (auto const* mappingType = dynamic_cast(type)) return m_context.functionCollector().createFunction(functionName, [&]() { + solAssert(!_varDecl.isConstant(), ""); pair slot_offset = m_context.storageLocationOfVariable(_varDecl); solAssert(slot_offset.second == 0, ""); FunctionType funType(_varDecl); @@ -268,6 +268,16 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) ("id", to_string(_varDecl.id())) .render(); } + else if (_varDecl.isConstant()) + return Whiskers(R"( + function () -> { + := () + } + )") + ("functionName", functionName) + ("constantValueFunction", IRGeneratorForStatements(m_context, m_utils).constantValueFunction(_varDecl)) + ("ret", suffixedVariableNameList("ret_", 0, _varDecl.type()->sizeOnStack())) + .render(); else { pair slot_offset = m_context.storageLocationOfVariable(_varDecl); diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index f8c8b2956..cdb5f3c26 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -178,6 +178,28 @@ IRVariable IRGeneratorForStatements::evaluateExpression(Expression const& _expre return variable; } +string IRGeneratorForStatements::constantValueFunction(VariableDeclaration const& _constant) +{ + string functionName = "constant_" + _constant.name() + "_" + to_string(_constant.id()); + return m_context.functionCollector().createFunction(functionName, [&] { + Whiskers templ(R"( + function () -> { + + := + } + )"); + templ("functionName", functionName); + IRGeneratorForStatements generator(m_context, m_utils); + solAssert(_constant.value(), ""); + Type const& constantType = *_constant.type(); + templ("value", generator.evaluateExpression(*_constant.value(), constantType).commaSeparatedList()); + templ("code", generator.code()); + templ("ret", IRVariable("ret", constantType).commaSeparatedList()); + + return templ.render(); + }); +} + void IRGeneratorForStatements::endVisit(VariableDeclarationStatement const& _varDeclStatement) { if (Expression const* expression = _varDeclStatement.initialValue()) @@ -1576,11 +1598,9 @@ void IRGeneratorForStatements::handleVariableReference( Expression const& _referencingExpression ) { - // TODO for the constant case, we have to be careful: - // If the value is visited twice, `defineExpression` is called twice on - // the same expression. - solUnimplementedAssert(!_variable.isConstant(), ""); - if (_variable.isStateVariable() && _variable.immutable()) + if (_variable.isStateVariable() && _variable.isConstant()) + define(_referencingExpression) << constantValueFunction(_variable) << "()\n"; + else if (_variable.isStateVariable() && _variable.immutable()) setLValue(_referencingExpression, IRLValue{ *_variable.annotation().type, IRLValue::Immutable{&_variable} diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.h b/libsolidity/codegen/ir/IRGeneratorForStatements.h index b8fafd8b6..a35c09fbb 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.h +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.h @@ -54,6 +54,10 @@ public: /// Calculates expression's value and returns variable where it was stored IRVariable evaluateExpression(Expression const& _expression, Type const& _to); + /// @returns the name of a function that computes the value of the given constant + /// and also generates the function. + std::string constantValueFunction(VariableDeclaration const& _constant); + void endVisit(VariableDeclarationStatement const& _variableDeclaration) override; bool visit(Conditional const& _conditional) override; bool visit(Assignment const& _assignment) override; diff --git a/test/libsolidity/semanticTests/accessor/accessor_for_const_state_variable.sol b/test/libsolidity/semanticTests/accessor/accessor_for_const_state_variable.sol index a9402aa86..a56956a90 100644 --- a/test/libsolidity/semanticTests/accessor/accessor_for_const_state_variable.sol +++ b/test/libsolidity/semanticTests/accessor/accessor_for_const_state_variable.sol @@ -1,6 +1,7 @@ contract Lotto { uint256 public constant ticketPrice = 555; } - +// ==== +// compileViaYul: also // ---- // ticketPrice() -> 555 diff --git a/test/libsolidity/semanticTests/builtinFunctions/assignment_to_const_var_involving_keccak.sol b/test/libsolidity/semanticTests/builtinFunctions/assignment_to_const_var_involving_keccak.sol index 2fc479d0e..a1bdf3236 100644 --- a/test/libsolidity/semanticTests/builtinFunctions/assignment_to_const_var_involving_keccak.sol +++ b/test/libsolidity/semanticTests/builtinFunctions/assignment_to_const_var_involving_keccak.sol @@ -5,5 +5,7 @@ contract C { return x; } } +// ==== +// compileViaYul: also // ---- // f() -> 0x4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45 diff --git a/test/libsolidity/semanticTests/constants/constant_string.sol b/test/libsolidity/semanticTests/constants/constant_string.sol index 56cbf982d..6b588571d 100644 --- a/test/libsolidity/semanticTests/constants/constant_string.sol +++ b/test/libsolidity/semanticTests/constants/constant_string.sol @@ -16,6 +16,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> 0x20, 3, "\x03\x01\x02" // g() -> 0x20, 3, "\x03\x01\x02" diff --git a/test/libsolidity/semanticTests/constants/simple_constant_variables_test.sol b/test/libsolidity/semanticTests/constants/simple_constant_variables_test.sol index c05060b7e..613cf62bb 100644 --- a/test/libsolidity/semanticTests/constants/simple_constant_variables_test.sol +++ b/test/libsolidity/semanticTests/constants/simple_constant_variables_test.sol @@ -6,5 +6,7 @@ contract Foo { uint256 constant x = 56; } +// ==== +// compileViaYul: also // ---- // getX() -> 56 diff --git a/test/libsolidity/semanticTests/intheritance/inherited_constant_state_var.sol b/test/libsolidity/semanticTests/intheritance/inherited_constant_state_var.sol index e25db0dcb..ab7a097cc 100644 --- a/test/libsolidity/semanticTests/intheritance/inherited_constant_state_var.sol +++ b/test/libsolidity/semanticTests/intheritance/inherited_constant_state_var.sol @@ -9,5 +9,7 @@ contract B is A { } } +// ==== +// compileViaYul: also // ---- // f() -> 7 diff --git a/test/libsolidity/semanticTests/various/assignment_to_const_var_involving_expression.sol b/test/libsolidity/semanticTests/various/assignment_to_const_var_involving_expression.sol index b83b1c598..4f849be89 100644 --- a/test/libsolidity/semanticTests/various/assignment_to_const_var_involving_expression.sol +++ b/test/libsolidity/semanticTests/various/assignment_to_const_var_involving_expression.sol @@ -6,5 +6,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> 0x57a From b580106c806aea796594edfa35a784955cc08f42 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Tue, 5 May 2020 17:22:54 +0200 Subject: [PATCH 18/89] Yul parser hack and more yul tests. --- libyul/AsmParser.cpp | 2 ++ test/libsolidity/semanticTests/array/function_memory_array.sol | 3 ++- .../semanticTests/cleanup/cleanup_bytes_types_shortening.sol | 3 ++- .../semanticTests/reverts/invalid_enum_compared.sol | 3 ++- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index 758b11d92..99a3a6e21 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -325,6 +325,7 @@ Parser::ElementaryOperation Parser::parseElementaryOperation() case Token::Bool: case Token::Address: case Token::Var: + case Token::In: { YulString literal{currentLiteral()}; if (m_dialect.builtin(literal)) @@ -515,6 +516,7 @@ YulString Parser::expectAsmIdentifier() case Token::Bool: case Token::Identifier: case Token::Var: + case Token::In: break; default: expectToken(Token::Identifier); diff --git a/test/libsolidity/semanticTests/array/function_memory_array.sol b/test/libsolidity/semanticTests/array/function_memory_array.sol index cc6b3cf46..9ff4cad33 100644 --- a/test/libsolidity/semanticTests/array/function_memory_array.sol +++ b/test/libsolidity/semanticTests/array/function_memory_array.sol @@ -30,7 +30,8 @@ contract C { return arr[i](x); } } - +// ==== +// compileViaYul: also // ---- // test(uint256,uint256): 10, 0 -> 11 // test(uint256,uint256): 10, 1 -> 12 diff --git a/test/libsolidity/semanticTests/cleanup/cleanup_bytes_types_shortening.sol b/test/libsolidity/semanticTests/cleanup/cleanup_bytes_types_shortening.sol index dc7c7f890..073e015b4 100644 --- a/test/libsolidity/semanticTests/cleanup/cleanup_bytes_types_shortening.sol +++ b/test/libsolidity/semanticTests/cleanup/cleanup_bytes_types_shortening.sol @@ -10,6 +10,7 @@ contract C { require(y == bytes2(0xffff)); } } - +// ==== +// compileViaYul: also // ---- // f() -> "\xff\xff\xff\xff" diff --git a/test/libsolidity/semanticTests/reverts/invalid_enum_compared.sol b/test/libsolidity/semanticTests/reverts/invalid_enum_compared.sol index 17ee32bb8..3c082a363 100644 --- a/test/libsolidity/semanticTests/reverts/invalid_enum_compared.sol +++ b/test/libsolidity/semanticTests/reverts/invalid_enum_compared.sol @@ -22,7 +22,8 @@ contract C { return garbled != garbled; } } - +// ==== +// compileViaYul: also // ---- // test_eq_ok() -> 1 // test_eq() -> FAILURE # both should throw # From c25a3eba14697b011411e105b019f626ba721ef1 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Mon, 4 May 2020 14:21:48 +0200 Subject: [PATCH 19/89] Fix accessing memory reference types in yul codegen and clean up on memory reads. --- libsolidity/codegen/YulUtilFunctions.cpp | 20 +++++++++++-------- libsolidity/codegen/YulUtilFunctions.h | 2 +- .../codegen/ir/IRGeneratorForStatements.cpp | 12 ++++------- .../viaYul/dirty_memory_read.sol | 15 ++++++++++++++ 4 files changed, 32 insertions(+), 17 deletions(-) create mode 100644 test/libsolidity/semanticTests/viaYul/dirty_memory_read.sol diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 78af6306e..540086756 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -2245,7 +2245,6 @@ string YulUtilFunctions::readFromMemoryOrCalldata(Type const& _type, bool _fromC } solAssert(_type.isValueType(), ""); - if (auto const* funType = dynamic_cast(&_type)) if (funType->kind() == FunctionType::Kind::External) return Whiskers(R"( @@ -2259,18 +2258,23 @@ string YulUtilFunctions::readFromMemoryOrCalldata(Type const& _type, bool _fromC ("splitFunction", splitExternalFunctionIdFunction()) .render(); + return Whiskers(R"( - function (memPtr) -> value { - value := (memPtr) - + function (ptr) -> value { + + value := calldataload(ptr) (value) - + + value := (mload(ptr)) + } )") ("functionName", functionName) - ("load", _fromCalldata ? "calldataload" : "mload") - ("needsValidation", _fromCalldata) - ("validate", _fromCalldata ? validatorFunction(_type) : "") + ("fromCalldata", _fromCalldata) + ("validate", validatorFunction(_type)) + // Byte array elements generally need cleanup. + // Other types are cleaned as well to account for dirty memory e.g. due to inline assembly. + ("cleanup", cleanupFunction(_type)) .render(); }); } diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index 4f7556f5f..9f21a7d39 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -204,7 +204,7 @@ public: std::string readFromStorage(Type const& _type, size_t _offset, bool _splitFunctionTypes); std::string readFromStorageDynamic(Type const& _type, bool _splitFunctionTypes); - /// @returns a function that reads a value type from memory. + /// @returns a function that reads a value type from memory. Performs cleanup. /// signature: (addr) -> value std::string readFromMemory(Type const& _type); /// @returns a function that reads a value type from calldata. diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index f795e0e98..aee1ec34b 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -117,10 +117,12 @@ struct CopyTranslate: public yul::ASTCopier reference.isOffset == false && reference.isSlot == false, "Should not be called for offset/slot" ); + auto const& var = m_context.localVariable(*varDecl); + solAssert(var.type().sizeOnStack() == 1, ""); return yul::Identifier{ _identifier.location, - yul::YulString{m_context.localVariable(*varDecl).name()} + yul::YulString{var.commaSeparatedList()} }; } @@ -2060,13 +2062,7 @@ IRVariable IRGeneratorForStatements::readFromLValue(IRLValue const& _lvalue) ")\n"; }, [&](IRLValue::Memory const& _memory) { - if (_memory.byteArrayElement) - define(result) << - m_utils.cleanupFunction(_lvalue.type) << - "(mload(" << - _memory.address << - "))\n"; - else if (_lvalue.type.isValueType()) + if (_lvalue.type.isValueType()) define(result) << m_utils.readFromMemory(_lvalue.type) << "(" << diff --git a/test/libsolidity/semanticTests/viaYul/dirty_memory_read.sol b/test/libsolidity/semanticTests/viaYul/dirty_memory_read.sol new file mode 100644 index 000000000..d03aa489f --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/dirty_memory_read.sol @@ -0,0 +1,15 @@ +contract C { + function f() public pure returns (uint8 x, bool a, bool b) { + uint8[1] memory m; + assembly { + mstore(m, 257) + } + x = m[0]; + a = (m[0] == 0x01); + b = (m[0] == 0x0101); + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> 1, true, false From 02c5f1f7488f43ce56668982ecad5de596ac6924 Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Wed, 6 May 2020 11:49:05 +0200 Subject: [PATCH 20/89] Remove --optimize-yul flag for soltest --- test/Common.cpp | 1 - test/Common.h | 1 - test/ExecutionFramework.cpp | 4 +--- test/libsolidity/GasCosts.cpp | 4 ++-- 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/test/Common.cpp b/test/Common.cpp index b65555ba1..69bfd21ee 100644 --- a/test/Common.cpp +++ b/test/Common.cpp @@ -94,7 +94,6 @@ CommonOptions::CommonOptions(std::string _caption): ("evmonepath", po::value(&evmonePath)->default_value(EVMOneEnvOrDefaultPath()), "path to evmone library") ("no-smt", po::bool_switch(&disableSMT), "disable SMT checker") ("optimize", po::bool_switch(&optimize), "enables optimization") - ("optimize-yul", po::bool_switch(&optimizeYul), "enables Yul optimization") ("enforce-via-yul", po::bool_switch(&enforceViaYul), "Enforce compiling all tests via yul to see if additional tests can be activated.") ("abiencoderv2", po::bool_switch(&useABIEncoderV2), "enables abi encoder v2") ("show-messages", po::bool_switch(&showMessages), "enables message output") diff --git a/test/Common.h b/test/Common.h index 128d23ee5..119050f39 100644 --- a/test/Common.h +++ b/test/Common.h @@ -46,7 +46,6 @@ struct CommonOptions: boost::noncopyable boost::filesystem::path evmonePath; boost::filesystem::path testPath; bool optimize = false; - bool optimizeYul = false; bool enforceViaYul = false; bool disableSMT = false; bool useABIEncoderV2 = false; diff --git a/test/ExecutionFramework.cpp b/test/ExecutionFramework.cpp index 170f5638c..ab11b2e98 100644 --- a/test/ExecutionFramework.cpp +++ b/test/ExecutionFramework.cpp @@ -49,9 +49,7 @@ ExecutionFramework::ExecutionFramework(langutil::EVMVersion _evmVersion): m_showMessages(solidity::test::CommonOptions::get().showMessages), m_evmHost(make_shared(m_evmVersion)) { - if (solidity::test::CommonOptions::get().optimizeYul) - m_optimiserSettings = solidity::frontend::OptimiserSettings::full(); - else if (solidity::test::CommonOptions::get().optimize) + if (solidity::test::CommonOptions::get().optimize) m_optimiserSettings = solidity::frontend::OptimiserSettings::standard(); reset(); diff --git a/test/libsolidity/GasCosts.cpp b/test/libsolidity/GasCosts.cpp index 1fa0bf712..252b7759b 100644 --- a/test/libsolidity/GasCosts.cpp +++ b/test/libsolidity/GasCosts.cpp @@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE(string_storage) // This is only correct on >=Constantinople. else if (CommonOptions::get().useABIEncoderV2) { - if (CommonOptions::get().optimizeYul) + if (CommonOptions::get().optimize) { // Costs with 0 are cases which cannot be triggered in tests. if (evmVersion < EVMVersion::istanbul()) @@ -129,7 +129,7 @@ BOOST_AUTO_TEST_CASE(string_storage) // This is only correct on >=Constantinople. else if (CommonOptions::get().useABIEncoderV2) { - if (CommonOptions::get().optimizeYul) + if (CommonOptions::get().optimize) { if (evmVersion < EVMVersion::istanbul()) CHECK_GAS(0, 21567, 20); From a93d79ff28d80b1b101f65e5ad5c605e6f33031f Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Mon, 4 May 2020 11:28:27 +0200 Subject: [PATCH 21/89] Remove obsolete flag --optimize-yul from scripts --- .circleci/soltest.sh | 2 +- scripts/tests.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/soltest.sh b/.circleci/soltest.sh index 948c79dee..f55239e60 100755 --- a/.circleci/soltest.sh +++ b/.circleci/soltest.sh @@ -57,7 +57,7 @@ get_logfile_basename() { BOOST_TEST_ARGS="--color_output=no --show_progress=yes --logger=JUNIT,error,test_results/`get_logfile_basename`.xml" SOLTEST_ARGS="--evm-version=$EVM $SOLTEST_FLAGS" test "${OPTIMIZE}" = "1" && SOLTEST_ARGS="${SOLTEST_ARGS} --optimize" -test "${ABI_ENCODER_V2}" = "1" && SOLTEST_ARGS="${SOLTEST_ARGS} --abiencoderv2 --optimize-yul" +test "${ABI_ENCODER_V2}" = "1" && SOLTEST_ARGS="${SOLTEST_ARGS} --abiencoderv2" echo "Running ${REPODIR}/build/test/soltest ${BOOST_TEST_ARGS} -- ${SOLTEST_ARGS}" diff --git a/scripts/tests.sh b/scripts/tests.sh index c0601a12d..00b4a1641 100755 --- a/scripts/tests.sh +++ b/scripts/tests.sh @@ -100,7 +100,7 @@ do force_abiv2_flag="" if [[ "$abiv2" == "yes" ]] then - force_abiv2_flag="--abiencoderv2 --optimize-yul" + force_abiv2_flag="--abiencoderv2" fi printTask "--> Running tests using "$optimize" --evm-version "$vm" $force_abiv2_flag..." From e3641b88ec59895762dbb649830da5aea4a94a5e Mon Sep 17 00:00:00 2001 From: a3d4 Date: Sat, 18 Apr 2020 03:00:22 +0200 Subject: [PATCH 22/89] Groundwork. Prepare for automatic tagging [Not compilable until the next commit] --- liblangutil/ErrorReporter.cpp | 65 +++++++++++++-------- liblangutil/ErrorReporter.h | 46 ++++++++++----- libsolidity/analysis/ConstantEvaluator.cpp | 1 + libsolidity/analysis/ImmutableValidator.cpp | 1 + libsolidity/analysis/SyntaxChecker.cpp | 2 +- libsolidity/parsing/Parser.cpp | 2 +- 6 files changed, 76 insertions(+), 41 deletions(-) diff --git a/liblangutil/ErrorReporter.cpp b/liblangutil/ErrorReporter.cpp index c6c059bc7..d06fbc65b 100644 --- a/liblangutil/ErrorReporter.cpp +++ b/liblangutil/ErrorReporter.cpp @@ -28,6 +28,8 @@ using namespace std; using namespace solidity; using namespace solidity::langutil; +ErrorId solidity::langutil::operator"" _error(unsigned long long _error) { return ErrorId{ _error }; } + ErrorReporter& ErrorReporter::operator=(ErrorReporter const& _errorReporter) { if (&_errorReporter == this) @@ -36,30 +38,31 @@ ErrorReporter& ErrorReporter::operator=(ErrorReporter const& _errorReporter) return *this; } - -void ErrorReporter::warning(string const& _description) +void ErrorReporter::warning(ErrorId _error, string const& _description) { - error(Error::Type::Warning, SourceLocation(), _description); + error(_error, Error::Type::Warning, SourceLocation(), _description); } void ErrorReporter::warning( + ErrorId _error, SourceLocation const& _location, string const& _description ) { - error(Error::Type::Warning, _location, _description); + error(_error, Error::Type::Warning, _location, _description); } void ErrorReporter::warning( + ErrorId _error, SourceLocation const& _location, string const& _description, SecondarySourceLocation const& _secondaryLocation ) { - error(Error::Type::Warning, _location, _secondaryLocation, _description); + error(_error, Error::Type::Warning, _location, _secondaryLocation, _description); } -void ErrorReporter::error(Error::Type _type, SourceLocation const& _location, string const& _description) +void ErrorReporter::error(ErrorId, Error::Type _type, SourceLocation const& _location, string const& _description) { if (checkForExcessiveErrors(_type)) return; @@ -72,7 +75,7 @@ void ErrorReporter::error(Error::Type _type, SourceLocation const& _location, st m_errorList.push_back(err); } -void ErrorReporter::error(Error::Type _type, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description) +void ErrorReporter::error(ErrorId, Error::Type _type, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description) { if (checkForExcessiveErrors(_type)) return; @@ -123,15 +126,15 @@ bool ErrorReporter::checkForExcessiveErrors(Error::Type _type) return false; } -void ErrorReporter::fatalError(Error::Type _type, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description) +void ErrorReporter::fatalError(ErrorId _error, Error::Type _type, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description) { - error(_type, _location, _secondaryLocation, _description); + error(_error, _type, _location, _secondaryLocation, _description); BOOST_THROW_EXCEPTION(FatalError()); } -void ErrorReporter::fatalError(Error::Type _type, SourceLocation const& _location, string const& _description) +void ErrorReporter::fatalError(ErrorId _error, Error::Type _type, SourceLocation const& _location, string const& _description) { - error(_type, _location, _description); + error(_error, _type, _location, _description); BOOST_THROW_EXCEPTION(FatalError()); } @@ -145,9 +148,10 @@ void ErrorReporter::clear() m_errorList.clear(); } -void ErrorReporter::declarationError(SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description) +void ErrorReporter::declarationError(ErrorId _error, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description) { error( + _error, Error::Type::DeclarationError, _location, _secondaryLocation, @@ -155,53 +159,59 @@ void ErrorReporter::declarationError(SourceLocation const& _location, SecondaryS ); } -void ErrorReporter::declarationError(SourceLocation const& _location, string const& _description) +void ErrorReporter::declarationError(ErrorId _error, SourceLocation const& _location, string const& _description) { error( + _error, Error::Type::DeclarationError, _location, _description ); } -void ErrorReporter::fatalDeclarationError(SourceLocation const& _location, std::string const& _description) +void ErrorReporter::fatalDeclarationError(ErrorId _error, SourceLocation const& _location, std::string const& _description) { fatalError( + _error, Error::Type::DeclarationError, _location, _description); } -void ErrorReporter::parserError(SourceLocation const& _location, string const& _description) +void ErrorReporter::parserError(ErrorId _error, SourceLocation const& _location, string const& _description) { error( + _error, Error::Type::ParserError, _location, _description ); } -void ErrorReporter::fatalParserError(SourceLocation const& _location, string const& _description) +void ErrorReporter::fatalParserError(ErrorId _error, SourceLocation const& _location, string const& _description) { fatalError( + _error, Error::Type::ParserError, _location, _description ); } -void ErrorReporter::syntaxError(SourceLocation const& _location, string const& _description) +void ErrorReporter::syntaxError(ErrorId _error, SourceLocation const& _location, string const& _description) { error( + _error, Error::Type::SyntaxError, _location, _description ); } -void ErrorReporter::typeError(SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description) +void ErrorReporter::typeError(ErrorId _error, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description) { error( + _error, Error::Type::TypeError, _location, _secondaryLocation, @@ -209,18 +219,21 @@ void ErrorReporter::typeError(SourceLocation const& _location, SecondarySourceLo ); } -void ErrorReporter::typeError(SourceLocation const& _location, string const& _description) +void ErrorReporter::typeError(ErrorId _error, SourceLocation const& _location, string const& _description) { error( + _error, Error::Type::TypeError, _location, _description ); } -void ErrorReporter::fatalTypeError(SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description) + +void ErrorReporter::fatalTypeError(ErrorId _error, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description) { fatalError( + _error, Error::Type::TypeError, _location, _secondaryLocation, @@ -228,26 +241,30 @@ void ErrorReporter::fatalTypeError(SourceLocation const& _location, SecondarySou ); } -void ErrorReporter::fatalTypeError(SourceLocation const& _location, string const& _description) +void ErrorReporter::fatalTypeError(ErrorId _error, SourceLocation const& _location, string const& _description) { - fatalError(Error::Type::TypeError, + fatalError( + _error, + Error::Type::TypeError, _location, _description ); } -void ErrorReporter::docstringParsingError(string const& _description) +void ErrorReporter::docstringParsingError(ErrorId _error, string const& _description) { error( + _error, Error::Type::DocstringParsingError, SourceLocation(), _description ); } -void ErrorReporter::docstringParsingError(SourceLocation const& _location, string const& _description) +void ErrorReporter::docstringParsingError(ErrorId _error, SourceLocation const& _location, string const& _description) { error( + _error, Error::Type::DocstringParsingError, _location, _description diff --git a/liblangutil/ErrorReporter.h b/liblangutil/ErrorReporter.h index 5aca4beb9..17e236e61 100644 --- a/liblangutil/ErrorReporter.h +++ b/liblangutil/ErrorReporter.h @@ -33,6 +33,15 @@ namespace solidity::langutil { +/** + * Unique identifiers are used to tag and track individual error cases. + * They are passed as the first parameter of error reporting functions. + * Suffix _error helps to find them in the sources. + * The struct ErrorId prevents incidental calls like typeError(3141) instead of typeError(3141_error). + */ +struct ErrorId { unsigned long long error = 0; }; +ErrorId operator"" _error(unsigned long long error); + class ErrorReporter { public: @@ -50,64 +59,68 @@ public: m_errorList += _errorList; } - void warning(std::string const& _description); + void warning(ErrorId _error, std::string const& _description); - void warning(SourceLocation const& _location, std::string const& _description); + void warning(ErrorId _error, SourceLocation const& _location, std::string const& _description); void warning( + ErrorId _error, SourceLocation const& _location, std::string const& _description, SecondarySourceLocation const& _secondaryLocation ); void error( + ErrorId _error, Error::Type _type, SourceLocation const& _location, std::string const& _description ); void declarationError( + ErrorId _error, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, std::string const& _description ); - void declarationError(SourceLocation const& _location, std::string const& _description); + void declarationError(ErrorId _error, SourceLocation const& _location, std::string const& _description); - void fatalDeclarationError(SourceLocation const& _location, std::string const& _description); + void fatalDeclarationError(ErrorId _error, SourceLocation const& _location, std::string const& _description); - void parserError(SourceLocation const& _location, std::string const& _description); + void parserError(ErrorId _error, SourceLocation const& _location, std::string const& _description); - void fatalParserError(SourceLocation const& _location, std::string const& _description); + void fatalParserError(ErrorId _error, SourceLocation const& _location, std::string const& _description); - void syntaxError(SourceLocation const& _location, std::string const& _description); + void syntaxError(ErrorId _error, SourceLocation const& _location, std::string const& _description); void typeError( + ErrorId _error, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation = SecondarySourceLocation(), std::string const& _description = std::string() ); - void typeError(SourceLocation const& _location, std::string const& _description); + void typeError(ErrorId _error, SourceLocation const& _location, std::string const& _description); template - void typeErrorConcatenateDescriptions(SourceLocation const& _location, Strings const&... _descriptions) + void typeErrorConcatenateDescriptions(ErrorId _error, SourceLocation const& _location, Strings const&... _descriptions) { - std::initializer_list const descs = {_descriptions...}; + std::initializer_list const descs = { _descriptions... }; solAssert(descs.size() > 0, "Need error descriptions!"); auto filterEmpty = boost::adaptors::filtered([](std::string const& _s) { return !_s.empty(); }); std::string errorStr = util::joinHumanReadable(descs | filterEmpty, " "); - error(Error::Type::TypeError, _location, errorStr); + error(_error, Error::Type::TypeError, _location, errorStr); } - void fatalTypeError(SourceLocation const& _location, std::string const& _description); - void fatalTypeError(SourceLocation const& _location, SecondarySourceLocation const& _secondLocation, std::string const& _description); + void fatalTypeError(ErrorId _error, SourceLocation const& _location, std::string const& _description); + void fatalTypeError(ErrorId _error, SourceLocation const& _location, SecondarySourceLocation const& _secondLocation, std::string const& _description); - void docstringParsingError(std::string const& _description); - void docstringParsingError(SourceLocation const& _location, std::string const& _description); + void docstringParsingError(ErrorId _error, std::string const& _description); + void docstringParsingError(ErrorId _error, SourceLocation const& _location, std::string const& _description); ErrorList const& errors() const; @@ -124,18 +137,21 @@ public: private: void error( + ErrorId _error, Error::Type _type, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, std::string const& _description = std::string()); void fatalError( + ErrorId _error, Error::Type _type, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, std::string const& _description = std::string()); void fatalError( + ErrorId _error, Error::Type _type, SourceLocation const& _location = SourceLocation(), std::string const& _description = std::string()); diff --git a/libsolidity/analysis/ConstantEvaluator.cpp b/libsolidity/analysis/ConstantEvaluator.cpp index d48d640ce..7617cc518 100644 --- a/libsolidity/analysis/ConstantEvaluator.cpp +++ b/libsolidity/analysis/ConstantEvaluator.cpp @@ -29,6 +29,7 @@ using namespace std; using namespace solidity; using namespace solidity::frontend; +using namespace solidity::langutil; void ConstantEvaluator::endVisit(UnaryOperation const& _operation) { diff --git a/libsolidity/analysis/ImmutableValidator.cpp b/libsolidity/analysis/ImmutableValidator.cpp index 598f43e50..a63d38ccf 100644 --- a/libsolidity/analysis/ImmutableValidator.cpp +++ b/libsolidity/analysis/ImmutableValidator.cpp @@ -22,6 +22,7 @@ #include using namespace solidity::frontend; +using namespace solidity::langutil; void ImmutableValidator::analyze() { diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp index c9ad29d33..bd2060d6a 100644 --- a/libsolidity/analysis/SyntaxChecker.cpp +++ b/libsolidity/analysis/SyntaxChecker.cpp @@ -123,7 +123,7 @@ bool SyntaxChecker::visit(PragmaDirective const& _pragma) m_errorReporter.syntaxError( _pragma.location(), "Source file requires different compiler version (current compiler is " + - string(VersionString) + " - note that nightly builds are considered to be " + string(VersionString) + ") - note that nightly builds are considered to be " "strictly less than the released version" ); m_versionPragmaFound = true; diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index c6da9a55b..d3c4a2cdd 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -130,7 +130,7 @@ void Parser::parsePragmaVersion(SourceLocation const& _location, vector c m_errorReporter.fatalParserError( _location, "Source file requires different compiler version (current compiler is " + - string(VersionString) + " - note that nightly builds are considered to be " + string(VersionString) + ") - note that nightly builds are considered to be " "strictly less than the released version" ); } From 8f68c043583247e56ff848d5193d01e49d4c2e9b Mon Sep 17 00:00:00 2001 From: a3d4 Date: Wed, 6 May 2020 00:38:28 +0200 Subject: [PATCH 23/89] Add unique IDs to error reporting calls --- liblangutil/ParserBase.cpp | 6 +- libsolidity/analysis/ConstantEvaluator.cpp | 3 +- libsolidity/analysis/ContractLevelChecker.cpp | 21 +- libsolidity/analysis/ControlFlowAnalyzer.cpp | 3 +- .../analysis/DeclarationTypeChecker.cpp | 12 +- libsolidity/analysis/DocStringAnalyser.cpp | 2 +- libsolidity/analysis/ImmutableValidator.cpp | 7 + libsolidity/analysis/NameAndTypeResolver.cpp | 13 +- libsolidity/analysis/OverrideChecker.cpp | 13 +- libsolidity/analysis/PostTypeChecker.cpp | 8 +- libsolidity/analysis/ReferencesResolver.cpp | 6 +- libsolidity/analysis/StaticAnalyzer.cpp | 13 +- libsolidity/analysis/SyntaxChecker.cpp | 56 +-- libsolidity/analysis/TypeChecker.cpp | 330 +++++++++++------- libsolidity/analysis/ViewPureChecker.cpp | 5 + libsolidity/formal/BMC.cpp | 21 +- libsolidity/formal/CHC.cpp | 4 +- libsolidity/formal/SMTEncoder.cpp | 29 +- libsolidity/interface/CompilerStack.cpp | 4 +- libsolidity/parsing/DocStringParser.cpp | 2 +- libsolidity/parsing/Parser.cpp | 1 + libyul/AsmAnalysis.cpp | 5 +- libyul/AsmParser.cpp | 9 +- libyul/AsmScopeFiller.cpp | 2 + 24 files changed, 382 insertions(+), 193 deletions(-) diff --git a/liblangutil/ParserBase.cpp b/liblangutil/ParserBase.cpp index 747cb37cf..c3a15794b 100644 --- a/liblangutil/ParserBase.cpp +++ b/liblangutil/ParserBase.cpp @@ -145,12 +145,12 @@ void ParserBase::decreaseRecursionDepth() void ParserBase::parserWarning(string const& _description) { - m_errorReporter.warning(currentLocation(), _description); + m_errorReporter.warning(6635_error, currentLocation(), _description); } void ParserBase::parserError(SourceLocation const& _location, string const& _description) { - m_errorReporter.parserError(_location, _description); + m_errorReporter.parserError(2314_error, _location, _description); } void ParserBase::parserError(string const& _description) @@ -165,5 +165,5 @@ void ParserBase::fatalParserError(string const& _description) void ParserBase::fatalParserError(SourceLocation const& _location, string const& _description) { - m_errorReporter.fatalParserError(_location, _description); + m_errorReporter.fatalParserError(1957_error, _location, _description); } diff --git a/libsolidity/analysis/ConstantEvaluator.cpp b/libsolidity/analysis/ConstantEvaluator.cpp index 7617cc518..4bd8b1389 100644 --- a/libsolidity/analysis/ConstantEvaluator.cpp +++ b/libsolidity/analysis/ConstantEvaluator.cpp @@ -47,6 +47,7 @@ void ConstantEvaluator::endVisit(BinaryOperation const& _operation) TypePointer commonType = left->binaryOperatorResult(_operation.getOperator(), right); if (!commonType) m_errorReporter.fatalTypeError( + 6020_error, _operation.location(), "Operator " + string(TokenTraits::toString(_operation.getOperator())) + @@ -83,7 +84,7 @@ void ConstantEvaluator::endVisit(Identifier const& _identifier) else if (!m_types->count(value.get())) { if (m_depth > 32) - m_errorReporter.fatalTypeError(_identifier.location(), "Cyclic constant definition (or maximum recursion depth exhausted)."); + m_errorReporter.fatalTypeError(5210_error, _identifier.location(), "Cyclic constant definition (or maximum recursion depth exhausted)."); ConstantEvaluator(m_errorReporter, m_depth + 1, m_types).evaluate(*value); } diff --git a/libsolidity/analysis/ContractLevelChecker.cpp b/libsolidity/analysis/ContractLevelChecker.cpp index 18051f99b..1327e89f3 100644 --- a/libsolidity/analysis/ContractLevelChecker.cpp +++ b/libsolidity/analysis/ContractLevelChecker.cpp @@ -78,6 +78,7 @@ void ContractLevelChecker::checkDuplicateFunctions(ContractDefinition const& _co { if (constructor) m_errorReporter.declarationError( + 7997_error, function->location(), SecondarySourceLocation().append("Another declaration is here:", constructor->location()), "More than one constructor defined." @@ -88,6 +89,7 @@ void ContractLevelChecker::checkDuplicateFunctions(ContractDefinition const& _co { if (fallback) m_errorReporter.declarationError( + 7301_error, function->location(), SecondarySourceLocation().append("Another declaration is here:", fallback->location()), "Only one fallback function is allowed." @@ -98,6 +100,7 @@ void ContractLevelChecker::checkDuplicateFunctions(ContractDefinition const& _co { if (receive) m_errorReporter.declarationError( + 4046_error, function->location(), SecondarySourceLocation().append("Another declaration is here:", receive->location()), "Only one receive function is allowed." @@ -147,6 +150,7 @@ void ContractLevelChecker::findDuplicateDefinitions(map> const ssl.limitSize(_message); m_errorReporter.declarationError( + 1686_error, overloads[i]->location(), ssl, _message @@ -197,9 +201,9 @@ void ContractLevelChecker::checkAbstractDefinitions(ContractDefinition const& _c if (_contract.abstract()) { if (_contract.contractKind() == ContractKind::Interface) - m_errorReporter.typeError(_contract.location(), "Interfaces do not need the \"abstract\" keyword, they are abstract implicitly."); + m_errorReporter.typeError(9348_error, _contract.location(), "Interfaces do not need the \"abstract\" keyword, they are abstract implicitly."); else if (_contract.contractKind() == ContractKind::Library) - m_errorReporter.typeError(_contract.location(), "Libraries cannot be abstract."); + m_errorReporter.typeError(9571_error, _contract.location(), "Libraries cannot be abstract."); else solAssert(_contract.contractKind() == ContractKind::Contract, ""); } @@ -215,7 +219,8 @@ void ContractLevelChecker::checkAbstractDefinitions(ContractDefinition const& _c SecondarySourceLocation ssl; for (auto declaration: _contract.annotation().unimplementedDeclarations) ssl.append("Missing implementation: ", declaration->location()); - m_errorReporter.typeError(_contract.location(), ssl, + m_errorReporter.typeError( + 3656_error,_contract.location(), ssl, "Contract \"" + _contract.annotation().canonicalName + "\" should be marked as abstract."); @@ -243,6 +248,7 @@ void ContractLevelChecker::checkBaseConstructorArguments(ContractDefinition cons } else m_errorReporter.declarationError( + 1563_error, modifier->location(), "Modifier-style base constructor call without arguments." ); @@ -304,6 +310,7 @@ void ContractLevelChecker::annotateBaseConstructorArguments( } m_errorReporter.declarationError( + 3364_error, *mainLocation, ssl, "Base constructor arguments given twice." @@ -343,6 +350,7 @@ void ContractLevelChecker::checkExternalTypeClashes(ContractDefinition const& _c for (size_t j = i + 1; j < it.second.size(); ++j) if (!it.second[i].second->hasEqualParameterTypes(*it.second[j].second)) m_errorReporter.typeError( + 9914_error, it.second[j].first->location(), "Function overload clash during conversion to external types for arguments." ); @@ -356,6 +364,7 @@ void ContractLevelChecker::checkHashCollisions(ContractDefinition const& _contra util::FixedHash<4> const& hash = it.first; if (hashes.count(hash)) m_errorReporter.typeError( + 1860_error, _contract.location(), string("Function signature hash collision for ") + it.second->externalSignature() ); @@ -369,11 +378,11 @@ void ContractLevelChecker::checkLibraryRequirements(ContractDefinition const& _c return; if (!_contract.baseContracts().empty()) - m_errorReporter.typeError(_contract.location(), "Library is not allowed to inherit."); + m_errorReporter.typeError(9469_error, _contract.location(), "Library is not allowed to inherit."); for (auto const& var: _contract.stateVariables()) if (!var->isConstant()) - m_errorReporter.typeError(var->location(), "Library cannot have non-constant state variables"); + m_errorReporter.typeError(9957_error, var->location(), "Library cannot have non-constant state variables"); } void ContractLevelChecker::checkBaseABICompatibility(ContractDefinition const& _contract) @@ -412,6 +421,7 @@ void ContractLevelChecker::checkBaseABICompatibility(ContractDefinition const& _ if (!errors.infos.empty()) m_errorReporter.fatalTypeError( + 6594_error, _contract.location(), errors, std::string("Contract \"") + @@ -428,6 +438,7 @@ void ContractLevelChecker::checkPayableFallbackWithoutReceive(ContractDefinition if (auto const* fallback = _contract.fallbackFunction()) if (fallback->isPayable() && !_contract.interfaceFunctionList().empty() && !_contract.receiveFunction()) m_errorReporter.warning( + 3628_error, _contract.location(), "This contract has a payable fallback function, but no receive ether function. Consider adding a receive ether function.", SecondarySourceLocation{}.append("The payable fallback function is defined here.", fallback->location()) diff --git a/libsolidity/analysis/ControlFlowAnalyzer.cpp b/libsolidity/analysis/ControlFlowAnalyzer.cpp index 1a001eb1e..84979082f 100644 --- a/libsolidity/analysis/ControlFlowAnalyzer.cpp +++ b/libsolidity/analysis/ControlFlowAnalyzer.cpp @@ -136,6 +136,7 @@ void ControlFlowAnalyzer::checkUninitializedAccess(CFGNode const* _entry, CFGNod ssl.append("The variable was declared here.", variableOccurrence->declaration().location()); m_errorReporter.typeError( + 3464_error, variableOccurrence->occurrence() ? *variableOccurrence->occurrence() : variableOccurrence->declaration().location(), @@ -176,6 +177,6 @@ void ControlFlowAnalyzer::checkUnreachable(CFGNode const* _entry, CFGNode const* // Extend the location, as long as the next location overlaps (unreachable is sorted). for (; it != unreachable.end() && it->start <= location.end; ++it) location.end = std::max(location.end, it->end); - m_errorReporter.warning(location, "Unreachable code."); + m_errorReporter.warning(5740_error, location, "Unreachable code."); } } diff --git a/libsolidity/analysis/DeclarationTypeChecker.cpp b/libsolidity/analysis/DeclarationTypeChecker.cpp index 0c53732d6..4e55151e9 100644 --- a/libsolidity/analysis/DeclarationTypeChecker.cpp +++ b/libsolidity/analysis/DeclarationTypeChecker.cpp @@ -188,12 +188,14 @@ void DeclarationTypeChecker::endVisit(Mapping const& _mapping) { if (contractType->contractDefinition().isLibrary()) m_errorReporter.fatalTypeError( + 1665_error, typeName->location(), "Library types cannot be used as mapping keys." ); } else if (typeName->annotation().type->category() != Type::Category::Enum) m_errorReporter.fatalTypeError( + 7804_error, typeName->location(), "Only elementary types, contract types or enums are allowed as mapping keys." ); @@ -253,9 +255,9 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable) return; if (_variable.isConstant() && !_variable.isStateVariable()) - m_errorReporter.declarationError(_variable.location(), "The \"constant\" keyword can only be used for state variables."); + m_errorReporter.declarationError(1788_error, _variable.location(), "The \"constant\" keyword can only be used for state variables."); if (_variable.immutable() && !_variable.isStateVariable()) - m_errorReporter.declarationError(_variable.location(), "The \"immutable\" keyword can only be used for state variables."); + m_errorReporter.declarationError(8297_error, _variable.location(), "The \"immutable\" keyword can only be used for state variables."); if (!_variable.typeName()) { @@ -360,19 +362,19 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable) void DeclarationTypeChecker::typeError(SourceLocation const& _location, string const& _description) { m_errorOccurred = true; - m_errorReporter.typeError(_location, _description); + m_errorReporter.typeError(2311_error, _location, _description); } void DeclarationTypeChecker::fatalTypeError(SourceLocation const& _location, string const& _description) { m_errorOccurred = true; - m_errorReporter.fatalTypeError(_location, _description); + m_errorReporter.fatalTypeError(5651_error, _location, _description); } void DeclarationTypeChecker::fatalDeclarationError(SourceLocation const& _location, string const& _description) { m_errorOccurred = true; - m_errorReporter.fatalDeclarationError(_location, _description); + m_errorReporter.fatalDeclarationError(2046_error, _location, _description); } bool DeclarationTypeChecker::check(ASTNode const& _node) diff --git a/libsolidity/analysis/DocStringAnalyser.cpp b/libsolidity/analysis/DocStringAnalyser.cpp index ee0a39163..53edc8cdf 100644 --- a/libsolidity/analysis/DocStringAnalyser.cpp +++ b/libsolidity/analysis/DocStringAnalyser.cpp @@ -173,5 +173,5 @@ void DocStringAnalyser::parseDocStrings( void DocStringAnalyser::appendError(SourceLocation const& _location, string const& _description) { m_errorOccured = true; - m_errorReporter.docstringParsingError(_location, _description); + m_errorReporter.docstringParsingError(7816_error, _location, _description); } diff --git a/libsolidity/analysis/ImmutableValidator.cpp b/libsolidity/analysis/ImmutableValidator.cpp index a63d38ccf..0fad0a66d 100644 --- a/libsolidity/analysis/ImmutableValidator.cpp +++ b/libsolidity/analysis/ImmutableValidator.cpp @@ -166,33 +166,39 @@ void ImmutableValidator::analyseVariableReference(VariableDeclaration const& _va { if (!m_currentConstructor) m_errorReporter.typeError( + 1581_error, _expression.location(), "Immutable variables can only be initialized inline or assigned directly in the constructor." ); else if (m_currentConstructor->annotation().contract->id() != _variableReference.annotation().contract->id()) m_errorReporter.typeError( + 7484_error, _expression.location(), "Immutable variables must be initialized in the constructor of the contract they are defined in." ); else if (m_inLoop) m_errorReporter.typeError( + 6672_error, _expression.location(), "Immutable variables can only be initialized once, not in a while statement." ); else if (m_inBranch) m_errorReporter.typeError( + 4599_error, _expression.location(), "Immutable variables must be initialized unconditionally, not in an if statement." ); if (!m_initializedStateVariables.emplace(&_variableReference).second) m_errorReporter.typeError( + 1574_error, _expression.location(), "Immutable state variable already initialized." ); } else if (m_inConstructionContext) m_errorReporter.typeError( + 7733_error, _expression.location(), "Immutable variables cannot be read during contract creation time, which means " "they cannot be read in the constructor or any function or modifier called from it." @@ -206,6 +212,7 @@ void ImmutableValidator::checkAllVariablesInitialized(solidity::langutil::Source if (varDecl->immutable()) if (!util::contains(m_initializedStateVariables, varDecl)) m_errorReporter.typeError( + 2658_error, _location, solidity::langutil::SecondarySourceLocation().append("Not initialized: ", varDecl->location()), "Construction control flow ends without initializing all immutable state variables." diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index 65831ec86..87482b78c 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -80,6 +80,7 @@ bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, maplocation(), "Import \"" + path + "\" (referenced as \"" + imp->path() + "\") not found." ); @@ -95,6 +96,7 @@ bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, maplocation(), "Declaration \"" + alias.symbol->name() + @@ -208,6 +210,7 @@ void NameAndTypeResolver::warnVariablesNamedLikeInstructions() // Don't warn the user for what the user did not. continue; m_errorReporter.warning( + 8261_error, declaration->location(), "Variable is shadowed in inline assembly by an instruction of the same name" ); @@ -326,6 +329,7 @@ void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base) } m_errorReporter.declarationError( + 9097_error, secondDeclarationLocation, SecondarySourceLocation().append("The previous declaration is here:", firstDeclarationLocation), "Identifier already declared." @@ -343,19 +347,19 @@ void NameAndTypeResolver::linearizeBaseContracts(ContractDefinition& _contract) UserDefinedTypeName const& baseName = baseSpecifier->name(); auto base = dynamic_cast(baseName.annotation().referencedDeclaration); if (!base) - m_errorReporter.fatalTypeError(baseName.location(), "Contract expected."); + m_errorReporter.fatalTypeError(8758_error, baseName.location(), "Contract expected."); // "push_front" has the effect that bases mentioned later can overwrite members of bases // mentioned earlier input.back().push_front(base); vector const& basesBases = base->annotation().linearizedBaseContracts; if (basesBases.empty()) - m_errorReporter.fatalTypeError(baseName.location(), "Definition of base has to precede definition of derived contract"); + m_errorReporter.fatalTypeError(2449_error, baseName.location(), "Definition of base has to precede definition of derived contract"); input.push_front(list(basesBases.begin(), basesBases.end())); } input.back().push_front(&_contract); vector result = cThreeMerge(input); if (result.empty()) - m_errorReporter.fatalTypeError(_contract.location(), "Linearization of inheritance graph impossible"); + m_errorReporter.fatalTypeError(5005_error, _contract.location(), "Linearization of inheritance graph impossible"); _contract.annotation().linearizedBaseContracts = result; _contract.annotation().contractDependencies.insert(result.begin() + 1, result.end()); } @@ -476,6 +480,7 @@ bool DeclarationRegistrationHelper::registerDeclaration( } _errorReporter.declarationError( + 2333_error, secondDeclarationLocation, SecondarySourceLocation().append("The previous declaration is here:", firstDeclarationLocation), "Identifier already declared." @@ -486,6 +491,7 @@ bool DeclarationRegistrationHelper::registerDeclaration( { if (dynamic_cast(shadowedDeclaration)) _errorReporter.warning( + 2319_error, *_errorLocation, "This declaration shadows a builtin symbol." ); @@ -493,6 +499,7 @@ bool DeclarationRegistrationHelper::registerDeclaration( { auto shadowedLocation = shadowedDeclaration->location(); _errorReporter.warning( + 2519_error, _declaration.location(), "This declaration shadows an existing declaration.", SecondarySourceLocation().append("The shadowed declaration is here:", shadowedLocation) diff --git a/libsolidity/analysis/OverrideChecker.cpp b/libsolidity/analysis/OverrideChecker.cpp index 91b45d33c..fbff807f9 100644 --- a/libsolidity/analysis/OverrideChecker.cpp +++ b/libsolidity/analysis/OverrideChecker.cpp @@ -461,6 +461,7 @@ void OverrideChecker::checkIllegalOverrides(ContractDefinition const& _contract) { if (contains_if(inheritedFuncs, MatchByName{modifier->name()})) m_errorReporter.typeError( + 5631_error, modifier->location(), "Override changes function or public state variable to modifier." ); @@ -474,7 +475,7 @@ void OverrideChecker::checkIllegalOverrides(ContractDefinition const& _contract) continue; if (contains_if(inheritedMods, MatchByName{function->name()})) - m_errorReporter.typeError(function->location(), "Override changes modifier to function."); + m_errorReporter.typeError(1469_error, function->location(), "Override changes modifier to function."); checkOverrideList(OverrideProxy{function}, inheritedFuncs); } @@ -484,7 +485,7 @@ void OverrideChecker::checkIllegalOverrides(ContractDefinition const& _contract) continue; if (contains_if(inheritedMods, MatchByName{stateVar->name()})) - m_errorReporter.typeError(stateVar->location(), "Override changes modifier to public state variable."); + m_errorReporter.typeError(1456_error, stateVar->location(), "Override changes modifier to public state variable."); checkOverrideList(OverrideProxy{stateVar}, inheritedFuncs); } @@ -500,6 +501,7 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr if (_overriding.isModifier() && *_overriding.modifierType() != *_super.modifierType()) m_errorReporter.typeError( + 1078_error, _overriding.location(), "Override changes modifier signature." ); @@ -593,6 +595,7 @@ void OverrideChecker::overrideListError( contractSingularPlural = "contracts "; m_errorReporter.typeError( + 5883_error, _item.overrides() ? _item.overrides()->location() : _item.location(), ssl, _message1 + @@ -606,6 +609,7 @@ void OverrideChecker::overrideListError( void OverrideChecker::overrideError(Declaration const& _overriding, Declaration const& _super, string const& _message, string const& _secondaryMsg) { m_errorReporter.typeError( + 9456_error, _overriding.location(), SecondarySourceLocation().append(_secondaryMsg, _super.location()), _message @@ -616,6 +620,7 @@ void OverrideChecker::overrideError(Declaration const& _overriding, Declaration void OverrideChecker::overrideError(OverrideProxy const& _overriding, OverrideProxy const& _super, string const& _message, string const& _secondaryMsg) { m_errorReporter.typeError( + 1452_error, _overriding.location(), SecondarySourceLocation().append(_secondaryMsg, _super.location()), _message @@ -718,7 +723,7 @@ void OverrideChecker::checkAmbiguousOverridesInternal(set _baseCa " Since one of the bases defines a public state variable which cannot be overridden, " "you have to change the inheritance layout or the names of the functions."; - m_errorReporter.typeError(_location, ssl, message); + m_errorReporter.typeError(6480_error, _location, ssl, message); } set OverrideChecker::resolveOverrideList(OverrideSpecifier const& _overrides) const @@ -766,6 +771,7 @@ void OverrideChecker::checkOverrideList(OverrideProxy _item, OverrideProxyBySign SecondarySourceLocation ssl; ssl.append("First occurrence here: ", list[i-1]->location()); m_errorReporter.typeError( + 4520_error, list[i]->location(), ssl, "Duplicate contract \"" + @@ -791,6 +797,7 @@ void OverrideChecker::checkOverrideList(OverrideProxy _item, OverrideProxyBySign if (_item.overrides() && expectedContracts.empty()) m_errorReporter.typeError( + 7792_error, _item.overrides()->location(), _item.astNodeNameCapitalized() + " has override specified but does not override anything." ); diff --git a/libsolidity/analysis/PostTypeChecker.cpp b/libsolidity/analysis/PostTypeChecker.cpp index 62317587a..1b5b5b7c3 100644 --- a/libsolidity/analysis/PostTypeChecker.cpp +++ b/libsolidity/analysis/PostTypeChecker.cpp @@ -122,6 +122,7 @@ struct ConstStateVarCircularReferenceChecker: public PostTypeChecker::Checker for (auto declaration: m_constVariables) if (auto identifier = findCycle(*declaration)) m_errorReporter.typeError( + 6161_error, declaration->location(), "The value of the constant " + declaration->name() + " has a cyclic dependency via " + identifier->name() + "." @@ -165,7 +166,7 @@ struct ConstStateVarCircularReferenceChecker: public PostTypeChecker::Checker auto visitor = [&](VariableDeclaration const& _variable, util::CycleDetector& _cycleDetector, size_t _depth) { if (_depth >= 256) - m_errorReporter.fatalDeclarationError(_variable.location(), "Variable definition exhausting cyclic dependency validator."); + m_errorReporter.fatalDeclarationError(7380_error, _variable.location(), "Variable definition exhausting cyclic dependency validator."); // Iterating through the dependencies needs to be deterministic and thus cannot // depend on the memory layout. @@ -209,6 +210,7 @@ struct OverrideSpecifierChecker: public PostTypeChecker::Checker TypeType const* actualTypeType = dynamic_cast(decl->type()); m_errorReporter.typeError( + 9301_error, override->location(), "Expected contract but got " + actualTypeType->actualType()->toString(true) + @@ -243,6 +245,7 @@ struct ModifierContextChecker: public PostTypeChecker::Checker if (ModifierType const* type = dynamic_cast(_identifier.annotation().type)) { m_errorReporter.typeError( + 3112_error, _identifier.location(), "Modifier can only be referenced in function headers." ); @@ -280,6 +283,7 @@ struct EventOutsideEmitChecker: public PostTypeChecker::Checker // Check for event outside of emit statement if (!m_insideEmitStatement && functionType->kind() == FunctionType::Kind::Event) m_errorReporter.typeError( + 3132_error, _functionCall.location(), "Event invocations have to be prefixed by \"emit\"." ); @@ -308,7 +312,7 @@ struct NoVariablesInInterfaceChecker: public PostTypeChecker::Checker && !_variable.isCallableOrCatchParameter() && !m_insideStruct ) - m_errorReporter.typeError(_variable.location(), "Variables cannot be declared in interfaces."); + m_errorReporter.typeError(8274_error, _variable.location(), "Variables cannot be declared in interfaces."); return true; } diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index f72253c1f..3415dee22 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -268,19 +268,19 @@ void ReferencesResolver::operator()(yul::VariableDeclaration const& _varDecl) void ReferencesResolver::declarationError(SourceLocation const& _location, string const& _description) { m_errorOccurred = true; - m_errorReporter.declarationError(_location, _description); + m_errorReporter.declarationError(8532_error, _location, _description); } void ReferencesResolver::declarationError(SourceLocation const& _location, SecondarySourceLocation const& _ssl, string const& _description) { m_errorOccurred = true; - m_errorReporter.declarationError(_location, _ssl, _description); + m_errorReporter.declarationError(3881_error, _location, _ssl, _description); } void ReferencesResolver::fatalDeclarationError(SourceLocation const& _location, string const& _description) { m_errorOccurred = true; - m_errorReporter.fatalDeclarationError(_location, _description); + m_errorReporter.fatalDeclarationError(6546_error, _location, _description); } } diff --git a/libsolidity/analysis/StaticAnalyzer.cpp b/libsolidity/analysis/StaticAnalyzer.cpp index c53bc03fa..3cbfa4db4 100644 --- a/libsolidity/analysis/StaticAnalyzer.cpp +++ b/libsolidity/analysis/StaticAnalyzer.cpp @@ -120,13 +120,14 @@ void StaticAnalyzer::endVisit(FunctionDefinition const&) { if (var.first.second->isCallableOrCatchParameter()) m_errorReporter.warning( + 5667_error, var.first.second->location(), "Unused " + string(var.first.second->isTryCatchParameter() ? "try/catch" : "function") + " parameter. Remove or comment out the variable name to silence this warning." ); else - m_errorReporter.warning(var.first.second->location(), "Unused local variable."); + m_errorReporter.warning(2072_error, var.first.second->location(), "Unused local variable."); } m_localVarUseCount.clear(); m_constructor = false; @@ -159,6 +160,7 @@ bool StaticAnalyzer::visit(VariableDeclaration const& _variable) set structsSeen; if (structureSizeEstimate(*_variable.type(), structsSeen) >= bigint(1) << 64) m_errorReporter.warning( + 3408_error, _variable.location(), "Variable covers a large part of storage and thus makes collisions likely. " "Either use mappings or dynamic arrays and allow their size to be increased only " @@ -183,6 +185,7 @@ bool StaticAnalyzer::visit(ExpressionStatement const& _statement) { if (_statement.expression().annotation().isPure) m_errorReporter.warning( + 6133_error, _statement.location(), "Statement has no effect." ); @@ -196,11 +199,13 @@ bool StaticAnalyzer::visit(MemberAccess const& _memberAccess) { if (type->kind() == MagicType::Kind::Message && _memberAccess.memberName() == "gas") m_errorReporter.typeError( + 1400_error, _memberAccess.location(), "\"msg.gas\" has been deprecated in favor of \"gasleft()\"" ); else if (type->kind() == MagicType::Kind::Block && _memberAccess.memberName() == "blockhash") m_errorReporter.typeError( + 8113_error, _memberAccess.location(), "\"block.blockhash()\" has been deprecated in favor of \"blockhash()\"" ); @@ -211,6 +216,7 @@ bool StaticAnalyzer::visit(MemberAccess const& _memberAccess) ContractType const& contract = dynamic_cast(*type->typeArgument()); if (m_constructorUsesAssembly->check(contract.contractDefinition())) m_errorReporter.warning( + 6417_error, _memberAccess.location(), "The constructor of the contract (or its base) uses inline assembly. " "Because of that, it might be that the deployed bytecode is different from type(...).runtimeCode." @@ -222,6 +228,7 @@ bool StaticAnalyzer::visit(MemberAccess const& _memberAccess) if (auto const* type = dynamic_cast(_memberAccess.annotation().type)) if (type->kind() == FunctionType::Kind::BareCallCode) m_errorReporter.typeError( + 2256_error, _memberAccess.location(), "\"callcode\" has been deprecated in favour of \"delegatecall\"." ); @@ -235,6 +242,7 @@ bool StaticAnalyzer::visit(MemberAccess const& _memberAccess) { if (id->name() == "this") m_errorReporter.warning( + 5805_error, id->location(), "\"this\" used in constructor. " "Note that external functions of a contract " @@ -285,6 +293,7 @@ bool StaticAnalyzer::visit(BinaryOperation const& _operation) )) if (rhs->isZero()) m_errorReporter.typeError( + 1211_error, _operation.location(), (_operation.getOperator() == Token::Div) ? "Division by zero." : "Modulo zero." ); @@ -307,6 +316,7 @@ bool StaticAnalyzer::visit(FunctionCall const& _functionCall) )) if (lastArg->isZero()) m_errorReporter.typeError( + 4195_error, _functionCall.location(), "Arithmetic modulo zero." ); @@ -317,6 +327,7 @@ bool StaticAnalyzer::visit(FunctionCall const& _functionCall) functionType->declaration().scope() == m_currentContract ) m_errorReporter.typeError( + 6700_error, _functionCall.location(), SecondarySourceLocation().append( "The function declaration is here:", diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp index bd2060d6a..c3267c37f 100644 --- a/libsolidity/analysis/SyntaxChecker.cpp +++ b/libsolidity/analysis/SyntaxChecker.cpp @@ -69,7 +69,7 @@ void SyntaxChecker::endVisit(SourceUnit const& _sourceUnit) string(";\""); // when reporting the warning, print the source name only - m_errorReporter.warning({-1, -1, _sourceUnit.location().source}, errorString); + m_errorReporter.warning(3420_error, {-1, -1, _sourceUnit.location().source}, errorString); } m_sourceUnit = nullptr; } @@ -79,18 +79,20 @@ bool SyntaxChecker::visit(PragmaDirective const& _pragma) solAssert(!_pragma.tokens().empty(), ""); solAssert(_pragma.tokens().size() == _pragma.literals().size(), ""); if (_pragma.tokens()[0] != Token::Identifier) - m_errorReporter.syntaxError(_pragma.location(), "Invalid pragma \"" + _pragma.literals()[0] + "\""); + m_errorReporter.syntaxError(5226_error, _pragma.location(), "Invalid pragma \"" + _pragma.literals()[0] + "\""); else if (_pragma.literals()[0] == "experimental") { solAssert(m_sourceUnit, ""); vector literals(_pragma.literals().begin() + 1, _pragma.literals().end()); if (literals.empty()) m_errorReporter.syntaxError( + 9679_error, _pragma.location(), "Experimental feature name is missing." ); else if (literals.size() > 1) m_errorReporter.syntaxError( + 6022_error, _pragma.location(), "Stray arguments." ); @@ -98,17 +100,17 @@ bool SyntaxChecker::visit(PragmaDirective const& _pragma) { string const literal = literals[0]; if (literal.empty()) - m_errorReporter.syntaxError(_pragma.location(), "Empty experimental feature name is invalid."); + m_errorReporter.syntaxError(3250_error, _pragma.location(), "Empty experimental feature name is invalid."); else if (!ExperimentalFeatureNames.count(literal)) - m_errorReporter.syntaxError(_pragma.location(), "Unsupported experimental feature name."); + m_errorReporter.syntaxError(8491_error, _pragma.location(), "Unsupported experimental feature name."); else if (m_sourceUnit->annotation().experimentalFeatures.count(ExperimentalFeatureNames.at(literal))) - m_errorReporter.syntaxError(_pragma.location(), "Duplicate experimental feature name."); + m_errorReporter.syntaxError(1231_error, _pragma.location(), "Duplicate experimental feature name."); else { auto feature = ExperimentalFeatureNames.at(literal); m_sourceUnit->annotation().experimentalFeatures.insert(feature); if (!ExperimentalFeatureWithoutWarning.count(feature)) - m_errorReporter.warning(_pragma.location(), "Experimental features are turned on. Do not use experimental features on live deployments."); + m_errorReporter.warning(2264_error, _pragma.location(), "Experimental features are turned on. Do not use experimental features on live deployments."); } } } @@ -121,6 +123,7 @@ bool SyntaxChecker::visit(PragmaDirective const& _pragma) static SemVerVersion const currentVersion{string(VersionString)}; if (!matchExpression.matches(currentVersion)) m_errorReporter.syntaxError( + 3997_error, _pragma.location(), "Source file requires different compiler version (current compiler is " + string(VersionString) + ") - note that nightly builds are considered to be " @@ -129,7 +132,7 @@ bool SyntaxChecker::visit(PragmaDirective const& _pragma) m_versionPragmaFound = true; } else - m_errorReporter.syntaxError(_pragma.location(), "Unknown pragma \"" + _pragma.literals()[0] + "\""); + m_errorReporter.syntaxError(4936_error, _pragma.location(), "Unknown pragma \"" + _pragma.literals()[0] + "\""); return true; } @@ -142,7 +145,7 @@ bool SyntaxChecker::visit(ModifierDefinition const&) void SyntaxChecker::endVisit(ModifierDefinition const& _modifier) { if (_modifier.isImplemented() && !m_placeholderFound) - m_errorReporter.syntaxError(_modifier.body().location(), "Modifier body does not contain '_'."); + m_errorReporter.syntaxError(2883_error, _modifier.body().location(), "Modifier body does not contain '_'."); m_placeholderFound = false; } @@ -150,7 +153,7 @@ void SyntaxChecker::checkSingleStatementVariableDeclaration(ASTNode const& _stat { auto varDecl = dynamic_cast(&_statement); if (varDecl) - m_errorReporter.syntaxError(_statement.location(), "Variable declarations can only be used inside blocks."); + m_errorReporter.syntaxError(9079_error, _statement.location(), "Variable declarations can only be used inside blocks."); } bool SyntaxChecker::visit(IfStatement const& _ifStatement) @@ -189,7 +192,7 @@ bool SyntaxChecker::visit(Continue const& _continueStatement) { if (m_inLoopDepth <= 0) // we're not in a for/while loop, report syntax error - m_errorReporter.syntaxError(_continueStatement.location(), "\"continue\" has to be in a \"for\" or \"while\" loop."); + m_errorReporter.syntaxError(4123_error, _continueStatement.location(), "\"continue\" has to be in a \"for\" or \"while\" loop."); return true; } @@ -197,13 +200,14 @@ bool SyntaxChecker::visit(Break const& _breakStatement) { if (m_inLoopDepth <= 0) // we're not in a for/while loop, report syntax error - m_errorReporter.syntaxError(_breakStatement.location(), "\"break\" has to be in a \"for\" or \"while\" loop."); + m_errorReporter.syntaxError(6102_error, _breakStatement.location(), "\"break\" has to be in a \"for\" or \"while\" loop."); return true; } bool SyntaxChecker::visit(Throw const& _throwStatement) { m_errorReporter.syntaxError( + 4538_error, _throwStatement.location(), "\"throw\" is deprecated in favour of \"revert()\", \"require()\" and \"assert()\"." ); @@ -222,29 +226,29 @@ bool SyntaxChecker::visit(Literal const& _literal) // Generic checks no matter what base this number literal is of: if (value.back() == '_') { - m_errorReporter.syntaxError(_literal.location(), "Invalid use of underscores in number literal. No trailing underscores allowed."); + m_errorReporter.syntaxError(2090_error, _literal.location(), "Invalid use of underscores in number literal. No trailing underscores allowed."); return true; } if (value.find("__") != ASTString::npos) { - m_errorReporter.syntaxError(_literal.location(), "Invalid use of underscores in number literal. Only one consecutive underscores between digits allowed."); + m_errorReporter.syntaxError(2990_error, _literal.location(), "Invalid use of underscores in number literal. Only one consecutive underscores between digits allowed."); return true; } if (!_literal.isHexNumber()) // decimal literal { if (value.find("._") != ASTString::npos) - m_errorReporter.syntaxError(_literal.location(), "Invalid use of underscores in number literal. No underscores in front of the fraction part allowed."); + m_errorReporter.syntaxError(3891_error, _literal.location(), "Invalid use of underscores in number literal. No underscores in front of the fraction part allowed."); if (value.find("_.") != ASTString::npos) - m_errorReporter.syntaxError(_literal.location(), "Invalid use of underscores in number literal. No underscores in front of the fraction part allowed."); + m_errorReporter.syntaxError(1023_error, _literal.location(), "Invalid use of underscores in number literal. No underscores in front of the fraction part allowed."); if (value.find("_e") != ASTString::npos) - m_errorReporter.syntaxError(_literal.location(), "Invalid use of underscores in number literal. No underscore at the end of the mantissa allowed."); + m_errorReporter.syntaxError(6415_error, _literal.location(), "Invalid use of underscores in number literal. No underscore at the end of the mantissa allowed."); if (value.find("e_") != ASTString::npos) - m_errorReporter.syntaxError(_literal.location(), "Invalid use of underscores in number literal. No underscore in front of exponent allowed."); + m_errorReporter.syntaxError(6165_error, _literal.location(), "Invalid use of underscores in number literal. No underscore in front of exponent allowed."); } return true; @@ -253,7 +257,7 @@ bool SyntaxChecker::visit(Literal const& _literal) bool SyntaxChecker::visit(UnaryOperation const& _operation) { if (_operation.getOperator() == Token::Add) - m_errorReporter.syntaxError(_operation.location(), "Use of unary + is disallowed."); + m_errorReporter.syntaxError(9636_error, _operation.location(), "Use of unary + is disallowed."); return true; } @@ -265,6 +269,7 @@ bool SyntaxChecker::visit(InlineAssembly const& _inlineAssembly) if (yul::MSizeFinder::containsMSize(_inlineAssembly.dialect(), _inlineAssembly.operations())) m_errorReporter.syntaxError( + 6553_error, _inlineAssembly.location(), "The msize instruction cannot be used when the Yul optimizer is activated because " "it can change its semantics. Either disable the Yul optimizer or do not use the instruction." @@ -285,7 +290,8 @@ bool SyntaxChecker::visit(ContractDefinition const& _contract) ASTString const& contractName = _contract.name(); for (FunctionDefinition const* function: _contract.definedFunctions()) if (function->name() == contractName) - m_errorReporter.syntaxError(function->location(), + m_errorReporter.syntaxError( + 5796_error,function->location(), "Functions are not allowed to have the same name as the contract. " "If you intend this to be a constructor, use \"constructor(...) { ... }\" to define it." ); @@ -298,15 +304,16 @@ bool SyntaxChecker::visit(FunctionDefinition const& _function) { string suggestedVisibility = _function.isFallback() || _function.isReceive() || m_isInterface ? "external" : "public"; m_errorReporter.syntaxError( + 4937_error, _function.location(), "No visibility specified. Did you intend to add \"" + suggestedVisibility + "\"?" ); } if (m_isInterface && !_function.modifiers().empty()) - m_errorReporter.syntaxError(_function.location(), "Functions in interfaces cannot have modifiers."); + m_errorReporter.syntaxError(5842_error, _function.location(), "Functions in interfaces cannot have modifiers."); else if (!_function.isImplemented() && !_function.modifiers().empty()) - m_errorReporter.syntaxError(_function.location(), "Functions without implementation cannot have modifiers."); + m_errorReporter.syntaxError(2668_error, _function.location(), "Functions without implementation cannot have modifiers."); return true; } @@ -315,11 +322,11 @@ bool SyntaxChecker::visit(FunctionTypeName const& _node) { for (auto const& decl: _node.parameterTypeList()->parameters()) if (!decl->name().empty()) - m_errorReporter.warning(decl->location(), "Naming function type parameters is deprecated."); + m_errorReporter.warning(6162_error, decl->location(), "Naming function type parameters is deprecated."); for (auto const& decl: _node.returnParameterTypeList()->parameters()) if (!decl->name().empty()) - m_errorReporter.syntaxError(decl->location(), "Return parameters in function types may not be named."); + m_errorReporter.syntaxError(7304_error, decl->location(), "Return parameters in function types may not be named."); return true; } @@ -329,6 +336,7 @@ bool SyntaxChecker::visit(VariableDeclarationStatement const& _statement) // Report if none of the variable components in the tuple have a name (only possible via deprecated "var") if (boost::algorithm::all_of_equal(_statement.declarations(), nullptr)) m_errorReporter.syntaxError( + 3299_error, _statement.location(), "The use of the \"var\" keyword is disallowed. The declaration part of the statement can be removed, since it is empty." ); @@ -339,7 +347,7 @@ bool SyntaxChecker::visit(VariableDeclarationStatement const& _statement) bool SyntaxChecker::visit(StructDefinition const& _struct) { if (_struct.members().empty()) - m_errorReporter.syntaxError(_struct.location(), "Defining empty structs is disallowed."); + m_errorReporter.syntaxError(5306_error, _struct.location(), "Defining empty structs is disallowed."); return true; } diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index b4030c0c4..7277714b8 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -117,6 +117,7 @@ void TypeChecker::checkDoubleStorageAssignment(Assignment const& _assignment) } if (storageToStorageCopies >= 1 && toStorageCopies >= 2) m_errorReporter.warning( + 7238_error, _assignment.location(), "This assignment performs two copies to storage. Since storage copies do not first " "copy to a temporary location, one of them might be overwritten before the second " @@ -130,6 +131,7 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c vector> arguments = _functionCall.arguments(); if (arguments.size() != 2) m_errorReporter.typeError( + 5782_error, _functionCall.location(), "This function takes two arguments, but " + toString(arguments.size()) + @@ -142,6 +144,7 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c !type(*arguments.front())->isImplicitlyConvertibleTo(*TypeProvider::bytesCalldata()) ) m_errorReporter.typeError( + 1956_error, arguments.front()->location(), "The first argument to \"abi.decode\" must be implicitly convertible to " "bytes memory or bytes calldata, but is of type " + @@ -158,6 +161,7 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c if (!tupleExpression) { m_errorReporter.typeError( + 6444_error, arguments[1]->location(), "The second argument to \"abi.decode\" has to be a tuple of types." ); @@ -186,6 +190,7 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c ); if (!actualType->fullEncodingType(false, _abiEncoderV2, false)) m_errorReporter.typeError( + 9611_error, typeArgument->location(), "Decoding type " + actualType->toString(false) + " not supported." ); @@ -193,7 +198,7 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c } else { - m_errorReporter.typeError(typeArgument->location(), "Argument has to be a type name."); + m_errorReporter.typeError(1039_error, typeArgument->location(), "Argument has to be a type name."); components.push_back(TypeProvider::emptyTuple()); } } @@ -206,6 +211,7 @@ TypePointers TypeChecker::typeCheckMetaTypeFunctionAndRetrieveReturnType(Functio if (arguments.size() != 1) { m_errorReporter.typeError( + 8885_error, _functionCall.location(), "This function takes one argument, but " + toString(arguments.size()) + @@ -220,6 +226,7 @@ TypePointers TypeChecker::typeCheckMetaTypeFunctionAndRetrieveReturnType(Functio ) { m_errorReporter.typeError( + 4259_error, arguments.front()->location(), "Invalid type for argument in function call. " "Contract type required, but " + @@ -238,10 +245,10 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance) solAssert(base, "Base contract not available."); if (m_scope->isInterface() && !base->isInterface()) - m_errorReporter.typeError(_inheritance.location(), "Interfaces can only inherit from other interfaces."); + m_errorReporter.typeError(6536_error, _inheritance.location(), "Interfaces can only inherit from other interfaces."); if (base->isLibrary()) - m_errorReporter.typeError(_inheritance.location(), "Libraries cannot be inherited from."); + m_errorReporter.typeError(2571_error, _inheritance.location(), "Libraries cannot be inherited from."); auto const& arguments = _inheritance.arguments(); TypePointers parameterTypes; @@ -254,6 +261,7 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance) if (parameterTypes.size() != arguments->size()) { m_errorReporter.typeError( + 7927_error, _inheritance.location(), "Wrong argument count for constructor call: " + toString(arguments->size()) + @@ -267,6 +275,7 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance) BoolResult result = type(*(*arguments)[i])->isImplicitlyConvertibleTo(*parameterTypes[i]); if (!result) m_errorReporter.typeErrorConcatenateDescriptions( + 9827_error, (*arguments)[i]->location(), "Invalid type for argument in constructor call. " "Invalid implicit conversion from " + @@ -286,13 +295,13 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor) _usingFor.libraryName().annotation().referencedDeclaration ); if (!library || !library->isLibrary()) - m_errorReporter.fatalTypeError(_usingFor.libraryName().location(), "Library name expected."); + m_errorReporter.fatalTypeError(4357_error, _usingFor.libraryName().location(), "Library name expected."); } void TypeChecker::endVisit(ModifierDefinition const& _modifier) { if (!_modifier.isImplemented() && !_modifier.virtualSemantics()) - m_errorReporter.typeError(_modifier.location(), "Modifiers without implementation must be marked virtual."); + m_errorReporter.typeError(8063_error, _modifier.location(), "Modifiers without implementation must be marked virtual."); } bool TypeChecker::visit(FunctionDefinition const& _function) @@ -302,17 +311,17 @@ bool TypeChecker::visit(FunctionDefinition const& _function) if (_function.markedVirtual()) { if (_function.annotation().contract->isInterface()) - m_errorReporter.warning(_function.location(), "Interface functions are implicitly \"virtual\""); + m_errorReporter.warning(5815_error, _function.location(), "Interface functions are implicitly \"virtual\""); if (_function.visibility() == Visibility::Private) - m_errorReporter.typeError(_function.location(), "\"virtual\" and \"private\" cannot be used together."); + m_errorReporter.typeError(3942_error, _function.location(), "\"virtual\" and \"private\" cannot be used together."); } if (_function.isPayable()) { if (isLibraryFunction) - m_errorReporter.typeError(_function.location(), "Library functions cannot be payable."); + m_errorReporter.typeError(7708_error, _function.location(), "Library functions cannot be payable."); if (_function.isOrdinary() && !_function.isPartOfExternalInterface()) - m_errorReporter.typeError(_function.location(), "Internal functions cannot be payable."); + m_errorReporter.typeError(5587_error, _function.location(), "Internal functions cannot be payable."); } auto checkArgumentAndReturnParameter = [&](VariableDeclaration const& var) { if (type(var)->category() == Type::Category::Mapping) @@ -320,9 +329,9 @@ bool TypeChecker::visit(FunctionDefinition const& _function) if (var.referenceLocation() != VariableDeclaration::Location::Storage) { if (!isLibraryFunction && _function.isPublic()) - m_errorReporter.typeError(var.location(), "Mapping types can only have a data location of \"storage\" and thus only be parameters or return variables for internal or library functions."); + m_errorReporter.typeError(3442_error, var.location(), "Mapping types can only have a data location of \"storage\" and thus only be parameters or return variables for internal or library functions."); else - m_errorReporter.typeError(var.location(), "Mapping types can only have a data location of \"storage\"." ); + m_errorReporter.typeError(5380_error, var.location(), "Mapping types can only have a data location of \"storage\"." ); } else { @@ -332,7 +341,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function) else { if (!type(var)->canLiveOutsideStorage() && _function.isPublic()) - m_errorReporter.typeError(var.location(), "Type is required to live outside storage."); + m_errorReporter.typeError(3312_error, var.location(), "Type is required to live outside storage."); if (_function.isPublic()) { auto iType = type(var)->interfaceType(isLibraryFunction); @@ -340,7 +349,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function) if (!iType) { solAssert(!iType.message().empty(), "Expected detailed error message!"); - m_errorReporter.fatalTypeError(var.location(), iType.message()); + m_errorReporter.fatalTypeError(4103_error, var.location(), iType.message()); } } } @@ -350,6 +359,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function) !typeSupportedByOldABIEncoder(*type(var), isLibraryFunction) ) m_errorReporter.typeError( + 4957_error, var.location(), "This type is only supported in ABIEncoderV2. " "Use \"pragma experimental ABIEncoderV2;\" to enable the feature." @@ -380,7 +390,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function) if (modifiers.count(decl)) { if (dynamic_cast(decl)) - m_errorReporter.declarationError(modifier->location(), "Base constructor already provided."); + m_errorReporter.declarationError(1697_error, modifier->location(), "Base constructor already provided."); } else modifiers.insert(decl); @@ -388,25 +398,25 @@ bool TypeChecker::visit(FunctionDefinition const& _function) if (m_scope->isInterface()) { if (_function.isImplemented()) - m_errorReporter.typeError(_function.location(), "Functions in interfaces cannot have an implementation."); + m_errorReporter.typeError(4726_error, _function.location(), "Functions in interfaces cannot have an implementation."); if (_function.visibility() != Visibility::External) - m_errorReporter.typeError(_function.location(), "Functions in interfaces must be declared external."); + m_errorReporter.typeError(1560_error, _function.location(), "Functions in interfaces must be declared external."); if (_function.isConstructor()) - m_errorReporter.typeError(_function.location(), "Constructor cannot be defined in interfaces."); + m_errorReporter.typeError(6482_error, _function.location(), "Constructor cannot be defined in interfaces."); } else if (m_scope->contractKind() == ContractKind::Library) if (_function.isConstructor()) - m_errorReporter.typeError(_function.location(), "Constructor cannot be defined in libraries."); + m_errorReporter.typeError(7634_error, _function.location(), "Constructor cannot be defined in libraries."); if (_function.isImplemented()) _function.body().accept(*this); else if (_function.isConstructor()) - m_errorReporter.typeError(_function.location(), "Constructor must be implemented if declared."); + m_errorReporter.typeError(5700_error, _function.location(), "Constructor must be implemented if declared."); else if (isLibraryFunction) - m_errorReporter.typeError(_function.location(), "Library functions must be implemented if declared."); + m_errorReporter.typeError(9231_error, _function.location(), "Library functions must be implemented if declared."); else if (!_function.virtualSemantics()) - m_errorReporter.typeError(_function.location(), "Functions without implementation must be marked virtual."); + m_errorReporter.typeError(5424_error, _function.location(), "Functions without implementation must be marked virtual."); if (_function.isFallback()) @@ -431,7 +441,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) if (auto contractType = dynamic_cast(varType)) if (contractType->contractDefinition().isLibrary()) - m_errorReporter.typeError(_variable.location(), "The type of a variable cannot be a library."); + m_errorReporter.typeError(1273_error, _variable.location(), "The type of a variable cannot be a library."); if (_variable.value()) expectType(*_variable.value(), *varType); if (_variable.isConstant()) @@ -442,13 +452,14 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) if (auto arrayType = dynamic_cast(_variable.type())) allowed = arrayType->isByteArray(); if (!allowed) - m_errorReporter.typeError(_variable.location(), "Constants of non-value type not yet implemented."); + m_errorReporter.typeError(9259_error, _variable.location(), "Constants of non-value type not yet implemented."); } if (!_variable.value()) - m_errorReporter.typeError(_variable.location(), "Uninitialized \"constant\" variable."); + m_errorReporter.typeError(4266_error, _variable.location(), "Uninitialized \"constant\" variable."); else if (!_variable.value()->annotation().isPure) m_errorReporter.typeError( + 8349_error, _variable.value()->location(), "Initial value for constant variable has to be compile-time constant." ); @@ -456,12 +467,12 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) else if (_variable.immutable()) { if (!_variable.type()->isValueType()) - m_errorReporter.typeError(_variable.location(), "Immutable variables cannot have a non-value type."); + m_errorReporter.typeError(6377_error, _variable.location(), "Immutable variables cannot have a non-value type."); if ( auto const* functionType = dynamic_cast(_variable.type()); functionType && functionType->kind() == FunctionType::Kind::External ) - m_errorReporter.typeError(_variable.location(), "Immutable variables of external function type are not yet supported."); + m_errorReporter.typeError(3366_error, _variable.location(), "Immutable variables of external function type are not yet supported."); solAssert(_variable.type()->sizeOnStack() == 1 || m_errorReporter.hasErrors(), ""); } @@ -469,7 +480,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) { if (varType->dataStoredIn(DataLocation::Memory) || varType->dataStoredIn(DataLocation::CallData)) if (!varType->canLiveOutsideStorage()) - m_errorReporter.typeError(_variable.location(), "Type " + varType->toString() + " is only valid in storage."); + m_errorReporter.typeError(4061_error, _variable.location(), "Type " + varType->toString() + " is only valid in storage."); } else if (_variable.visibility() >= Visibility::Public) { @@ -481,14 +492,15 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) if (!typeSupportedByOldABIEncoder(*param, false /* isLibrary */)) unsupportedTypes.emplace_back(param->toString()); if (!unsupportedTypes.empty()) - m_errorReporter.typeError(_variable.location(), + m_errorReporter.typeError( + 2763_error,_variable.location(), "The following types are only supported for getters in ABIEncoderV2: " + joinHumanReadable(unsupportedTypes) + ". Either remove \"public\" or use \"pragma experimental ABIEncoderV2;\" to enable the feature." ); } if (!getter.interfaceFunctionType()) - m_errorReporter.typeError(_variable.location(), "Internal or recursive type is not allowed for public state variables."); + m_errorReporter.typeError(6744_error, _variable.location(), "Internal or recursive type is not allowed for public state variables."); } if (auto referenceType = dynamic_cast(varType)) @@ -499,7 +511,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) if (!result) { solAssert(!result.message().empty(), "Expected detailed error message"); - m_errorReporter.typeError(_variable.location(), result.message()); + m_errorReporter.typeError(1534_error, _variable.location(), result.message()); } } @@ -536,12 +548,13 @@ void TypeChecker::visitManually( } if (!parameters) { - m_errorReporter.typeError(_modifier.location(), "Referenced declaration is neither modifier nor base class."); + m_errorReporter.typeError(4659_error, _modifier.location(), "Referenced declaration is neither modifier nor base class."); return; } if (parameters->size() != arguments.size()) { m_errorReporter.typeError( + 2973_error, _modifier.location(), "Wrong argument count for modifier invocation: " + toString(arguments.size()) + @@ -556,6 +569,7 @@ void TypeChecker::visitManually( BoolResult result = type(*arguments[i])->isImplicitlyConvertibleTo(*type(*(*parameters)[i])); if (!result) m_errorReporter.typeErrorConcatenateDescriptions( + 4649_error, arguments[i]->location(), "Invalid type for argument in modifier invocation. " "Invalid implicit conversion from " + @@ -577,23 +591,24 @@ bool TypeChecker::visit(EventDefinition const& _eventDef) if (var->isIndexed()) numIndexed++; if (!type(*var)->canLiveOutsideStorage()) - m_errorReporter.typeError(var->location(), "Type is required to live outside storage."); + m_errorReporter.typeError(3448_error, var->location(), "Type is required to live outside storage."); if (!type(*var)->interfaceType(false)) - m_errorReporter.typeError(var->location(), "Internal or recursive type is not allowed as event parameter type."); + m_errorReporter.typeError(3417_error, var->location(), "Internal or recursive type is not allowed as event parameter type."); if ( !_eventDef.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) && !typeSupportedByOldABIEncoder(*type(*var), false /* isLibrary */) ) m_errorReporter.typeError( + 3061_error, var->location(), "This type is only supported in ABIEncoderV2. " "Use \"pragma experimental ABIEncoderV2;\" to enable the feature." ); } if (_eventDef.isAnonymous() && numIndexed > 4) - m_errorReporter.typeError(_eventDef.location(), "More than 4 indexed arguments for anonymous event."); + m_errorReporter.typeError(8598_error, _eventDef.location(), "More than 4 indexed arguments for anonymous event."); else if (!_eventDef.isAnonymous() && numIndexed > 3) - m_errorReporter.typeError(_eventDef.location(), "More than 3 indexed arguments for event."); + m_errorReporter.typeError(7249_error, _eventDef.location(), "More than 3 indexed arguments for event."); return false; } @@ -606,7 +621,7 @@ void TypeChecker::endVisit(FunctionTypeName const& _funType) { solAssert(t->annotation().type, "Type not set for parameter."); if (!t->annotation().type->interfaceType(false).get()) - m_errorReporter.typeError(t->location(), "Internal type cannot be used for external function type."); + m_errorReporter.typeError(2582_error, t->location(), "Internal type cannot be used for external function type."); } solAssert(fun.interfaceType(false), "External function type uses internal types."); } @@ -633,7 +648,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) solAssert(var->type(), "Expected variable type!"); if (var->immutable()) { - m_errorReporter.typeError(_identifier.location, "Assembly access to immutable variables is not supported."); + m_errorReporter.typeError(3773_error, _identifier.location, "Assembly access to immutable variables is not supported."); return size_t(-1); } if (var->isConstant()) @@ -642,7 +657,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) if (var && !var->value()) { - m_errorReporter.typeError(_identifier.location, "Constant has no value."); + m_errorReporter.typeError(3224_error, _identifier.location, "Constant has no value."); return size_t(-1); } else if (!var || !type(*var)->isValueType() || ( @@ -650,17 +665,17 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) type(*var->value())->category() != Type::Category::RationalNumber )) { - m_errorReporter.typeError(_identifier.location, "Only direct number constants and references to such constants are supported by inline assembly."); + m_errorReporter.typeError(7615_error, _identifier.location, "Only direct number constants and references to such constants are supported by inline assembly."); return size_t(-1); } else if (_context == yul::IdentifierContext::LValue) { - m_errorReporter.typeError(_identifier.location, "Constant variables cannot be assigned to."); + m_errorReporter.typeError(6252_error, _identifier.location, "Constant variables cannot be assigned to."); return size_t(-1); } else if (requiresStorage) { - m_errorReporter.typeError(_identifier.location, "The suffixes _offset and _slot can only be used on non-constant storage variables."); + m_errorReporter.typeError(6617_error, _identifier.location, "The suffixes _offset and _slot can only be used on non-constant storage variables."); return size_t(-1); } } @@ -669,19 +684,19 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) { if (!var->isStateVariable() && !var->type()->dataStoredIn(DataLocation::Storage)) { - m_errorReporter.typeError(_identifier.location, "The suffixes _offset and _slot can only be used on storage variables."); + m_errorReporter.typeError(3622_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables."); return size_t(-1); } else if (_context == yul::IdentifierContext::LValue) { if (var->isStateVariable()) { - m_errorReporter.typeError(_identifier.location, "State variables cannot be assigned to - you have to use \"sstore()\"."); + m_errorReporter.typeError(4713_error, _identifier.location, "State variables cannot be assigned to - you have to use \"sstore()\"."); return size_t(-1); } else if (ref->second.isOffset) { - m_errorReporter.typeError(_identifier.location, "Only _slot can be assigned to."); + m_errorReporter.typeError(9739_error, _identifier.location, "Only _slot can be assigned to."); return size_t(-1); } else @@ -690,26 +705,26 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) } else if (!var->isConstant() && var->isStateVariable()) { - m_errorReporter.typeError(_identifier.location, "Only local variables are supported. To access storage variables, use the _slot and _offset suffixes."); + m_errorReporter.typeError(1408_error, _identifier.location, "Only local variables are supported. To access storage variables, use the _slot and _offset suffixes."); return size_t(-1); } else if (var->type()->dataStoredIn(DataLocation::Storage)) { - m_errorReporter.typeError(_identifier.location, "You have to use the _slot or _offset suffix to access storage reference variables."); + m_errorReporter.typeError(9068_error, _identifier.location, "You have to use the _slot or _offset suffix to access storage reference variables."); return size_t(-1); } else if (var->type()->sizeOnStack() != 1) { if (var->type()->dataStoredIn(DataLocation::CallData)) - m_errorReporter.typeError(_identifier.location, "Call data elements cannot be accessed directly. Copy to a local variable first or use \"calldataload\" or \"calldatacopy\" with manually determined offsets and sizes."); + m_errorReporter.typeError(2370_error, _identifier.location, "Call data elements cannot be accessed directly. Copy to a local variable first or use \"calldataload\" or \"calldatacopy\" with manually determined offsets and sizes."); else - m_errorReporter.typeError(_identifier.location, "Only types that use one stack slot are supported."); + m_errorReporter.typeError(9857_error, _identifier.location, "Only types that use one stack slot are supported."); return size_t(-1); } } else if (requiresStorage) { - m_errorReporter.typeError(_identifier.location, "The suffixes _offset and _slot can only be used on storage variables."); + m_errorReporter.typeError(7944_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables."); return size_t(-1); } else if (_context == yul::IdentifierContext::LValue) @@ -717,7 +732,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) if (dynamic_cast(declaration)) return size_t(-1); - m_errorReporter.typeError(_identifier.location, "Only local variables can be assigned to in inline assembly."); + m_errorReporter.typeError(1990_error, _identifier.location, "Only local variables can be assigned to in inline assembly."); return size_t(-1); } @@ -726,7 +741,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) solAssert(!!declaration->type(), "Type of declaration required but not yet determined."); if (dynamic_cast(declaration)) { - m_errorReporter.declarationError(_identifier.location, "Access to functions is not allowed in inline assembly."); + m_errorReporter.declarationError(2025_error, _identifier.location, "Access to functions is not allowed in inline assembly."); return size_t(-1); } else if (dynamic_cast(declaration)) @@ -736,7 +751,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) { if (!contract->isLibrary()) { - m_errorReporter.typeError(_identifier.location, "Expected a library."); + m_errorReporter.typeError(4977_error, _identifier.location, "Expected a library."); return size_t(-1); } } @@ -774,6 +789,7 @@ void TypeChecker::endVisit(TryStatement const& _tryStatement) if (!externalCall || externalCall->annotation().kind != FunctionCallKind::FunctionCall) { m_errorReporter.typeError( + 5347_error, _tryStatement.externalCall().location(), "Try can only be used with external function calls and contract creation calls." ); @@ -788,6 +804,7 @@ void TypeChecker::endVisit(TryStatement const& _tryStatement) ) { m_errorReporter.typeError( + 2536_error, _tryStatement.externalCall().location(), "Try can only be used with external function calls and contract creation calls." ); @@ -810,6 +827,7 @@ void TypeChecker::endVisit(TryStatement const& _tryStatement) successClause.parameters()->parameters(); if (returnTypes.size() != parameters.size()) m_errorReporter.typeError( + 2800_error, successClause.location(), "Function returns " + to_string(functionType.returnParameterTypes().size()) + @@ -823,6 +841,7 @@ void TypeChecker::endVisit(TryStatement const& _tryStatement) solAssert(returnTypes[i], ""); if (parameters[i] && *parameters[i]->annotation().type != *returnTypes[i]) m_errorReporter.typeError( + 6509_error, parameters[i]->location(), "Invalid type, expected " + returnTypes[i]->toString(false) + @@ -842,6 +861,7 @@ void TypeChecker::endVisit(TryStatement const& _tryStatement) { if (lowLevelClause) m_errorReporter.typeError( + 5320_error, clause.location(), SecondarySourceLocation{}.append("The first clause is here:", lowLevelClause->location()), "This try statement already has a low-level catch clause." @@ -853,9 +873,10 @@ void TypeChecker::endVisit(TryStatement const& _tryStatement) clause.parameters()->parameters().size() != 1 || *clause.parameters()->parameters().front()->type() != *TypeProvider::bytesMemory() ) - m_errorReporter.typeError(clause.location(), "Expected `catch (bytes memory ...) { ... }` or `catch { ... }`."); + m_errorReporter.typeError(6231_error, clause.location(), "Expected `catch (bytes memory ...) { ... }` or `catch { ... }`."); if (!m_evmVersion.supportsReturndata()) m_errorReporter.typeError( + 9908_error, clause.location(), "This catch clause type cannot be used on the selected EVM version (" + m_evmVersion.name() + @@ -867,6 +888,7 @@ void TypeChecker::endVisit(TryStatement const& _tryStatement) { if (!m_evmVersion.supportsReturndata()) m_errorReporter.typeError( + 1812_error, clause.location(), "This catch clause type cannot be used on the selected EVM version (" + m_evmVersion.name() + @@ -875,6 +897,7 @@ void TypeChecker::endVisit(TryStatement const& _tryStatement) if (errorClause) m_errorReporter.typeError( + 1036_error, clause.location(), SecondarySourceLocation{}.append("The first clause is here:", errorClause->location()), "This try statement already has an \"Error\" catch clause." @@ -885,10 +908,11 @@ void TypeChecker::endVisit(TryStatement const& _tryStatement) clause.parameters()->parameters().size() != 1 || *clause.parameters()->parameters().front()->type() != *TypeProvider::stringMemory() ) - m_errorReporter.typeError(clause.location(), "Expected `catch Error(string memory ...) { ... }`."); + m_errorReporter.typeError(2943_error, clause.location(), "Expected `catch Error(string memory ...) { ... }`."); } else m_errorReporter.typeError( + 3542_error, clause.location(), "Invalid catch clause name. Expected either `catch (...)` or `catch Error(...)`." ); @@ -920,12 +944,12 @@ void TypeChecker::endVisit(Return const& _return) if (!_return.expression()) { if (params && !params->parameters().empty()) - m_errorReporter.typeError(_return.location(), "Return arguments required."); + m_errorReporter.typeError(6777_error, _return.location(), "Return arguments required."); return; } if (!params) { - m_errorReporter.typeError(_return.location(), "Return arguments not allowed."); + m_errorReporter.typeError(7552_error, _return.location(), "Return arguments not allowed."); return; } TypePointers returnTypes; @@ -934,12 +958,13 @@ void TypeChecker::endVisit(Return const& _return) if (auto tupleType = dynamic_cast(type(*_return.expression()))) { if (tupleType->components().size() != params->parameters().size()) - m_errorReporter.typeError(_return.location(), "Different number of arguments in return statement than in returns declaration."); + m_errorReporter.typeError(5132_error, _return.location(), "Different number of arguments in return statement than in returns declaration."); else { BoolResult result = tupleType->isImplicitlyConvertibleTo(TupleType(returnTypes)); if (!result) m_errorReporter.typeErrorConcatenateDescriptions( + 5992_error, _return.expression()->location(), "Return argument type " + type(*_return.expression())->toString() + @@ -950,13 +975,14 @@ void TypeChecker::endVisit(Return const& _return) } } else if (params->parameters().size() != 1) - m_errorReporter.typeError(_return.location(), "Different number of arguments in return statement than in returns declaration."); + m_errorReporter.typeError(8863_error, _return.location(), "Different number of arguments in return statement than in returns declaration."); else { TypePointer const& expected = type(*params->parameters().front()); BoolResult result = type(*_return.expression())->isImplicitlyConvertibleTo(*expected); if (!result) m_errorReporter.typeErrorConcatenateDescriptions( + 6359_error, _return.expression()->location(), "Return argument type " + type(*_return.expression())->toString() + @@ -974,7 +1000,7 @@ void TypeChecker::endVisit(EmitStatement const& _emit) type(_emit.eventCall().expression())->category() != Type::Category::Function || dynamic_cast(*type(_emit.eventCall().expression())).kind() != FunctionType::Kind::Event ) - m_errorReporter.typeError(_emit.eventCall().expression().location(), "Expression has to be an event invocation."); + m_errorReporter.typeError(9292_error, _emit.eventCall().expression().location(), "Expression has to be an event invocation."); } namespace @@ -1042,15 +1068,16 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) } else // Bailing out *fatal* here, as those (untyped) vars may be used later, and diagnostics wouldn't be helpful then. - m_errorReporter.fatalTypeError(_statement.location(), "Use of the \"var\" keyword is disallowed."); + m_errorReporter.fatalTypeError(4626_error, _statement.location(), "Use of the \"var\" keyword is disallowed."); } VariableDeclaration const& varDecl = *_statement.declarations().front(); if (!varDecl.annotation().type) - m_errorReporter.fatalTypeError(_statement.location(), "Use of the \"var\" keyword is disallowed."); + m_errorReporter.fatalTypeError(6983_error, _statement.location(), "Use of the \"var\" keyword is disallowed."); if (dynamic_cast(type(varDecl))) m_errorReporter.typeError( + 4182_error, varDecl.location(), "Uninitialized mapping. Mappings cannot be created dynamically, you have to assign them from a state variable." ); @@ -1074,6 +1101,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) solAssert(m_errorReporter.hasErrors(), ""); else if (valueTypes.size() != variables.size()) m_errorReporter.typeError( + 7364_error, _statement.location(), "Different number of components on the left hand side (" + toString(variables.size()) + @@ -1103,6 +1131,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) { if (valueComponentType->category() == Type::Category::RationalNumber) m_errorReporter.fatalTypeError( + 6963_error, _statement.initialValue()->location(), "Invalid rational " + valueComponentType->toString() + @@ -1158,11 +1187,13 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) { if (var.annotation().type->operator==(*valueComponentType->mobileType())) m_errorReporter.typeError( + 5107_error, _statement.location(), errorMsg + ", but it can be explicitly converted." ); else m_errorReporter.typeError( + 4486_error, _statement.location(), errorMsg + ". Try converting to type " + @@ -1172,6 +1203,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) } else m_errorReporter.typeErrorConcatenateDescriptions( + 9574_error, _statement.location(), errorMsg + ".", result.message() @@ -1192,12 +1224,14 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) { if (!typeCanBeExpressed(variables)) m_errorReporter.syntaxError( + 3478_error, _statement.location(), "Use of the \"var\" keyword is disallowed. " "Type cannot be expressed in syntax." ); else m_errorReporter.syntaxError( + 1719_error, _statement.location(), "Use of the \"var\" keyword is disallowed. " "Use explicit declaration `" + createTupleDecl(variables) + " = ...´ instead." @@ -1211,7 +1245,7 @@ void TypeChecker::endVisit(ExpressionStatement const& _statement) { if (type(_statement.expression())->category() == Type::Category::RationalNumber) if (!dynamic_cast(*type(_statement.expression())).mobileType()) - m_errorReporter.typeError(_statement.expression().location(), "Invalid rational number."); + m_errorReporter.typeError(3757_error, _statement.expression().location(), "Invalid rational number."); if (auto call = dynamic_cast(&_statement.expression())) { @@ -1224,9 +1258,9 @@ void TypeChecker::endVisit(ExpressionStatement const& _statement) kind == FunctionType::Kind::BareDelegateCall || kind == FunctionType::Kind::BareStaticCall ) - m_errorReporter.warning(_statement.location(), "Return value of low-level calls not used."); + m_errorReporter.warning(9302_error, _statement.location(), "Return value of low-level calls not used."); else if (kind == FunctionType::Kind::Send) - m_errorReporter.warning(_statement.location(), "Failure condition of 'send' ignored. Consider using 'transfer' instead."); + m_errorReporter.warning(5878_error, _statement.location(), "Failure condition of 'send' ignored. Consider using 'transfer' instead."); } } } @@ -1244,12 +1278,12 @@ bool TypeChecker::visit(Conditional const& _conditional) TypePointer commonType = nullptr; if (!trueType) - m_errorReporter.typeError(_conditional.trueExpression().location(), "Invalid mobile type in true expression."); + m_errorReporter.typeError(9717_error, _conditional.trueExpression().location(), "Invalid mobile type in true expression."); else commonType = trueType; if (!falseType) - m_errorReporter.typeError(_conditional.falseExpression().location(), "Invalid mobile type in false expression."); + m_errorReporter.typeError(3703_error, _conditional.falseExpression().location(), "Invalid mobile type in false expression."); else commonType = falseType; @@ -1262,6 +1296,7 @@ bool TypeChecker::visit(Conditional const& _conditional) if (!commonType) { m_errorReporter.typeError( + 1080_error, _conditional.location(), "True expression's type " + trueType->toString() + @@ -1283,6 +1318,7 @@ bool TypeChecker::visit(Conditional const& _conditional) if (_conditional.annotation().willBeWrittenTo) m_errorReporter.typeError( + 2212_error, _conditional.location(), "Conditional expression as left value is not supported yet." ); @@ -1295,7 +1331,7 @@ void TypeChecker::checkExpressionAssignment(Type const& _type, Expression const& if (auto const* tupleExpression = dynamic_cast(&_expression)) { if (tupleExpression->components().empty()) - m_errorReporter.typeError(_expression.location(), "Empty tuple on the left hand side."); + m_errorReporter.typeError(5547_error, _expression.location(), "Empty tuple on the left hand side."); auto const* tupleType = dynamic_cast(&_type); auto const& types = tupleType && tupleExpression->components().size() != 1 ? tupleType->components() : vector { &_type }; @@ -1320,7 +1356,7 @@ void TypeChecker::checkExpressionAssignment(Type const& _type, Expression const& if (variableDeclaration->isLocalOrReturn()) isLocalOrReturn = true; if (!isLocalOrReturn) - m_errorReporter.typeError(_expression.location(), "Mappings cannot be assigned to."); + m_errorReporter.typeError(9214_error, _expression.location(), "Mappings cannot be assigned to."); } } @@ -1339,6 +1375,7 @@ bool TypeChecker::visit(Assignment const& _assignment) { if (_assignment.assignmentOperator() != Token::Assign) m_errorReporter.typeError( + 4289_error, _assignment.location(), "Compound assignment is not allowed for tuple types." ); @@ -1363,6 +1400,7 @@ bool TypeChecker::visit(Assignment const& _assignment) ); if (!resultType || *resultType != *t) m_errorReporter.typeError( + 7366_error, _assignment.location(), "Operator " + string(TokenTraits::toString(_assignment.assignmentOperator())) + @@ -1383,7 +1421,7 @@ bool TypeChecker::visit(TupleExpression const& _tuple) if (_tuple.annotation().willBeWrittenTo) { if (_tuple.isInlineArray()) - m_errorReporter.fatalTypeError(_tuple.location(), "Inline array type cannot be declared as LValue."); + m_errorReporter.fatalTypeError(3025_error, _tuple.location(), "Inline array type cannot be declared as LValue."); for (auto const& component: components) if (component) { @@ -1410,7 +1448,7 @@ bool TypeChecker::visit(TupleExpression const& _tuple) for (size_t i = 0; i < components.size(); ++i) { if (!components[i]) - m_errorReporter.fatalTypeError(_tuple.location(), "Tuple component cannot be empty."); + m_errorReporter.fatalTypeError(8381_error, _tuple.location(), "Tuple component cannot be empty."); components[i]->accept(*this); types.push_back(type(*components[i])); @@ -1419,21 +1457,21 @@ bool TypeChecker::visit(TupleExpression const& _tuple) if (dynamic_cast(*types[i]).components().empty()) { if (_tuple.isInlineArray()) - m_errorReporter.fatalTypeError(components[i]->location(), "Array component cannot be empty."); - m_errorReporter.typeError(components[i]->location(), "Tuple component cannot be empty."); + m_errorReporter.fatalTypeError(5604_error, components[i]->location(), "Array component cannot be empty."); + m_errorReporter.typeError(6473_error, components[i]->location(), "Tuple component cannot be empty."); } // Note: code generation will visit each of the expression even if they are not assigned from. if (types[i]->category() == Type::Category::RationalNumber && components.size() > 1) if (!dynamic_cast(*types[i]).mobileType()) - m_errorReporter.fatalTypeError(components[i]->location(), "Invalid rational number."); + m_errorReporter.fatalTypeError(3390_error, components[i]->location(), "Invalid rational number."); if (_tuple.isInlineArray()) { solAssert(!!types[i], "Inline array cannot have empty components"); if ((i == 0 || inlineArrayType) && !types[i]->mobileType()) - m_errorReporter.fatalTypeError(components[i]->location(), "Invalid mobile type."); + m_errorReporter.fatalTypeError(9563_error, components[i]->location(), "Invalid mobile type."); if (i == 0) inlineArrayType = types[i]->mobileType(); @@ -1447,9 +1485,9 @@ bool TypeChecker::visit(TupleExpression const& _tuple) if (_tuple.isInlineArray()) { if (!inlineArrayType) - m_errorReporter.fatalTypeError(_tuple.location(), "Unable to deduce common type for array elements."); + m_errorReporter.fatalTypeError(6378_error, _tuple.location(), "Unable to deduce common type for array elements."); else if (!inlineArrayType->canLiveOutsideStorage()) - m_errorReporter.fatalTypeError(_tuple.location(), "Type " + inlineArrayType->toString() + " is only valid in storage."); + m_errorReporter.fatalTypeError(1545_error, _tuple.location(), "Type " + inlineArrayType->toString() + " is only valid in storage."); _tuple.annotation().type = TypeProvider::array(DataLocation::Memory, inlineArrayType, types.size()); } @@ -1482,9 +1520,9 @@ bool TypeChecker::visit(UnaryOperation const& _operation) if (modifying) // Cannot just report the error, ignore the unary operator, and continue, // because the sub-expression was already processed with requireLValue() - m_errorReporter.fatalTypeError(_operation.location(), description); + m_errorReporter.fatalTypeError(9767_error, _operation.location(), description); else - m_errorReporter.typeError(_operation.location(), description); + m_errorReporter.typeError(4907_error, _operation.location(), description); t = subExprType; } _operation.annotation().type = t; @@ -1501,6 +1539,7 @@ void TypeChecker::endVisit(BinaryOperation const& _operation) if (!commonType) { m_errorReporter.typeError( + 2271_error, _operation.location(), "Operator " + string(TokenTraits::toString(_operation.getOperator())) + @@ -1536,6 +1575,7 @@ void TypeChecker::endVisit(BinaryOperation const& _operation) dynamic_cast(*commonType).numBits() != 256 )) m_errorReporter.warning( + 9085_error, _operation.location(), "Result of " + operation + " has type " + commonType->toString() + " and thus " "might overflow. Silence this warning by converting the literal to the " @@ -1548,6 +1588,7 @@ void TypeChecker::endVisit(BinaryOperation const& _operation) dynamic_cast(*rightType).numBits() ) m_errorReporter.warning( + 3149_error, _operation.location(), "The result type of the " + operation + @@ -1574,11 +1615,13 @@ TypePointer TypeChecker::typeCheckTypeConversionAndRetrieveReturnType( TypePointer resultType = dynamic_cast(*expressionType).actualType(); if (arguments.size() != 1) m_errorReporter.typeError( + 2558_error, _functionCall.location(), "Exactly one argument expected for explicit type conversion." ); else if (!isPositionalCall) m_errorReporter.typeError( + 5153_error, _functionCall.location(), "Type conversion cannot allow named arguments." ); @@ -1639,6 +1682,7 @@ TypePointer TypeChecker::typeCheckTypeConversionAndRetrieveReturnType( variableDeclaration->location() ); m_errorReporter.typeError( + 7398_error, _functionCall.location(), ssl, "Explicit type conversion not allowed from non-payable \"address\" to \"" + @@ -1653,6 +1697,7 @@ TypePointer TypeChecker::typeCheckTypeConversionAndRetrieveReturnType( resultType->category() == Type::Category::Address ) m_errorReporter.typeError( + 5030_error, _functionCall.location(), "Explicit type conversion not allowed from \"" + argType->toString() + @@ -1663,6 +1708,7 @@ TypePointer TypeChecker::typeCheckTypeConversionAndRetrieveReturnType( ); else m_errorReporter.typeError( + 9640_error, _functionCall.location(), "Explicit type conversion not allowed from \"" + argType->toString() + @@ -1700,11 +1746,13 @@ void TypeChecker::typeCheckFunctionCall( !dynamic_cast(_functionType->declaration()).isImplemented() ) m_errorReporter.typeError( + 7501_error, _functionCall.location(), "Cannot call unimplemented base function." ); else m_errorReporter.typeError( + 3419_error, _functionCall.location(), "Cannot call function via contract type name." ); @@ -1717,6 +1765,7 @@ void TypeChecker::typeCheckFunctionCall( !m_evmVersion.hasStaticCall() ) m_errorReporter.typeError( + 5052_error, _functionCall.location(), "\"staticcall\" is not supported by the VM version." ); @@ -1730,25 +1779,26 @@ void TypeChecker::typeCheckFallbackFunction(FunctionDefinition const& _function) solAssert(_function.isFallback(), ""); if (_function.inContractKind() == ContractKind::Library) - m_errorReporter.typeError(_function.location(), "Libraries cannot have fallback functions."); + m_errorReporter.typeError(5982_error, _function.location(), "Libraries cannot have fallback functions."); if (_function.stateMutability() != StateMutability::NonPayable && _function.stateMutability() != StateMutability::Payable) m_errorReporter.typeError( + 4575_error, _function.location(), "Fallback function must be payable or non-payable, but is \"" + stateMutabilityToString(_function.stateMutability()) + "\"." ); if (_function.visibility() != Visibility::External) - m_errorReporter.typeError(_function.location(), "Fallback function must be defined as \"external\"."); + m_errorReporter.typeError(1159_error, _function.location(), "Fallback function must be defined as \"external\"."); if (!_function.returnParameters().empty()) { if (_function.returnParameters().size() > 1 || *type(*_function.returnParameters().front()) != *TypeProvider::bytesMemory()) - m_errorReporter.typeError(_function.returnParameterList()->location(), "Fallback function can only have a single \"bytes memory\" return value."); + m_errorReporter.typeError(5570_error, _function.returnParameterList()->location(), "Fallback function can only have a single \"bytes memory\" return value."); else - m_errorReporter.typeError(_function.returnParameterList()->location(), "Return values for fallback functions are not yet implemented."); + m_errorReporter.typeError(6151_error, _function.returnParameterList()->location(), "Return values for fallback functions are not yet implemented."); } if (!_function.parameters().empty()) - m_errorReporter.typeError(_function.parameterList().location(), "Fallback function cannot take parameters."); + m_errorReporter.typeError(3978_error, _function.parameterList().location(), "Fallback function cannot take parameters."); } void TypeChecker::typeCheckReceiveFunction(FunctionDefinition const& _function) @@ -1756,21 +1806,22 @@ void TypeChecker::typeCheckReceiveFunction(FunctionDefinition const& _function) solAssert(_function.isReceive(), ""); if (_function.inContractKind() == ContractKind::Library) - m_errorReporter.typeError(_function.location(), "Libraries cannot have receive ether functions."); + m_errorReporter.typeError(4549_error, _function.location(), "Libraries cannot have receive ether functions."); if (_function.stateMutability() != StateMutability::Payable) m_errorReporter.typeError( + 7793_error, _function.location(), "Receive ether function must be payable, but is \"" + stateMutabilityToString(_function.stateMutability()) + "\"." ); if (_function.visibility() != Visibility::External) - m_errorReporter.typeError(_function.location(), "Receive ether function must be defined as \"external\"."); + m_errorReporter.typeError(4095_error, _function.location(), "Receive ether function must be defined as \"external\"."); if (!_function.returnParameters().empty()) - m_errorReporter.typeError(_function.returnParameterList()->location(), "Receive ether function cannot return values."); + m_errorReporter.typeError(6899_error, _function.returnParameterList()->location(), "Receive ether function cannot return values."); if (!_function.parameters().empty()) - m_errorReporter.typeError(_function.parameterList().location(), "Receive ether function cannot take parameters."); + m_errorReporter.typeError(6857_error, _function.parameterList().location(), "Receive ether function cannot take parameters."); } @@ -1778,20 +1829,21 @@ void TypeChecker::typeCheckConstructor(FunctionDefinition const& _function) { solAssert(_function.isConstructor(), ""); if (_function.markedVirtual()) - m_errorReporter.typeError(_function.location(), "Constructors cannot be virtual."); + m_errorReporter.typeError(7001_error, _function.location(), "Constructors cannot be virtual."); if (_function.overrides()) - m_errorReporter.typeError(_function.location(), "Constructors cannot override."); + m_errorReporter.typeError(1209_error, _function.location(), "Constructors cannot override."); if (!_function.returnParameters().empty()) - m_errorReporter.typeError(_function.returnParameterList()->location(), "Non-empty \"returns\" directive for constructor."); + m_errorReporter.typeError(9712_error, _function.returnParameterList()->location(), "Non-empty \"returns\" directive for constructor."); if (_function.stateMutability() != StateMutability::NonPayable && _function.stateMutability() != StateMutability::Payable) m_errorReporter.typeError( + 1558_error, _function.location(), "Constructor must be payable or non-payable, but is \"" + stateMutabilityToString(_function.stateMutability()) + "\"." ); if (_function.visibility() != Visibility::Public && _function.visibility() != Visibility::Internal) - m_errorReporter.typeError(_function.location(), "Constructor must be public or internal."); + m_errorReporter.typeError(9239_error, _function.location(), "Constructor must be public or internal."); } void TypeChecker::typeCheckABIEncodeFunctions( @@ -1820,6 +1872,7 @@ void TypeChecker::typeCheckABIEncodeFunctions( if (!_functionCall.names().empty()) { m_errorReporter.typeError( + 2627_error, _functionCall.location(), "Named arguments cannot be used for functions that take arbitrary parameters." ); @@ -1841,6 +1894,7 @@ void TypeChecker::typeCheckABIEncodeFunctions( if (rationalType.isFractional()) { m_errorReporter.typeError( + 6090_error, arguments[i]->location(), "Fractional numbers cannot yet be encoded." ); @@ -1849,6 +1903,7 @@ void TypeChecker::typeCheckABIEncodeFunctions( else if (!argType->mobileType()) { m_errorReporter.typeError( + 8009_error, arguments[i]->location(), "Invalid rational number (too large or division by zero)." ); @@ -1857,6 +1912,7 @@ void TypeChecker::typeCheckABIEncodeFunctions( else if (isPacked) { m_errorReporter.typeError( + 7279_error, arguments[i]->location(), "Cannot perform packed encoding for a literal." " Please convert it to an explicit type first." @@ -1868,6 +1924,7 @@ void TypeChecker::typeCheckABIEncodeFunctions( if (isPacked && !typeSupportedByOldABIEncoder(*argType, false /* isLibrary */)) { m_errorReporter.typeError( + 9578_error, arguments[i]->location(), "Type not supported in packed mode." ); @@ -1876,6 +1933,7 @@ void TypeChecker::typeCheckABIEncodeFunctions( if (!argType->fullEncodingType(false, abiEncoderV2, !_functionType->padArguments())) m_errorReporter.typeError( + 2056_error, arguments[i]->location(), "This type cannot be encoded." ); @@ -1977,7 +2035,7 @@ void TypeChecker::typeCheckFunctionGeneralChecks( " This function requires a single bytes argument." " Use abi.encodePacked(...) to obtain the pre-0.5.0" " behaviour or abi.encode(...) to use ABI encoding."; - m_errorReporter.typeError(_functionCall.location(), msg); + m_errorReporter.typeError(1093_error, _functionCall.location(), msg); return; } @@ -2006,6 +2064,7 @@ void TypeChecker::typeCheckFunctionGeneralChecks( { duplication = true; m_errorReporter.typeError( + 6995_error, arguments[i]->location(), "Duplicate named argument \"" + *argumentNames[i] + "\"." ); @@ -2032,6 +2091,7 @@ void TypeChecker::typeCheckFunctionGeneralChecks( paramArgMap[i] = nullptr; not_all_mapped = true; m_errorReporter.typeError( + 4974_error, _functionCall.location(), "Named argument \"" + *argumentNames[i] + @@ -2077,7 +2137,7 @@ void TypeChecker::typeCheckFunctionGeneralChecks( " This function requires a single bytes argument." " Use abi.encodePacked(...) to obtain the pre-0.5.0" " behaviour or abi.encode(...) to use ABI encoding."; - m_errorReporter.typeError(paramArgMap[i]->location(), msg); + m_errorReporter.typeError(6706_error, paramArgMap[i]->location(), msg); } } } @@ -2159,7 +2219,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) } default: - m_errorReporter.fatalTypeError(_functionCall.location(), "Type is not callable"); + m_errorReporter.fatalTypeError(5704_error, _functionCall.location(), "Type is not callable"); funcCallAnno.kind = FunctionCallKind::Unset; funcCallAnno.isPure = argumentsArePure; break; @@ -2238,7 +2298,7 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions) auto expressionFunctionType = dynamic_cast(type(_functionCallOptions.expression())); if (!expressionFunctionType) { - m_errorReporter.fatalTypeError(_functionCallOptions.location(), "Expected callable expression before call options."); + m_errorReporter.fatalTypeError(2622_error, _functionCallOptions.location(), "Expected callable expression before call options."); return false; } @@ -2257,6 +2317,7 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions) ) { m_errorReporter.fatalTypeError( + 2193_error, _functionCallOptions.location(), "Function call options can only be set on external function calls or contract creations." ); @@ -2267,6 +2328,7 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions) { if (_option || _alreadySet) m_errorReporter.typeError( + 9886_error, _functionCallOptions.location(), _alreadySet ? "Option \"" + std::move(_name) + "\" has already been set." : @@ -2288,6 +2350,7 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions) } else m_errorReporter.typeError( + 2721_error, _functionCallOptions.location(), "Function call option \"salt\" can only be used with \"new\"." ); @@ -2296,16 +2359,19 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions) { if (kind == FunctionType::Kind::BareDelegateCall) m_errorReporter.typeError( + 6189_error, _functionCallOptions.location(), "Cannot set option \"value\" for delegatecall." ); else if (kind == FunctionType::Kind::BareStaticCall) m_errorReporter.typeError( + 2842_error, _functionCallOptions.location(), "Cannot set option \"value\" for staticcall." ); else if (!expressionFunctionType->isPayable()) m_errorReporter.typeError( + 7006_error, _functionCallOptions.location(), kind == FunctionType::Kind::Creation ? "Cannot set option \"value\", since the constructor of " + @@ -2324,6 +2390,7 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions) { if (kind == FunctionType::Kind::Creation) m_errorReporter.typeError( + 9903_error, _functionCallOptions.location(), "Function call option \"gas\" cannot be used with \"new\"." ); @@ -2336,6 +2403,7 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions) } else m_errorReporter.typeError( + 9318_error, _functionCallOptions.location(), "Unknown call option \"" + name + "\". Valid options are \"salt\", \"value\" and \"gas\"." ); @@ -2343,6 +2411,7 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions) if (setSalt && !m_evmVersion.hasCreate2()) m_errorReporter.typeError( + 5189_error, _functionCallOptions.location(), "Unsupported call option \"salt\" (requires Constantinople-compatible VMs)." ); @@ -2361,13 +2430,13 @@ void TypeChecker::endVisit(NewExpression const& _newExpression) auto contract = dynamic_cast(&dereference(*contractName)); if (!contract) - m_errorReporter.fatalTypeError(_newExpression.location(), "Identifier is not a contract."); + m_errorReporter.fatalTypeError(5540_error, _newExpression.location(), "Identifier is not a contract."); if (contract->isInterface()) - m_errorReporter.fatalTypeError(_newExpression.location(), "Cannot instantiate an interface."); + m_errorReporter.fatalTypeError(2971_error, _newExpression.location(), "Cannot instantiate an interface."); if (!contract->constructorIsPublic()) - m_errorReporter.typeError(_newExpression.location(), "Contract with internal constructor cannot be created directly."); + m_errorReporter.typeError(9054_error, _newExpression.location(), "Contract with internal constructor cannot be created directly."); if (contract->abstract()) - m_errorReporter.typeError(_newExpression.location(), "Cannot instantiate an abstract contract."); + m_errorReporter.typeError(4614_error, _newExpression.location(), "Cannot instantiate an abstract contract."); solAssert(!!m_scope, ""); m_scope->annotation().contractDependencies.insert(contract); @@ -2377,6 +2446,7 @@ void TypeChecker::endVisit(NewExpression const& _newExpression) ); if (contractDependenciesAreCyclic(*m_scope)) m_errorReporter.typeError( + 4579_error, _newExpression.location(), "Circular reference for contract creation (cannot create instance of derived or same contract)." ); @@ -2387,11 +2457,13 @@ void TypeChecker::endVisit(NewExpression const& _newExpression) { if (!type->canLiveOutsideStorage()) m_errorReporter.fatalTypeError( + 1164_error, _newExpression.typeName().location(), "Type cannot live outside storage." ); if (!type->isDynamicallySized()) m_errorReporter.typeError( + 3904_error, _newExpression.typeName().location(), "Length has to be placed in parentheses after the array type for new expression." ); @@ -2408,7 +2480,7 @@ void TypeChecker::endVisit(NewExpression const& _newExpression) _newExpression.annotation().isPure = true; } else - m_errorReporter.fatalTypeError(_newExpression.location(), "Contract or array type expected."); + m_errorReporter.fatalTypeError(8807_error, _newExpression.location(), "Contract or array type expected."); } bool TypeChecker::visit(MemberAccess const& _memberAccess) @@ -2447,6 +2519,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) ); if (!storageType->members(m_scope).membersByName(memberName).empty()) m_errorReporter.fatalTypeError( + 4994_error, _memberAccess.location(), "Member \"" + memberName + "\" is not available in " + exprType->toString() + @@ -2505,12 +2578,14 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) } m_errorReporter.fatalTypeError( + 4035_error, _memberAccess.location(), errorMsg ); } else if (possibleMembers.size() > 1) m_errorReporter.fatalTypeError( + 6675_error, _memberAccess.location(), "Member \"" + memberName + "\" not unique " "after argument-dependent lookup in " + exprType->toString() + @@ -2534,6 +2609,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) (memberName == "value" || memberName == "gas") ) m_errorReporter.warning( + 1621_error, _memberAccess.location(), "Using \"." + memberName + "(...)\" is deprecated. Use \"{" + memberName + ": ...}\" instead." ); @@ -2592,6 +2668,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) ); if (contractDependenciesAreCyclic(*m_scope)) m_errorReporter.typeError( + 4224_error, _memberAccess.location(), "Circular reference for contract code access." ); @@ -2619,7 +2696,7 @@ bool TypeChecker::visit(IndexAccess const& _access) { auto const& arrayType = dynamic_cast(*baseType).arrayType(); if (arrayType.location() != DataLocation::CallData || !arrayType.isDynamicallySized()) - m_errorReporter.typeError(_access.location(), "Index access is only implemented for slices of dynamic calldata arrays."); + m_errorReporter.typeError(4802_error, _access.location(), "Index access is only implemented for slices of dynamic calldata arrays."); baseType = &arrayType; [[fallthrough]]; } @@ -2627,10 +2704,10 @@ bool TypeChecker::visit(IndexAccess const& _access) { ArrayType const& actualType = dynamic_cast(*baseType); if (!index) - m_errorReporter.typeError(_access.location(), "Index expression cannot be omitted."); + m_errorReporter.typeError(9689_error, _access.location(), "Index expression cannot be omitted."); else if (actualType.isString()) { - m_errorReporter.typeError(_access.location(), "Index access for string is not possible."); + m_errorReporter.typeError(9961_error, _access.location(), "Index access for string is not possible."); index->accept(*this); } else @@ -2641,7 +2718,7 @@ bool TypeChecker::visit(IndexAccess const& _access) { solAssert(!numberType->isFractional(), ""); if (!actualType.isDynamicallySized() && actualType.length() <= numberType->literalValue(nullptr)) - m_errorReporter.typeError(_access.location(), "Out of bounds array access."); + m_errorReporter.typeError(3383_error, _access.location(), "Out of bounds array access."); } } resultType = actualType.baseType(); @@ -2652,7 +2729,7 @@ bool TypeChecker::visit(IndexAccess const& _access) { MappingType const& actualType = dynamic_cast(*baseType); if (!index) - m_errorReporter.typeError(_access.location(), "Index expression cannot be omitted."); + m_errorReporter.typeError(1267_error, _access.location(), "Index expression cannot be omitted."); else expectType(*index, *actualType.keyType()); resultType = actualType.valueType(); @@ -2663,7 +2740,7 @@ bool TypeChecker::visit(IndexAccess const& _access) { TypeType const& typeType = dynamic_cast(*baseType); if (dynamic_cast(typeType.actualType())) - m_errorReporter.typeError(_access.location(), "Index access for contracts or libraries is not possible."); + m_errorReporter.typeError(2876_error, _access.location(), "Index access for contracts or libraries is not possible."); if (!index) resultType = TypeProvider::typeType(TypeProvider::array(DataLocation::Memory, typeType.actualType())); else @@ -2674,7 +2751,7 @@ bool TypeChecker::visit(IndexAccess const& _access) if (auto indexValue = dynamic_cast(type(*index))) length = indexValue->literalValue(nullptr); else - m_errorReporter.fatalTypeError(index->location(), "Integer constant expected."); + m_errorReporter.fatalTypeError(3940_error, index->location(), "Integer constant expected."); } else solAssert(m_errorReporter.hasErrors(), "Expected errors as expectType returned false"); @@ -2691,14 +2768,14 @@ bool TypeChecker::visit(IndexAccess const& _access) { FixedBytesType const& bytesType = dynamic_cast(*baseType); if (!index) - m_errorReporter.typeError(_access.location(), "Index expression cannot be omitted."); + m_errorReporter.typeError(8830_error, _access.location(), "Index expression cannot be omitted."); else { if (!expectType(*index, *TypeProvider::uint256())) - m_errorReporter.fatalTypeError(_access.location(), "Index expression cannot be represented as an unsigned integer."); + m_errorReporter.fatalTypeError(6318_error, _access.location(), "Index expression cannot be represented as an unsigned integer."); if (auto integerType = dynamic_cast(type(*index))) if (bytesType.numBytes() <= integerType->literalValue(nullptr)) - m_errorReporter.typeError(_access.location(), "Out of bounds array access."); + m_errorReporter.typeError(1859_error, _access.location(), "Out of bounds array access."); } resultType = TypeProvider::fixedBytes(1); isLValue = false; // @todo this heavily depends on how it is embedded @@ -2706,6 +2783,7 @@ bool TypeChecker::visit(IndexAccess const& _access) } default: m_errorReporter.fatalTypeError( + 2614_error, _access.baseExpression().location(), "Indexed expression has to be a type, mapping or array (is " + baseType->toString() + ")" ); @@ -2742,7 +2820,7 @@ bool TypeChecker::visit(IndexRangeAccess const& _access) TypePointer exprType = type(_access.baseExpression()); if (exprType->category() == Type::Category::TypeType) { - m_errorReporter.typeError(_access.location(), "Types cannot be sliced."); + m_errorReporter.typeError(1760_error, _access.location(), "Types cannot be sliced."); _access.annotation().type = exprType; return false; } @@ -2751,11 +2829,11 @@ bool TypeChecker::visit(IndexRangeAccess const& _access) if (auto const* arraySlice = dynamic_cast(exprType)) arrayType = &arraySlice->arrayType(); else if (!(arrayType = dynamic_cast(exprType))) - m_errorReporter.fatalTypeError(_access.location(), "Index range access is only possible for arrays and array slices."); + m_errorReporter.fatalTypeError(4781_error, _access.location(), "Index range access is only possible for arrays and array slices."); if (arrayType->location() != DataLocation::CallData || !arrayType->isDynamicallySized()) - m_errorReporter.typeError(_access.location(), "Index range access is only supported for dynamic calldata arrays."); + m_errorReporter.typeError(1227_error, _access.location(), "Index range access is only supported for dynamic calldata arrays."); _access.annotation().type = TypeProvider::arraySlice(*arrayType); _access.annotation().isLValue = isLValue; _access.annotation().isPure = isPure; @@ -2790,7 +2868,7 @@ vector TypeChecker::cleanOverloadedDeclarations( for (TypePointer parameter: functionType->parameterTypes() + functionType->returnParameterTypes()) if (!parameter) - m_errorReporter.fatalDeclarationError(_identifier.location(), "Function type can not be used in this context."); + m_errorReporter.fatalDeclarationError(3893_error, _identifier.location(), "Function type can not be used in this context."); if (uniqueDeclarations.end() == find_if( uniqueDeclarations.begin(), @@ -2825,14 +2903,14 @@ bool TypeChecker::visit(Identifier const& _identifier) candidates.push_back(declaration); } if (candidates.empty()) - m_errorReporter.fatalTypeError(_identifier.location(), "No matching declaration found after variable lookup."); + m_errorReporter.fatalTypeError(2144_error, _identifier.location(), "No matching declaration found after variable lookup."); else if (candidates.size() == 1) annotation.referencedDeclaration = candidates.front(); else - m_errorReporter.fatalTypeError(_identifier.location(), "No unique declaration found after variable lookup."); + m_errorReporter.fatalTypeError(7589_error, _identifier.location(), "No unique declaration found after variable lookup."); } else if (annotation.overloadedDeclarations.empty()) - m_errorReporter.fatalTypeError(_identifier.location(), "No candidates for overload resolution found."); + m_errorReporter.fatalTypeError(7593_error, _identifier.location(), "No candidates for overload resolution found."); else if (annotation.overloadedDeclarations.size() == 1) annotation.referencedDeclaration = *annotation.overloadedDeclarations.begin(); else @@ -2866,9 +2944,9 @@ bool TypeChecker::visit(Identifier const& _identifier) else ssl.append("Candidate:", declaration->location()); if (candidates.empty()) - m_errorReporter.fatalTypeError(_identifier.location(), ssl, "No matching declaration found after argument-dependent lookup."); + m_errorReporter.fatalTypeError(9322_error, _identifier.location(), ssl, "No matching declaration found after argument-dependent lookup."); else - m_errorReporter.fatalTypeError(_identifier.location(), ssl, "No unique declaration found after argument-dependent lookup."); + m_errorReporter.fatalTypeError(4487_error, _identifier.location(), ssl, "No unique declaration found after argument-dependent lookup."); } } } @@ -2896,11 +2974,13 @@ bool TypeChecker::visit(Identifier const& _identifier) { if (_identifier.name() == "sha3" && fType->kind() == FunctionType::Kind::KECCAK256) m_errorReporter.typeError( + 3557_error, _identifier.location(), "\"sha3\" has been deprecated in favour of \"keccak256\"." ); else if (_identifier.name() == "suicide" && fType->kind() == FunctionType::Kind::Selfdestruct) m_errorReporter.typeError( + 8050_error, _identifier.location(), "\"suicide\" has been deprecated in favour of \"selfdestruct\"." ); @@ -2938,6 +3018,7 @@ void TypeChecker::endVisit(Literal const& _literal) if (!msg.empty()) m_errorReporter.syntaxError( + 9429_error, _literal.location(), msg + " If this is not used as an address, please prepend '00'. " + @@ -2947,6 +3028,7 @@ void TypeChecker::endVisit(Literal const& _literal) if (_literal.isHexNumber() && _literal.subDenomination() != Literal::SubDenomination::None) m_errorReporter.fatalTypeError( + 5145_error, _literal.location(), "Hexadecimal numbers cannot be used with unit denominations. " "You can use an expression of the form \"0x1234 * 1 day\" instead." @@ -2954,6 +3036,7 @@ void TypeChecker::endVisit(Literal const& _literal) if (_literal.subDenomination() == Literal::SubDenomination::Year) m_errorReporter.typeError( + 4820_error, _literal.location(), "Using \"years\" as a unit denomination is deprecated." ); @@ -2962,7 +3045,7 @@ void TypeChecker::endVisit(Literal const& _literal) _literal.annotation().type = TypeProvider::forLiteral(_literal); if (!_literal.annotation().type) - m_errorReporter.fatalTypeError(_literal.location(), "Invalid literal value."); + m_errorReporter.fatalTypeError(2826_error, _literal.location(), "Invalid literal value."); _literal.annotation().isPure = true; } @@ -3012,11 +3095,13 @@ bool TypeChecker::expectType(Expression const& _expression, Type const& _expecte { if (_expectedType.operator==(*type(_expression)->mobileType())) m_errorReporter.typeError( + 4426_error, _expression.location(), errorMsg + ", but it can be explicitly converted." ); else m_errorReporter.typeError( + 2326_error, _expression.location(), errorMsg + ". Try converting to type " + @@ -3025,7 +3110,7 @@ bool TypeChecker::expectType(Expression const& _expression, Type const& _expecte ); } else - m_errorReporter.typeError(_expression.location(), errorMsg + "."); + m_errorReporter.typeError(7407_error, _expression.location(), errorMsg + "."); return false; } return true; @@ -3040,7 +3125,8 @@ void TypeChecker::requireLValue(Expression const& _expression, bool _ordinaryAss if (_expression.annotation().isLValue) return; - return m_errorReporter.typeError(_expression.location(), [&]() { + return m_errorReporter.typeError( + 1123_error,_expression.location(), [&]() { if (_expression.annotation().isConstant) return "Cannot assign to a constant variable."; diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp index 0d87fdbc2..645425107 100644 --- a/libsolidity/analysis/ViewPureChecker.cpp +++ b/libsolidity/analysis/ViewPureChecker.cpp @@ -171,6 +171,7 @@ void ViewPureChecker::endVisit(FunctionDefinition const& _funDef) !_funDef.overrides() ) m_errorReporter.warning( + 2018_error, _funDef.location(), "Function state mutability can be restricted to " + stateMutabilityToString(m_bestMutabilityAndLocation.mutability) ); @@ -252,6 +253,7 @@ void ViewPureChecker::reportMutability( )) { m_errorReporter.typeError( + 2527_error, _location, "Function declared as pure, but this expression (potentially) reads from the " "environment or state and thus requires \"view\"." @@ -261,6 +263,7 @@ void ViewPureChecker::reportMutability( else if (_mutability == StateMutability::NonPayable) { m_errorReporter.typeError( + 8961_error, _location, "Function declared as " + stateMutabilityToString(m_currentFunction->stateMutability()) + @@ -277,12 +280,14 @@ void ViewPureChecker::reportMutability( { if (_nestedLocation) m_errorReporter.typeError( + 4006_error, _location, SecondarySourceLocation().append("\"msg.value\" or \"callvalue()\" appear here inside the modifier.", *_nestedLocation), "This modifier uses \"msg.value\" or \"callvalue()\" and thus the function has to be payable or internal." ); else m_errorReporter.typeError( + 5887_error, _location, "\"msg.value\" and \"callvalue()\" can only be used in payable public functions. Make the function " "\"payable\" or use an internal function to avoid this error." diff --git a/libsolidity/formal/BMC.cpp b/libsolidity/formal/BMC.cpp index 13a19694b..e8fc331fa 100644 --- a/libsolidity/formal/BMC.cpp +++ b/libsolidity/formal/BMC.cpp @@ -44,6 +44,7 @@ BMC::BMC( if (_enabledSolvers.some()) if (!_smtlib2Responses.empty()) m_errorReporter.warning( + 5622_error, "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." @@ -74,6 +75,7 @@ void BMC::analyze(SourceUnit const& _source, set _safeAsserti { m_noSolverWarning = true; m_outerErrorReporter.warning( + 8084_error, SourceLocation(), "BMC analysis was not possible since no integrated SMT solver (Z3 or CVC4) was found." ); @@ -467,6 +469,7 @@ void BMC::internalOrExternalFunctionCall(FunctionCall const& _funCall) inlineFunctionCall(_funCall); else if (funType.kind() == FunctionType::Kind::Internal) m_errorReporter.warning( + 5729_error, _funCall.location(), "Assertion checker does not yet implement this type of function call." ); @@ -760,6 +763,7 @@ void BMC::checkCondition( for (auto const& eval: sortedModel) modelMessage << " " << eval.first << " = " << eval.second << "\n"; m_errorReporter.warning( + 4334_error, _location, message.str(), SecondarySourceLocation().append(modelMessage.str(), SourceLocation{}) @@ -770,20 +774,20 @@ void BMC::checkCondition( else { message << "."; - m_errorReporter.warning(_location, message.str(), secondaryLocation); + m_errorReporter.warning(6084_error, _location, message.str(), secondaryLocation); } break; } case smt::CheckResult::UNSATISFIABLE: break; case smt::CheckResult::UNKNOWN: - m_errorReporter.warning(_location, _description + " might happen here.", secondaryLocation); + m_errorReporter.warning(5225_error, _location, _description + " might happen here.", secondaryLocation); break; case smt::CheckResult::CONFLICTING: - m_errorReporter.warning(_location, "At least two SMT solvers provided conflicting answers. Results might not be sound."); + m_errorReporter.warning(1584_error, _location, "At least two SMT solvers provided conflicting answers. Results might not be sound."); break; case smt::CheckResult::ERROR: - m_errorReporter.warning(_location, "Error trying to invoke SMT solver."); + m_errorReporter.warning(1823_error, _location, "Error trying to invoke SMT solver."); break; } @@ -813,9 +817,9 @@ void BMC::checkBooleanNotConstant( m_interface->pop(); if (positiveResult == smt::CheckResult::ERROR || negatedResult == smt::CheckResult::ERROR) - m_errorReporter.warning(_condition.location(), "Error trying to invoke SMT solver."); + m_errorReporter.warning(8592_error, _condition.location(), "Error trying to invoke SMT solver."); else if (positiveResult == smt::CheckResult::CONFLICTING || negatedResult == smt::CheckResult::CONFLICTING) - m_errorReporter.warning(_condition.location(), "At least two SMT solvers provided conflicting answers. Results might not be sound."); + m_errorReporter.warning(3356_error, _condition.location(), "At least two SMT solvers provided conflicting answers. Results might not be sound."); else if (positiveResult == smt::CheckResult::SATISFIABLE && negatedResult == smt::CheckResult::SATISFIABLE) { // everything fine. @@ -825,7 +829,7 @@ void BMC::checkBooleanNotConstant( // can't do anything. } else if (positiveResult == smt::CheckResult::UNSATISFIABLE && negatedResult == smt::CheckResult::UNSATISFIABLE) - m_errorReporter.warning(_condition.location(), "Condition unreachable.", SMTEncoder::callStackMessage(_callStack)); + m_errorReporter.warning(2512_error, _condition.location(), "Condition unreachable.", SMTEncoder::callStackMessage(_callStack)); else { string value; @@ -841,6 +845,7 @@ void BMC::checkBooleanNotConstant( value = "false"; } m_errorReporter.warning( + 6838_error, _condition.location(), boost::algorithm::replace_all_copy(_description, "$VALUE", value), SMTEncoder::callStackMessage(_callStack) @@ -862,7 +867,7 @@ BMC::checkSatisfiableAndGenerateModel(vector const& _expression string description("Error querying SMT solver"); if (_e.comment()) description += ": " + *_e.comment(); - m_errorReporter.warning(description); + m_errorReporter.warning(8140_error, description); result = smt::CheckResult::ERROR; } diff --git a/libsolidity/formal/CHC.cpp b/libsolidity/formal/CHC.cpp index 59e77d7cd..1453df34f 100644 --- a/libsolidity/formal/CHC.cpp +++ b/libsolidity/formal/CHC.cpp @@ -965,10 +965,10 @@ pair> CHC::query(smt::Expression const& _query, case smt::CheckResult::UNKNOWN: break; case smt::CheckResult::CONFLICTING: - m_outerErrorReporter.warning(_location, "At least two SMT solvers provided conflicting answers. Results might not be sound."); + m_outerErrorReporter.warning(1988_error, _location, "At least two SMT solvers provided conflicting answers. Results might not be sound."); break; case smt::CheckResult::ERROR: - m_outerErrorReporter.warning(_location, "Error trying to invoke SMT solver."); + m_outerErrorReporter.warning(1218_error, _location, "Error trying to invoke SMT solver."); break; } return {result, values}; diff --git a/libsolidity/formal/SMTEncoder.cpp b/libsolidity/formal/SMTEncoder.cpp index 9003d26ce..8760c7b6b 100644 --- a/libsolidity/formal/SMTEncoder.cpp +++ b/libsolidity/formal/SMTEncoder.cpp @@ -266,6 +266,7 @@ void SMTEncoder::endVisit(FunctionDefinition const&) bool SMTEncoder::visit(InlineAssembly const& _inlineAsm) { m_errorReporter.warning( + 7737_error, _inlineAsm.location(), "Assertion checker does not support inline assembly." ); @@ -325,6 +326,7 @@ void SMTEncoder::endVisit(VariableDeclarationStatement const& _varDecl) } else m_errorReporter.warning( + 7186_error, _varDecl.location(), "Assertion checker does not yet implement such variable declarations." ); @@ -350,6 +352,7 @@ void SMTEncoder::endVisit(Assignment const& _assignment) m_context.newValue(*varDecl); m_errorReporter.warning( + 9149_error, _assignment.location(), "Assertion checker does not yet implement this assignment operator." ); @@ -409,6 +412,7 @@ void SMTEncoder::endVisit(TupleExpression const& _tuple) if (_tuple.isInlineArray()) m_errorReporter.warning( + 2177_error, _tuple.location(), "Assertion checker does not yet implement inline arrays." ); @@ -493,6 +497,7 @@ void SMTEncoder::endVisit(UnaryOperation const& _op) } else m_errorReporter.warning( + 1950_error, _op.location(), "Assertion checker does not yet implement such increments / decrements." ); @@ -522,6 +527,7 @@ void SMTEncoder::endVisit(UnaryOperation const& _op) arrayIndexAssignment(_op.subExpression(), symbVar->currentValue()); else m_errorReporter.warning( + 2683_error, _op.location(), "Assertion checker does not yet implement \"delete\" for this expression." ); @@ -530,6 +536,7 @@ void SMTEncoder::endVisit(UnaryOperation const& _op) } default: m_errorReporter.warning( + 3682_error, _op.location(), "Assertion checker does not yet implement this operator." ); @@ -568,6 +575,7 @@ void SMTEncoder::endVisit(BinaryOperation const& _op) compareOperation(_op); else m_errorReporter.warning( + 3876_error, _op.location(), "Assertion checker does not yet implement this operator." ); @@ -580,6 +588,7 @@ void SMTEncoder::endVisit(FunctionCall const& _funCall) if (_funCall.annotation().kind == FunctionCallKind::StructConstructorCall) { m_errorReporter.warning( + 4639_error, _funCall.location(), "Assertion checker does not yet implement this expression." ); @@ -639,6 +648,7 @@ void SMTEncoder::endVisit(FunctionCall const& _funCall) } default: m_errorReporter.warning( + 4588_error, _funCall.location(), "Assertion checker does not yet implement this type of function call." ); @@ -771,6 +781,7 @@ void SMTEncoder::visitTypeConversion(FunctionCall const& _funCall) } m_errorReporter.warning( + 5084_error, _funCall.location(), "Type conversion is not yet fully supported and might yield false positives." ); @@ -800,6 +811,7 @@ void SMTEncoder::endVisit(Literal const& _literal) else { m_errorReporter.warning( + 7885_error, _literal.location(), "Assertion checker does not yet support the type of this literal (" + _literal.annotation().type->toString() + @@ -850,6 +862,7 @@ bool SMTEncoder::visit(MemberAccess const& _memberAccess) accessedName = identifier->name(); else m_errorReporter.warning( + 9551_error, _memberAccess.location(), "Assertion checker does not yet support this expression." ); @@ -879,6 +892,7 @@ bool SMTEncoder::visit(MemberAccess const& _memberAccess) } else m_errorReporter.warning( + 7650_error, _memberAccess.location(), "Assertion checker does not yet support this expression." ); @@ -903,6 +917,7 @@ void SMTEncoder::endVisit(IndexAccess const& _indexAccess) if (varDecl->type()->category() == Type::Category::FixedBytes) { m_errorReporter.warning( + 7989_error, _indexAccess.location(), "Assertion checker does not yet support index accessing fixed bytes." ); @@ -917,6 +932,7 @@ void SMTEncoder::endVisit(IndexAccess const& _indexAccess) else { m_errorReporter.warning( + 9118_error, _indexAccess.location(), "Assertion checker does not yet implement this expression." ); @@ -940,6 +956,7 @@ void SMTEncoder::endVisit(IndexRangeAccess const& _indexRangeAccess) { createExpr(_indexRangeAccess); m_errorReporter.warning( + 2923_error, _indexRangeAccess.location(), "Assertion checker does not yet implement this expression." ); @@ -1019,6 +1036,7 @@ void SMTEncoder::arrayIndexAssignment(Expression const& _expr, smt::Expression c else { m_errorReporter.warning( + 9056_error, _expr.location(), "Assertion checker does not yet implement this expression." ); @@ -1034,6 +1052,7 @@ void SMTEncoder::defineGlobalVariable(string const& _name, Expression const& _ex bool abstract = m_context.createGlobalSymbol(_name, _expr); if (abstract) m_errorReporter.warning( + 1695_error, _expr.location(), "Assertion checker does not yet support this global variable." ); @@ -1087,6 +1106,7 @@ void SMTEncoder::arithmeticOperation(BinaryOperation const& _op) } default: m_errorReporter.warning( + 5188_error, _op.location(), "Assertion checker does not yet implement this operator." ); @@ -1094,6 +1114,7 @@ void SMTEncoder::arithmeticOperation(BinaryOperation const& _op) } else m_errorReporter.warning( + 9011_error, _op.location(), "Assertion checker does not yet implement this operator for type " + type->richIdentifier() + "." ); @@ -1185,6 +1206,7 @@ void SMTEncoder::compareOperation(BinaryOperation const& _op) } else m_errorReporter.warning( + 7229_error, _op.location(), "Assertion checker does not yet implement the type " + _op.annotation().commonType->toString() + " for comparisons" ); @@ -1213,6 +1235,7 @@ void SMTEncoder::booleanOperation(BinaryOperation const& _op) } else m_errorReporter.warning( + 3263_error, _op.location(), "Assertion checker does not yet implement the type " + _op.annotation().commonType->toString() + " for boolean operations" ); @@ -1245,6 +1268,7 @@ void SMTEncoder::assignment( m_context.newValue(*varDecl); m_errorReporter.warning( + 6191_error, _location, "Assertion checker does not yet implement type " + _type->toString() ); @@ -1272,6 +1296,7 @@ void SMTEncoder::assignment( } else m_errorReporter.warning( + 8182_error, _location, "Assertion checker does not yet implement such assignments." ); @@ -1482,6 +1507,7 @@ bool SMTEncoder::createVariable(VariableDeclaration const& _varDecl) if (abstract) { m_errorReporter.warning( + 8115_error, _varDecl.location(), "Assertion checker does not yet support the type of this variable." ); @@ -1494,7 +1520,7 @@ smt::Expression SMTEncoder::expr(Expression const& _e, TypePointer _targetType) { if (!m_context.knownExpression(_e)) { - m_errorReporter.warning(_e.location(), "Internal error: Expression undefined for SMT solver." ); + m_errorReporter.warning(6031_error, _e.location(), "Internal error: Expression undefined for SMT solver." ); createExpr(_e); } @@ -1506,6 +1532,7 @@ void SMTEncoder::createExpr(Expression const& _e) bool abstract = m_context.createExpression(_e); if (abstract) m_errorReporter.warning( + 8364_error, _e.location(), "Assertion checker does not yet implement type " + _e.annotation().type->toString() ); diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 0af68bda7..519eea81a 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -239,7 +239,7 @@ bool CompilerStack::parse() m_errorReporter.clear(); if (SemVerVersion{string(VersionString)}.isPrerelease()) - m_errorReporter.warning("This is a pre-release compiler version, please do not use it in production."); + m_errorReporter.warning(3805_error, "This is a pre-release compiler version, please do not use it in production."); Parser parser{m_errorReporter, m_evmVersion, m_parserErrorRecovery}; @@ -949,6 +949,7 @@ StringMap CompilerStack::loadMissingSources(SourceUnit const& _ast, std::string else { m_errorReporter.parserError( + 6275_error, import->location(), string("Source \"" + importPath + "\" not found: " + result.responseOrErrorMessage) ); @@ -1110,6 +1111,7 @@ void CompilerStack::compileContract( compiledContract.runtimeObject.bytecode.size() > 0x6000 ) m_errorReporter.warning( + 5574_error, _contract.location(), "Contract code size exceeds 24576 bytes (a limit introduced in Spurious Dragon). " "This contract may not be deployable on mainnet. " diff --git a/libsolidity/parsing/DocStringParser.cpp b/libsolidity/parsing/DocStringParser.cpp index fb1468197..b8238554f 100644 --- a/libsolidity/parsing/DocStringParser.cpp +++ b/libsolidity/parsing/DocStringParser.cpp @@ -195,5 +195,5 @@ void DocStringParser::newTag(string const& _tagName) void DocStringParser::appendError(string const& _description) { m_errorsOccurred = true; - m_errorReporter->docstringParsingError(_description); + m_errorReporter->docstringParsingError(9440_error, _description); } diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index d3c4a2cdd..d24b0e69f 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -128,6 +128,7 @@ void Parser::parsePragmaVersion(SourceLocation const& _location, vector c // so we don't need to report anything here. if (!m_parserErrorRecovery) m_errorReporter.fatalParserError( + 5333_error, _location, "Source file requires different compiler version (current compiler is " + string(VersionString) + ") - note that nightly builds are considered to be " diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index 7858b70c4..5c6b7c927 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -583,6 +583,7 @@ bool AsmAnalyzer::warnOnInstructions(evmasm::Instruction _instr, SourceLocation ) { m_errorReporter.error( + 4316_error, Error::Type::SyntaxError, _location, "Jump instructions and labels are low-level EVM features that can lead to " @@ -599,13 +600,13 @@ bool AsmAnalyzer::warnOnInstructions(evmasm::Instruction _instr, SourceLocation void AsmAnalyzer::typeError(SourceLocation const& _location, string const& _description) { - m_errorReporter.typeError(_location, _description); + m_errorReporter.typeError(7569_error, _location, _description); m_success = false; } void AsmAnalyzer::declarationError(SourceLocation const& _location, string const& _description) { - m_errorReporter.declarationError(_location, _description); + m_errorReporter.declarationError(9595_error, _location, _description); m_success = false; } diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index 99a3a6e21..13b96839b 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -151,7 +151,7 @@ Statement Parser::parseStatement() { Statement stmt{createWithLocation()}; if (!m_insideFunction) - m_errorReporter.syntaxError(currentLocation(), "Keyword \"leave\" can only be used inside a function."); + m_errorReporter.syntaxError(8149_error, currentLocation(), "Keyword \"leave\" can only be used inside a function."); m_scanner->next(); return stmt; } @@ -417,6 +417,7 @@ FunctionDefinition Parser::parseFunctionDefinition() if (m_currentForLoopComponent == ForLoopComponent::ForLoopPre) m_errorReporter.syntaxError( + 3441_error, currentLocation(), "Functions cannot be defined inside a for-loop init block." ); @@ -534,13 +535,13 @@ void Parser::checkBreakContinuePosition(string const& _which) switch (m_currentForLoopComponent) { case ForLoopComponent::None: - m_errorReporter.syntaxError(currentLocation(), "Keyword \"" + _which + "\" needs to be inside a for-loop body."); + m_errorReporter.syntaxError(2592_error, currentLocation(), "Keyword \"" + _which + "\" needs to be inside a for-loop body."); break; case ForLoopComponent::ForLoopPre: - m_errorReporter.syntaxError(currentLocation(), "Keyword \"" + _which + "\" in for-loop init block is not allowed."); + m_errorReporter.syntaxError(9615_error, currentLocation(), "Keyword \"" + _which + "\" in for-loop init block is not allowed."); break; case ForLoopComponent::ForLoopPost: - m_errorReporter.syntaxError(currentLocation(), "Keyword \"" + _which + "\" in for-loop post block is not allowed."); + m_errorReporter.syntaxError(2461_error, currentLocation(), "Keyword \"" + _which + "\" in for-loop post block is not allowed."); break; case ForLoopComponent::ForLoopBody: break; diff --git a/libyul/AsmScopeFiller.cpp b/libyul/AsmScopeFiller.cpp index 4c37bf5ec..62d00435f 100644 --- a/libyul/AsmScopeFiller.cpp +++ b/libyul/AsmScopeFiller.cpp @@ -141,6 +141,7 @@ bool ScopeFiller::registerVariable(TypedName const& _name, SourceLocation const& { //@TODO secondary location m_errorReporter.declarationError( + 1395_error, _location, "Variable name " + _name.name.str() + " already taken in this scope." ); @@ -161,6 +162,7 @@ bool ScopeFiller::registerFunction(FunctionDefinition const& _funDef) { //@TODO secondary location m_errorReporter.declarationError( + 6052_error, _funDef.location, "Function name " + _funDef.name.str() + " already taken in this scope." ); From 2d984b77a10ebeb1028bba6254c549b090e5fb6f Mon Sep 17 00:00:00 2001 From: a3d4 Date: Wed, 6 May 2020 14:25:13 +0200 Subject: [PATCH 24/89] Add a script to correct IDs --- liblangutil/ErrorReporter.h | 2 + scripts/correct_error_ids.py | 158 +++++++++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 scripts/correct_error_ids.py diff --git a/liblangutil/ErrorReporter.h b/liblangutil/ErrorReporter.h index 17e236e61..466bb66cb 100644 --- a/liblangutil/ErrorReporter.h +++ b/liblangutil/ErrorReporter.h @@ -38,6 +38,8 @@ namespace solidity::langutil * They are passed as the first parameter of error reporting functions. * Suffix _error helps to find them in the sources. * The struct ErrorId prevents incidental calls like typeError(3141) instead of typeError(3141_error). + * To create a new ID, one can add 0000_error and then run "python ./scripts/correct_error_ids.py" + * from the root of the repo. */ struct ErrorId { unsigned long long error = 0; }; ErrorId operator"" _error(unsigned long long error); diff --git a/scripts/correct_error_ids.py b/scripts/correct_error_ids.py new file mode 100644 index 000000000..d1f1cbf57 --- /dev/null +++ b/scripts/correct_error_ids.py @@ -0,0 +1,158 @@ +import random +import re +import os +from os import path + +ENCODING = "utf-8" +PATTERN = r"\b\d+_error\b" + + +def read_file(file_name): + content = None + try: + with open(file_name, "r", encoding=ENCODING) as f: + content = f.read() + finally: + if content == None: + print(f"Error reading: {file_name}") + return content + + +def write_file(file_name, content): + with open(file_name, "w", encoding=ENCODING) as f: + f.write(content) + + +def in_comment(source, pos): + slash_slash_pos = source.rfind("//", 0, pos) + lf_pos = source.rfind("\n", 0, pos) + if slash_slash_pos > lf_pos: + return True + slash_star_pos = source.rfind("/*", 0, pos) + star_slash_pos = source.rfind("*/", 0, pos) + return slash_star_pos > star_slash_pos + + +def find_ids_in_file(file_name, ids): + source = read_file(file_name) + for m in re.finditer(PATTERN, source): + if in_comment(source, m.start()): + continue + underscore_pos = m.group(0).index("_") + id = m.group(0)[0:underscore_pos] + if id in ids: + ids[id] += 1 + else: + ids[id] = 1 + + +def get_used_ids(file_names): + used_ids = {} + for file_name in file_names: + find_ids_in_file(file_name, used_ids) + return used_ids + + +def get_id(available_ids, used_ids): + while len(available_ids) > 0: + random.seed(len(available_ids)) + k = random.randrange(len(available_ids)) + id = list(available_ids.keys())[k] + del available_ids[id] + if id not in used_ids: + return id + assert False, "Out of IDs" + + +def fix_ids_in_file(file_name, available_ids, used_ids): + source = read_file(file_name) + + k = 0 + destination = [] + for m in re.finditer(PATTERN, source): + destination.extend(source[k:m.start()]) + + underscore_pos = m.group(0).index("_") + id = m.group(0)[0:underscore_pos] + + # incorrect id or id has a duplicate somewhere + if not in_comment(source, m.start()) and (len(id) != 4 or id[0] == "0" or used_ids[id] > 1): + assert id in used_ids + new_id = get_id(available_ids, used_ids) + used_ids[id] -= 1 + else: + new_id = id + + destination.extend(new_id + "_error") + k = m.end() + + destination.extend(source[k:]) + + destination = ''.join(destination) + if source != destination: + write_file(file_name, destination) + print(f"Fixed file: {file_name}") + + +def fix_ids(used_ids, file_names): + available_ids = {str(id): None for id in range(1000, 10000)} + for file_name in file_names: + fix_ids_in_file(file_name, available_ids, used_ids) + + +def find_source_files(top_dir): + """Builds the list of .h and .cpp files in top_dir directory""" + + source_file_names = [] + black_set = { ".circleci", ".git", ".github", "build", "cmake", "CMakeFiles", "deps", "docs" } + + for root, _, file_names in os.walk(top_dir, onerror=lambda e: exit(f"Walk error: {e}")): + path_elements = set(root.split(os.sep)) + if not black_set.isdisjoint(path_elements): + continue + for file_name in file_names: + _, ext = path.splitext(file_name) + if ext in [".h", ".cpp"]: + source_file_names.append(path.join(root, file_name)) + + return source_file_names + + +def main(): + cwd = os.getcwd() + answer = input( + f"This script checks and corrects *_error literals in .h and .cpp files\n" + f"in {cwd}, recursively.\n\n" + f"Please commit current changes first, and review the results when the script finishes.\n\n" + f"Do you want to start [Y/N]? " + ) + while len(answer) == 0 or answer not in "YN": + answer = input("[Y/N]? ") + if answer != "Y": + return + + source_file_names = find_source_files(cwd) + + used_ids = get_used_ids(source_file_names) + + ok = True + for id in sorted(used_ids): + if len(id) != 4: + print(f"ID {id} length != 4") + ok = False + if id[0] == "0": + print(f"ID {id} starts with zero") + ok = False + if used_ids[id] > 1: + print(f"ID {id} appears {used_ids[id]} times") + ok = False + + if ok: + print("No incorrect IDs found") + else: + fix_ids(used_ids, source_file_names) + print("Fixing compteted") + + +if __name__ == "__main__": + main() From 327c75bc1b57c37f6dc6a92d3fbf0f9bb03a57a5 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 20 Apr 2020 22:16:42 +0100 Subject: [PATCH 25/89] IR generation for shifts --- libsolidity/codegen/YulUtilFunctions.cpp | 83 +++++++++++++++++- libsolidity/codegen/YulUtilFunctions.h | 8 ++ .../codegen/ir/IRGeneratorForStatements.cpp | 87 ++++++++++++++++--- .../codegen/ir/IRGeneratorForStatements.h | 5 ++ .../shifts/shift_cleanup_garbled.sol | 2 + .../shifts/shift_constant_left_assignment.sol | 2 + .../shift_constant_right_assignment.sol | 2 + .../semanticTests/shifts/shift_left.sol | 2 + .../shifts/shift_left_assignment.sol | 2 + .../shift_left_assignment_different_type.sol | 2 + .../shifts/shift_left_larger_type.sol | 3 +- .../shifts/shift_left_uint32.sol | 2 + .../semanticTests/shifts/shift_left_uint8.sol | 2 + .../shifts/shift_negative_rvalue.sol | 2 + .../shift_negative_rvalue_assignment.sol | 2 + .../semanticTests/shifts/shift_overflow.sol | 2 + .../semanticTests/shifts/shift_right.sol | 2 + .../shifts/shift_right_assignment.sol | 2 + .../shifts/shift_right_assignment_signed.sol | 2 + .../shifts/shift_right_garbled_signed_v2.sol | 2 + .../shifts/shift_right_garbled_v2.sol | 2 + .../shifts/shift_right_negative_lvalue.sol | 2 + ...shift_right_negative_lvalue_assignment.sol | 2 + .../shift_right_negative_lvalue_int16.sol | 2 + .../shift_right_negative_lvalue_int32.sol | 2 + .../shift_right_negative_lvalue_int8.sol | 2 + ...ht_negative_lvalue_signextend_int16_v2.sol | 2 + ...ht_negative_lvalue_signextend_int32_v2.sol | 2 + ...ght_negative_lvalue_signextend_int8_v2.sol | 2 + .../shifts/shift_right_uint32.sol | 2 + .../shifts/shift_right_uint8.sol | 2 + .../shifts/shift_signed_cleanup_amount.sol | 16 ++++ 32 files changed, 236 insertions(+), 18 deletions(-) create mode 100644 test/libsolidity/semanticTests/shifts/shift_signed_cleanup_amount.sol diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 540086756..4e0ebb929 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -299,9 +299,6 @@ string YulUtilFunctions::shiftRightFunction(size_t _numBits) string YulUtilFunctions::shiftRightFunctionDynamic() { - // Note that if this is extended with signed shifts, - // the opcodes SAR and SDIV behave differently with regards to rounding! - string const functionName = "shift_right_unsigned_dynamic"; return m_functionCollector.createFunction(functionName, [&]() { return @@ -321,6 +318,86 @@ string YulUtilFunctions::shiftRightFunctionDynamic() }); } +string YulUtilFunctions::shiftRightSignedFunctionDynamic() +{ + string const functionName = "shift_right_signed_dynamic"; + return m_functionCollector.createFunction(functionName, [&]() { + return + Whiskers(R"( + function (bits, value) -> result { + + result := sar(bits, value) + + let divisor := exp(2, bits) + let xor_mask := sub(0, slt(value, 0)) + result := xor(div(xor(value, xor_mask), divisor), xor_mask) + // combined version of + // switch slt(value, 0) + // case 0 { result := div(value, divisor) } + // default { result := not(div(not(value), divisor)) } + + } + )") + ("functionName", functionName) + ("hasShifts", m_evmVersion.hasBitwiseShifting()) + .render(); + }); +} + + +string YulUtilFunctions::typedShiftLeftFunction(Type const& _type, Type const& _amountType) +{ + solAssert(_type.category() == Type::Category::FixedBytes || _type.category() == Type::Category::Integer, ""); + solAssert(_amountType.category() == Type::Category::Integer, ""); + string const functionName = "shift_left_" + _type.identifier() + "_" + _amountType.identifier(); + return m_functionCollector.createFunction(functionName, [&]() { + return + Whiskers(R"( + function (value, bits) -> result { + bits := (bits) + + if slt(bits, 0) { invalid() } + + result := ((bits, value)) + } + )") + ("functionName", functionName) + ("amountSigned", dynamic_cast(_amountType).isSigned()) + ("cleanAmount", cleanupFunction(_amountType)) + ("shift", shiftLeftFunctionDynamic()) + ("cleanup", cleanupFunction(_type)) + .render(); + }); +} + +string YulUtilFunctions::typedShiftRightFunction(Type const& _type, Type const& _amountType) +{ + solAssert(_type.category() == Type::Category::FixedBytes || _type.category() == Type::Category::Integer, ""); + solAssert(_amountType.category() == Type::Category::Integer, ""); + IntegerType const* integerType = dynamic_cast(&_type); + bool valueSigned = integerType && integerType->isSigned(); + + string const functionName = "shift_right_" + _type.identifier() + "_" + _amountType.identifier(); + return m_functionCollector.createFunction(functionName, [&]() { + return + Whiskers(R"( + function (value, bits) -> result { + bits := (bits) + + if slt(bits, 0) { invalid() } + + result := ((bits, (value))) + } + )") + ("functionName", functionName) + ("amountSigned", dynamic_cast(_amountType).isSigned()) + ("cleanAmount", cleanupFunction(_amountType)) + ("shift", valueSigned ? shiftRightSignedFunctionDynamic() : shiftRightFunctionDynamic()) + ("cleanup", cleanupFunction(_type)) + .render(); + }); +} + string YulUtilFunctions::updateByteSliceFunction(size_t _numBytes, size_t _shiftBytes) { solAssert(_numBytes <= 32, ""); diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index 9f21a7d39..e72d6d293 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -81,6 +81,14 @@ public: std::string shiftLeftFunctionDynamic(); std::string shiftRightFunction(size_t _numBits); std::string shiftRightFunctionDynamic(); + std::string shiftRightSignedFunctionDynamic(); + + /// @returns the name of a function that performs a left shift and subsequent cleanup + /// and, if needed, prior cleanup. + /// If the amount to shift by is signed, a check for negativeness is performed. + /// signature: (value, amountToShift) -> result + std::string typedShiftLeftFunction(Type const& _type, Type const& _amountType); + std::string typedShiftRightFunction(Type const& _type, Type const& _amountType); /// @returns the name of a function which replaces the /// _numBytes bytes starting at byte position _shiftBytes (counted from the least significant diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index d10ec3bd5..6bfe35395 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -254,29 +254,53 @@ bool IRGeneratorForStatements::visit(Conditional const& _conditional) bool IRGeneratorForStatements::visit(Assignment const& _assignment) { _assignment.rightHandSide().accept(*this); - Type const* intermediateType = type(_assignment.rightHandSide()).closestTemporaryType( - &type(_assignment.leftHandSide()) - ); - IRVariable value = convert(_assignment.rightHandSide(), *intermediateType); + Token assignmentOperator = _assignment.assignmentOperator(); + Token binaryOperator = + assignmentOperator == Token::Assign ? + assignmentOperator : + TokenTraits::AssignmentToBinaryOp(assignmentOperator); + + Type const* rightIntermediateType = + TokenTraits::isShiftOp(binaryOperator) ? + type(_assignment.rightHandSide()).mobileType() : + type(_assignment.rightHandSide()).closestTemporaryType( + &type(_assignment.leftHandSide()) + ); + solAssert(rightIntermediateType, ""); + IRVariable value = convert(_assignment.rightHandSide(), *rightIntermediateType); _assignment.leftHandSide().accept(*this); solAssert(!!m_currentLValue, "LValue not retrieved."); - if (_assignment.assignmentOperator() != Token::Assign) + if (assignmentOperator != Token::Assign) { - solAssert(type(_assignment.leftHandSide()) == *intermediateType, ""); - solAssert(intermediateType->isValueType(), "Compound operators only available for value types."); - + solAssert(type(_assignment.leftHandSide()).isValueType(), "Compound operators only available for value types."); + solAssert(rightIntermediateType->isValueType(), "Compound operators only available for value types."); IRVariable leftIntermediate = readFromLValue(*m_currentLValue); - m_code << value.name() << " := " << binaryOperation( - TokenTraits::AssignmentToBinaryOp(_assignment.assignmentOperator()), - *intermediateType, - leftIntermediate.name(), - value.name() - ); + if (TokenTraits::isShiftOp(binaryOperator)) + { + solAssert(type(_assignment) == leftIntermediate.type(), ""); + solAssert(type(_assignment) == type(_assignment.leftHandSide()), ""); + define(_assignment) << shiftOperation(binaryOperator, leftIntermediate, value); + + writeToLValue(*m_currentLValue, IRVariable(_assignment)); + m_currentLValue.reset(); + return false; + } + else + { + solAssert(type(_assignment.leftHandSide()) == *rightIntermediateType, ""); + m_code << value.name() << " := " << binaryOperation( + binaryOperator, + *rightIntermediateType, + leftIntermediate.name(), + value.name() + ); + } } writeToLValue(*m_currentLValue, value); + m_currentLValue.reset(); if (*_assignment.annotation().type != *TypeProvider::emptyTuple()) define(_assignment, value); @@ -541,6 +565,12 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp) solAssert(false, "Unknown comparison operator."); define(_binOp) << expr << "\n"; } + else if (TokenTraits::isShiftOp(op)) + { + IRVariable left = convert(_binOp.leftExpression(), *commonType); + IRVariable right = convert(_binOp.rightExpression(), *type(_binOp.rightExpression()).mobileType()); + define(_binOp) << shiftOperation(_binOp.getOperator(), left, right) << "\n"; + } else { string left = expressionAsType(_binOp.leftExpression(), *commonType); @@ -1921,6 +1951,10 @@ string IRGeneratorForStatements::binaryOperation( string const& _right ) { + solAssert( + !TokenTraits::isShiftOp(_operator), + "Have to use specific shift operation function for shifts." + ); if (IntegerType const* type = dynamic_cast(&_type)) { string fun; @@ -1964,6 +1998,31 @@ string IRGeneratorForStatements::binaryOperation( return {}; } +std::string IRGeneratorForStatements::shiftOperation( + langutil::Token _operator, + IRVariable const& _value, + IRVariable const& _amountToShift +) +{ + IntegerType const* amountType = dynamic_cast(&_amountToShift.type()); + solAssert(amountType, ""); + + solAssert(_operator == Token::SHL || _operator == Token::SAR, ""); + + return + Whiskers(R"( + (, ) + )") + ("shift", + _operator == Token::SHL ? + m_utils.typedShiftLeftFunction(_value.type(), *amountType) : + m_utils.typedShiftRightFunction(_value.type(), *amountType) + ) + ("value", _value.name()) + ("amount", _amountToShift.name()) + .render(); +} + void IRGeneratorForStatements::appendAndOrOperatorCode(BinaryOperation const& _binOp) { langutil::Token const op = _binOp.getOperator(); diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.h b/libsolidity/codegen/ir/IRGeneratorForStatements.h index f73c585b4..c51b2225d 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.h +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.h @@ -147,6 +147,11 @@ private: std::string const& _right ); + /// @returns code to perform the given shift operation. + /// The operation itself will be performed in the type of the value, + /// while the amount to shift can have its own type. + std::string shiftOperation(langutil::Token _op, IRVariable const& _value, IRVariable const& _shiftAmount); + /// Assigns the value of @a _value to the lvalue @a _lvalue. void writeToLValue(IRLValue const& _lvalue, IRVariable const& _value); /// @returns a fresh IR variable containing the value of the lvalue @a _lvalue. diff --git a/test/libsolidity/semanticTests/shifts/shift_cleanup_garbled.sol b/test/libsolidity/semanticTests/shifts/shift_cleanup_garbled.sol index cc81c15e4..6789bc350 100644 --- a/test/libsolidity/semanticTests/shifts/shift_cleanup_garbled.sol +++ b/test/libsolidity/semanticTests/shifts/shift_cleanup_garbled.sol @@ -7,5 +7,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> 0x0 diff --git a/test/libsolidity/semanticTests/shifts/shift_constant_left_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_constant_left_assignment.sol index e5a4152b5..38a776b30 100644 --- a/test/libsolidity/semanticTests/shifts/shift_constant_left_assignment.sol +++ b/test/libsolidity/semanticTests/shifts/shift_constant_left_assignment.sol @@ -5,5 +5,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> 0x4200 diff --git a/test/libsolidity/semanticTests/shifts/shift_constant_right_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_constant_right_assignment.sol index 0f36c10ee..1853814c6 100644 --- a/test/libsolidity/semanticTests/shifts/shift_constant_right_assignment.sol +++ b/test/libsolidity/semanticTests/shifts/shift_constant_right_assignment.sol @@ -5,5 +5,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> 0x42 diff --git a/test/libsolidity/semanticTests/shifts/shift_left.sol b/test/libsolidity/semanticTests/shifts/shift_left.sol index 15d2a972a..e72671ceb 100644 --- a/test/libsolidity/semanticTests/shifts/shift_left.sol +++ b/test/libsolidity/semanticTests/shifts/shift_left.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint256,uint256): 0x4266, 0x0 -> 0x4266 // f(uint256,uint256): 0x4266, 0x8 -> 0x426600 diff --git a/test/libsolidity/semanticTests/shifts/shift_left_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_left_assignment.sol index 06cb38606..fd5981996 100644 --- a/test/libsolidity/semanticTests/shifts/shift_left_assignment.sol +++ b/test/libsolidity/semanticTests/shifts/shift_left_assignment.sol @@ -5,6 +5,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint256,uint256): 0x4266, 0x0 -> 0x4266 // f(uint256,uint256): 0x4266, 0x8 -> 0x426600 diff --git a/test/libsolidity/semanticTests/shifts/shift_left_assignment_different_type.sol b/test/libsolidity/semanticTests/shifts/shift_left_assignment_different_type.sol index 5cc15c1a8..2f470d500 100644 --- a/test/libsolidity/semanticTests/shifts/shift_left_assignment_different_type.sol +++ b/test/libsolidity/semanticTests/shifts/shift_left_assignment_different_type.sol @@ -5,6 +5,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint256,uint8): 0x4266, 0x0 -> 0x4266 // f(uint256,uint8): 0x4266, 0x8 -> 0x426600 diff --git a/test/libsolidity/semanticTests/shifts/shift_left_larger_type.sol b/test/libsolidity/semanticTests/shifts/shift_left_larger_type.sol index 99ff376d6..de7b4ec3e 100644 --- a/test/libsolidity/semanticTests/shifts/shift_left_larger_type.sol +++ b/test/libsolidity/semanticTests/shifts/shift_left_larger_type.sol @@ -6,6 +6,7 @@ contract C { return y << x; } } - +// ==== +// compileViaYul: also // ---- // f() -> 0 diff --git a/test/libsolidity/semanticTests/shifts/shift_left_uint32.sol b/test/libsolidity/semanticTests/shifts/shift_left_uint32.sol index 0f35077b1..a08f13aef 100644 --- a/test/libsolidity/semanticTests/shifts/shift_left_uint32.sol +++ b/test/libsolidity/semanticTests/shifts/shift_left_uint32.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint32,uint32): 0x4266, 0x0 -> 0x4266 // f(uint32,uint32): 0x4266, 0x8 -> 0x426600 diff --git a/test/libsolidity/semanticTests/shifts/shift_left_uint8.sol b/test/libsolidity/semanticTests/shifts/shift_left_uint8.sol index 3070314f8..af214a244 100644 --- a/test/libsolidity/semanticTests/shifts/shift_left_uint8.sol +++ b/test/libsolidity/semanticTests/shifts/shift_left_uint8.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint8,uint8): 0x66, 0x0 -> 0x66 // f(uint8,uint8): 0x66, 0x8 -> 0 diff --git a/test/libsolidity/semanticTests/shifts/shift_negative_rvalue.sol b/test/libsolidity/semanticTests/shifts/shift_negative_rvalue.sol index 77c18c44b..611458246 100644 --- a/test/libsolidity/semanticTests/shifts/shift_negative_rvalue.sol +++ b/test/libsolidity/semanticTests/shifts/shift_negative_rvalue.sol @@ -8,6 +8,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(int256,int256): 1, -1 -> FAILURE // g(int256,int256): 1, -1 -> FAILURE diff --git a/test/libsolidity/semanticTests/shifts/shift_negative_rvalue_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_negative_rvalue_assignment.sol index e63a9a57e..623a715ec 100644 --- a/test/libsolidity/semanticTests/shifts/shift_negative_rvalue_assignment.sol +++ b/test/libsolidity/semanticTests/shifts/shift_negative_rvalue_assignment.sol @@ -10,6 +10,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(int256,int256): 1, -1 -> FAILURE // g(int256,int256): 1, -1 -> FAILURE diff --git a/test/libsolidity/semanticTests/shifts/shift_overflow.sol b/test/libsolidity/semanticTests/shifts/shift_overflow.sol index f1b4bca0a..54f5fcc2b 100644 --- a/test/libsolidity/semanticTests/shifts/shift_overflow.sol +++ b/test/libsolidity/semanticTests/shifts/shift_overflow.sol @@ -8,6 +8,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // leftU(uint8,uint8): 255, 8 -> 0 // leftU(uint8,uint8): 255, 1 -> 254 diff --git a/test/libsolidity/semanticTests/shifts/shift_right.sol b/test/libsolidity/semanticTests/shifts/shift_right.sol index d78d18aba..bfdb665d1 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint256,uint256): 0x4266, 0x0 -> 0x4266 // f(uint256,uint256): 0x4266, 0x8 -> 0x42 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_right_assignment.sol index cfee67301..80f25238c 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_assignment.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_assignment.sol @@ -5,6 +5,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint256,uint256): 0x4266, 0x0 -> 0x4266 // f(uint256,uint256): 0x4266, 0x8 -> 0x42 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_assignment_signed.sol b/test/libsolidity/semanticTests/shifts/shift_right_assignment_signed.sol index ba819fbce..5b8494167 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_assignment_signed.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_assignment_signed.sol @@ -5,6 +5,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(int256,int256): 0x4266, 0x0 -> 0x4266 // f(int256,int256): 0x4266, 0x8 -> 0x42 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_garbled_signed_v2.sol b/test/libsolidity/semanticTests/shifts/shift_right_garbled_signed_v2.sol index 0c1949a59..4c705337c 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_garbled_signed_v2.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_garbled_signed_v2.sol @@ -18,6 +18,8 @@ contract C { return a >> b; } } +// ==== +// compileViaYul: also // ---- // f(int8,uint8): 0x00, 0x03 -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe // f(int8,uint8): 0x00, 0x04 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/test/libsolidity/semanticTests/shifts/shift_right_garbled_v2.sol b/test/libsolidity/semanticTests/shifts/shift_right_garbled_v2.sol index 54ac9540f..18ea9972c 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_garbled_v2.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_garbled_v2.sol @@ -10,6 +10,8 @@ contract C { return a >> b; } } +// ==== +// compileViaYul: also // ---- // f(uint8,uint8): 0x00, 0x04 -> 0x0f // f(uint8,uint8): 0x00, 0x1004 -> FAILURE diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue.sol index 73aae5bc9..2bac06e6e 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(int256,int256): -4266, 0 -> -4266 // f(int256,int256): -4266, 1 -> -2133 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_assignment.sol index 7f3beb59f..4fecffda4 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_assignment.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_assignment.sol @@ -5,6 +5,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(int256,int256): -4266, 0 -> -4266 // f(int256,int256): -4266, 1 -> -2133 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int16.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int16.sol index 24ab54123..883f004d0 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int16.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int16.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(int16,int16): -4266, 0 -> -4266 // f(int16,int16): -4266, 1 -> -2133 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int32.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int32.sol index 7ff669dc9..4f689c015 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int32.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int32.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(int32,int32): -4266, 0 -> -4266 // f(int32,int32): -4266, 1 -> -2133 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int8.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int8.sol index c6424f141..02f293e3c 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int8.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int8.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(int8,int8): -66, 0 -> -66 // f(int8,int8): -66, 1 -> -33 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int16_v2.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int16_v2.sol index 6e462e704..850a89be3 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int16_v2.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int16_v2.sol @@ -6,6 +6,8 @@ contract C { return a >> b; } } +// ==== +// compileViaYul: also // ---- // f(int16,int16): 0xff99, 0x00 -> FAILURE // f(int16,int16): 0xff99, 0x01 -> FAILURE diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int32_v2.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int32_v2.sol index 2466298f0..d797531ec 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int32_v2.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int32_v2.sol @@ -6,6 +6,8 @@ contract C { return a >> b; } } +// ==== +// compileViaYul: also // ---- // f(int32,int32): 0xffffff99, 0x00 -> FAILURE // f(int32,int32): 0xffffff99, 0x01 -> FAILURE diff --git a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int8_v2.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int8_v2.sol index 643bc5e62..ee485335d 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int8_v2.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int8_v2.sol @@ -6,6 +6,8 @@ contract C { return a >> b; } } +// ==== +// compileViaYul: also // ---- // f(int8,int8): 0x99, 0x00 -> FAILURE // f(int8,int8): 0x99, 0x01 -> FAILURE diff --git a/test/libsolidity/semanticTests/shifts/shift_right_uint32.sol b/test/libsolidity/semanticTests/shifts/shift_right_uint32.sol index 03573d985..8cc6c4a98 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_uint32.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_uint32.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint32,uint32): 0x4266, 0x0 -> 0x4266 // f(uint32,uint32): 0x4266, 0x8 -> 0x42 diff --git a/test/libsolidity/semanticTests/shifts/shift_right_uint8.sol b/test/libsolidity/semanticTests/shifts/shift_right_uint8.sol index 8457b10e1..acfd99b86 100644 --- a/test/libsolidity/semanticTests/shifts/shift_right_uint8.sol +++ b/test/libsolidity/semanticTests/shifts/shift_right_uint8.sol @@ -4,6 +4,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint8,uint8): 0x66, 0x0 -> 0x66 // f(uint8,uint8): 0x66, 0x8 -> 0x0 diff --git a/test/libsolidity/semanticTests/shifts/shift_signed_cleanup_amount.sol b/test/libsolidity/semanticTests/shifts/shift_signed_cleanup_amount.sol new file mode 100644 index 000000000..72b8f69c8 --- /dev/null +++ b/test/libsolidity/semanticTests/shifts/shift_signed_cleanup_amount.sol @@ -0,0 +1,16 @@ +contract C { + function f(uint256 a, int8 b) public returns (uint256) { + assembly { b := 0xff } + return a << b; + } + function g(uint256 a, int8 b) public returns (uint256) { + assembly { b := 0xff } + return a >> b; + } +} + +// ==== +// compileViaYul: also +// ---- +// f(uint256,int8): 0x1234, 0x0 -> FAILURE +// g(uint256,int8): 0x1234, 0x0 -> FAILURE From 6fb112fa8e5946ea1a9f86ded3fe2b191fdbc7dd Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 7 May 2020 01:49:46 +0200 Subject: [PATCH 26/89] Remove some unneeded headers. --- libevmasm/ExpressionClasses.cpp | 3 --- libevmasm/SimplificationRules.cpp | 3 --- libsolidity/analysis/ContractLevelChecker.cpp | 1 - libsolidity/analysis/ControlFlowGraph.cpp | 1 - libsolidity/analysis/OverrideChecker.cpp | 1 - libsolidity/codegen/ABIFunctions.cpp | 1 - libsolidity/codegen/ExpressionCompiler.cpp | 1 - libsolidity/codegen/MultiUseYulFunctionCollector.cpp | 2 -- libsolidity/codegen/YulUtilFunctions.cpp | 3 --- libsolidity/codegen/ir/IRGenerator.cpp | 3 --- libsolidity/codegen/ir/IRGeneratorForStatements.cpp | 1 - libyul/AsmScopeFiller.cpp | 2 -- libyul/backends/wasm/WasmCodeTransform.cpp | 3 --- libyul/optimiser/ExpressionSplitter.cpp | 2 -- libyul/optimiser/FullInliner.cpp | 2 -- 15 files changed, 29 deletions(-) diff --git a/libevmasm/ExpressionClasses.cpp b/libevmasm/ExpressionClasses.cpp index 62780b19f..04686ec94 100644 --- a/libevmasm/ExpressionClasses.cpp +++ b/libevmasm/ExpressionClasses.cpp @@ -26,9 +26,6 @@ #include #include -#include -#include - #include #include #include diff --git a/libevmasm/SimplificationRules.cpp b/libevmasm/SimplificationRules.cpp index 751153b05..8fb65d1d3 100644 --- a/libevmasm/SimplificationRules.cpp +++ b/libevmasm/SimplificationRules.cpp @@ -29,9 +29,6 @@ #include #include -#include -#include - #include #include diff --git a/libsolidity/analysis/ContractLevelChecker.cpp b/libsolidity/analysis/ContractLevelChecker.cpp index 1327e89f3..79b055784 100644 --- a/libsolidity/analysis/ContractLevelChecker.cpp +++ b/libsolidity/analysis/ContractLevelChecker.cpp @@ -26,7 +26,6 @@ #include #include #include -#include using namespace std; diff --git a/libsolidity/analysis/ControlFlowGraph.cpp b/libsolidity/analysis/ControlFlowGraph.cpp index 4cb096ae0..fb5fc1be0 100644 --- a/libsolidity/analysis/ControlFlowGraph.cpp +++ b/libsolidity/analysis/ControlFlowGraph.cpp @@ -18,7 +18,6 @@ #include #include -#include #include using namespace std; diff --git a/libsolidity/analysis/OverrideChecker.cpp b/libsolidity/analysis/OverrideChecker.cpp index fbff807f9..1f4fa10a2 100644 --- a/libsolidity/analysis/OverrideChecker.cpp +++ b/libsolidity/analysis/OverrideChecker.cpp @@ -27,7 +27,6 @@ #include #include -#include #include diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index 8909651be..20e4e23db 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -28,7 +28,6 @@ #include #include -#include using namespace std; using namespace solidity; diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 14b0d763b..a7ddb4b87 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -36,7 +36,6 @@ #include #include -#include #include #include diff --git a/libsolidity/codegen/MultiUseYulFunctionCollector.cpp b/libsolidity/codegen/MultiUseYulFunctionCollector.cpp index e8994ac04..f49f3083d 100644 --- a/libsolidity/codegen/MultiUseYulFunctionCollector.cpp +++ b/libsolidity/codegen/MultiUseYulFunctionCollector.cpp @@ -23,8 +23,6 @@ #include -#include -#include using namespace std; using namespace solidity; diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 4e0ebb929..f98d5770f 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -28,9 +28,6 @@ #include #include -#include -#include - using namespace std; using namespace solidity; using namespace solidity::util; diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index bac4fea66..bfecb9cf2 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -38,9 +38,6 @@ #include -#include -#include - #include using namespace std; diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 6bfe35395..902b7ba55 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -42,7 +42,6 @@ #include #include -#include #include using namespace std; diff --git a/libyul/AsmScopeFiller.cpp b/libyul/AsmScopeFiller.cpp index 62d00435f..90143ba4d 100644 --- a/libyul/AsmScopeFiller.cpp +++ b/libyul/AsmScopeFiller.cpp @@ -29,8 +29,6 @@ #include -#include - #include #include diff --git a/libyul/backends/wasm/WasmCodeTransform.cpp b/libyul/backends/wasm/WasmCodeTransform.cpp index cb1294d44..9c553b380 100644 --- a/libyul/backends/wasm/WasmCodeTransform.cpp +++ b/libyul/backends/wasm/WasmCodeTransform.cpp @@ -29,9 +29,6 @@ #include -#include -#include - using namespace std; using namespace solidity; using namespace solidity::yul; diff --git a/libyul/optimiser/ExpressionSplitter.cpp b/libyul/optimiser/ExpressionSplitter.cpp index 8144de49a..30a5fd5e9 100644 --- a/libyul/optimiser/ExpressionSplitter.cpp +++ b/libyul/optimiser/ExpressionSplitter.cpp @@ -31,8 +31,6 @@ #include #include -#include - using namespace std; using namespace solidity; using namespace solidity::yul; diff --git a/libyul/optimiser/FullInliner.cpp b/libyul/optimiser/FullInliner.cpp index 32036184a..a0c80533d 100644 --- a/libyul/optimiser/FullInliner.cpp +++ b/libyul/optimiser/FullInliner.cpp @@ -34,8 +34,6 @@ #include #include -#include - using namespace std; using namespace solidity; using namespace solidity::yul; From 7e1835af71560338fe1a2cf13c816b8cf0a38af1 Mon Sep 17 00:00:00 2001 From: a3d4 Date: Thu, 7 May 2020 03:52:53 +0200 Subject: [PATCH 27/89] Fix error reporting source code format --- libsolidity/analysis/ContractLevelChecker.cpp | 4 +++- libsolidity/analysis/SyntaxChecker.cpp | 3 ++- libsolidity/analysis/TypeChecker.cpp | 6 +++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/libsolidity/analysis/ContractLevelChecker.cpp b/libsolidity/analysis/ContractLevelChecker.cpp index 1327e89f3..8f7b69a4a 100644 --- a/libsolidity/analysis/ContractLevelChecker.cpp +++ b/libsolidity/analysis/ContractLevelChecker.cpp @@ -220,7 +220,9 @@ void ContractLevelChecker::checkAbstractDefinitions(ContractDefinition const& _c for (auto declaration: _contract.annotation().unimplementedDeclarations) ssl.append("Missing implementation: ", declaration->location()); m_errorReporter.typeError( - 3656_error,_contract.location(), ssl, + 3656_error, + _contract.location(), + ssl, "Contract \"" + _contract.annotation().canonicalName + "\" should be marked as abstract."); diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp index c3267c37f..058244cac 100644 --- a/libsolidity/analysis/SyntaxChecker.cpp +++ b/libsolidity/analysis/SyntaxChecker.cpp @@ -291,7 +291,8 @@ bool SyntaxChecker::visit(ContractDefinition const& _contract) for (FunctionDefinition const* function: _contract.definedFunctions()) if (function->name() == contractName) m_errorReporter.syntaxError( - 5796_error,function->location(), + 5796_error, + function->location(), "Functions are not allowed to have the same name as the contract. " "If you intend this to be a constructor, use \"constructor(...) { ... }\" to define it." ); diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 7277714b8..e8806da1f 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -493,7 +493,8 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) unsupportedTypes.emplace_back(param->toString()); if (!unsupportedTypes.empty()) m_errorReporter.typeError( - 2763_error,_variable.location(), + 2763_error, + _variable.location(), "The following types are only supported for getters in ABIEncoderV2: " + joinHumanReadable(unsupportedTypes) + ". Either remove \"public\" or use \"pragma experimental ABIEncoderV2;\" to enable the feature." @@ -3125,8 +3126,7 @@ void TypeChecker::requireLValue(Expression const& _expression, bool _ordinaryAss if (_expression.annotation().isLValue) return; - return m_errorReporter.typeError( - 1123_error,_expression.location(), [&]() { + return m_errorReporter.typeError(1123_error, _expression.location(), [&]() { if (_expression.annotation().isConstant) return "Cannot assign to a constant variable."; From 5e9502bfae0900e5696b5c6b760c4f7ccd9aabda Mon Sep 17 00:00:00 2001 From: a3d4 Date: Thu, 7 May 2020 05:33:08 +0200 Subject: [PATCH 28/89] Fix ABI internal compiler error caused by an internal constructor --- Changelog.md | 1 + libsolidity/interface/ABI.cpp | 5 +++-- test/libsolidity/ABIJson/internal_constructor.sol | 9 +++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 test/libsolidity/ABIJson/internal_constructor.sol diff --git a/Changelog.md b/Changelog.md index 0b3749be9..98a0ca408 100644 --- a/Changelog.md +++ b/Changelog.md @@ -9,6 +9,7 @@ Compiler Features: Bugfixes: + * ABI: Skip ``private`` or ``internal`` constructors. diff --git a/libsolidity/interface/ABI.cpp b/libsolidity/interface/ABI.cpp index 56e2ecbde..c00c2f83c 100644 --- a/libsolidity/interface/ABI.cpp +++ b/libsolidity/interface/ABI.cpp @@ -73,9 +73,10 @@ Json::Value ABI::generate(ContractDefinition const& _contractDef) ); abi.emplace(std::move(method)); } - if (_contractDef.constructor()) + FunctionDefinition const* constructor = _contractDef.constructor(); + if (constructor && constructor->visibility() >= Visibility::Public) { - FunctionType constrType(*_contractDef.constructor()); + FunctionType constrType(*constructor); FunctionType const* externalFunctionType = constrType.interfaceFunctionType(); solAssert(!!externalFunctionType, ""); Json::Value method; diff --git a/test/libsolidity/ABIJson/internal_constructor.sol b/test/libsolidity/ABIJson/internal_constructor.sol new file mode 100644 index 000000000..7f8ea5ed2 --- /dev/null +++ b/test/libsolidity/ABIJson/internal_constructor.sol @@ -0,0 +1,9 @@ +// bug #8712 +contract B { + uint immutable x; + constructor(function() internal returns(uint) fp) internal { + x = fp(); } +} +// ---- +// :B +// [] From ff084c28099a2758d4f780a13289f21a830eb319 Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Thu, 7 May 2020 11:22:56 +0200 Subject: [PATCH 29/89] Make error correction script user interaction case insensitive --- scripts/correct_error_ids.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/correct_error_ids.py b/scripts/correct_error_ids.py index d1f1cbf57..8717dbf23 100644 --- a/scripts/correct_error_ids.py +++ b/scripts/correct_error_ids.py @@ -126,9 +126,9 @@ def main(): f"Please commit current changes first, and review the results when the script finishes.\n\n" f"Do you want to start [Y/N]? " ) - while len(answer) == 0 or answer not in "YN": + while len(answer) == 0 or answer not in "YNyn": answer = input("[Y/N]? ") - if answer != "Y": + if answer not in "yY": return source_file_names = find_source_files(cwd) From e986fde0c191bc665c73ef3ff5777e02a0651fac Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 7 May 2020 01:55:30 +0200 Subject: [PATCH 30/89] Introduce non-reversed version of tupleEncoder. --- libsolidity/codegen/ABIFunctions.cpp | 20 ++++++++--- libsolidity/codegen/ABIFunctions.h | 34 +++++++++++++++---- libsolidity/codegen/CompilerUtils.cpp | 4 +-- libsolidity/codegen/YulUtilFunctions.cpp | 5 ++- libsolidity/codegen/ir/IRGenerator.cpp | 11 +++--- .../codegen/ir/IRGeneratorForStatements.cpp | 5 ++- .../yul_string_format_ascii/output.json | 2 +- .../output.json | 2 +- .../output.json | 2 +- .../yul_string_format_ascii_long/output.json | 2 +- .../yul_string_format_hex/output.json | 2 +- ...ta_array_dynamic_static_short_reencode.sol | 2 ++ .../pass_function_types_externally.sol | 2 ++ 13 files changed, 63 insertions(+), 30 deletions(-) diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index 8909651be..80d626038 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -38,7 +38,8 @@ using namespace solidity::frontend; string ABIFunctions::tupleEncoder( TypePointers const& _givenTypes, TypePointers const& _targetTypes, - bool _encodeAsLibraryTypes + bool _encodeAsLibraryTypes, + bool _reversed ) { EncodingOptions options; @@ -54,6 +55,8 @@ string ABIFunctions::tupleEncoder( for (auto const& t: _targetTypes) functionName += t->identifier() + "_"; functionName += options.toFunctionNameSuffix(); + if (_reversed) + functionName += "_reversed"; return createFunction(functionName, [&]() { // Note that the values are in reverse due to the difference in calling semantics. @@ -94,7 +97,10 @@ string ABIFunctions::tupleEncoder( stackPos += sizeOnStack; } solAssert(headPos == headSize_, ""); - string valueParams = suffixedVariableNameList("value", stackPos, 0); + string valueParams = + _reversed ? + suffixedVariableNameList("value", stackPos, 0) : + suffixedVariableNameList("value", 0, stackPos); templ("valueParams", valueParams.empty() ? "" : ", " + valueParams); templ("encodeElements", encodeElements); @@ -104,7 +110,8 @@ string ABIFunctions::tupleEncoder( string ABIFunctions::tupleEncoderPacked( TypePointers const& _givenTypes, - TypePointers const& _targetTypes + TypePointers const& _targetTypes, + bool _reversed ) { EncodingOptions options; @@ -120,6 +127,8 @@ string ABIFunctions::tupleEncoderPacked( for (auto const& t: _targetTypes) functionName += t->identifier() + "_"; functionName += options.toFunctionNameSuffix(); + if (_reversed) + functionName += "_reversed"; return createFunction(functionName, [&]() { solAssert(!_givenTypes.empty(), ""); @@ -158,7 +167,10 @@ string ABIFunctions::tupleEncoderPacked( encodeElements += elementTempl.render(); stackPos += sizeOnStack; } - string valueParams = suffixedVariableNameList("value", stackPos, 0); + string valueParams = + _reversed ? + suffixedVariableNameList("value", stackPos, 0) : + suffixedVariableNameList("value", 0, stackPos); templ("valueParams", valueParams.empty() ? "" : ", " + valueParams); templ("encodeElements", encodeElements); diff --git a/libsolidity/codegen/ABIFunctions.h b/libsolidity/codegen/ABIFunctions.h index e760917ac..a66b1284e 100644 --- a/libsolidity/codegen/ABIFunctions.h +++ b/libsolidity/codegen/ABIFunctions.h @@ -67,31 +67,53 @@ public: /// @returns name of an assembly function to ABI-encode values of @a _givenTypes /// into memory, converting the types to @a _targetTypes on the fly. - /// Parameters are: ... , i.e. - /// the layout on the stack is ... with + /// Parameters are: ... , i.e. + /// the layout on the stack is ... with /// the top of the stack on the right. /// The values represent stack slots. If a type occupies more or less than one /// stack slot, it takes exactly that number of values. /// Returns a pointer to the end of the area written in memory. /// Does not allocate memory (does not change the free memory pointer), but writes /// to memory starting at $headStart and an unrestricted amount after that. + /// If @reversed is true, the order of the variables after is reversed. std::string tupleEncoder( TypePointers const& _givenTypes, TypePointers const& _targetTypes, - bool _encodeAsLibraryTypes = false + bool _encodeAsLibraryTypes = false, + bool _reversed = false ); + /// Specialization of tupleEncoder to _reversed = true + std::string tupleEncoderReversed( + TypePointers const& _givenTypes, + TypePointers const& _targetTypes, + bool _encodeAsLibraryTypes = false + ) { + return tupleEncoder(_givenTypes, _targetTypes, _encodeAsLibraryTypes, true); + } + /// @returns name of an assembly function to encode values of @a _givenTypes /// with packed encoding into memory, converting the types to @a _targetTypes on the fly. - /// Parameters are: ... , i.e. - /// the layout on the stack is ... with + /// Parameters are: ... , i.e. + /// the layout on the stack is ... with /// the top of the stack on the right. /// The values represent stack slots. If a type occupies more or less than one /// stack slot, it takes exactly that number of values. /// Returns a pointer to the end of the area written in memory. /// Does not allocate memory (does not change the free memory pointer), but writes /// to memory starting at memPos and an unrestricted amount after that. - std::string tupleEncoderPacked(TypePointers const& _givenTypes, TypePointers const& _targetTypes); + /// If @reversed is true, the order of the variables after is reversed. + std::string tupleEncoderPacked( + TypePointers const& _givenTypes, + TypePointers const& _targetTypes, + bool _reversed = false + ); + + /// Specialization of tupleEncoderPacked to _reversed = true + std::string tupleEncoderPackedReversed(TypePointers const& _givenTypes, TypePointers const& _targetTypes) + { + return tupleEncoderPacked(_givenTypes, _targetTypes, true); + } /// @returns name of an assembly function to ABI-decode values of @a _types /// into memory. If @a _fromMemory is true, decodes from memory instead of diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 3d0117707..156cee565 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -559,8 +559,8 @@ void CompilerUtils::abiEncodeV2( string encoderName = _padToWordBoundaries ? - m_context.abiFunctions().tupleEncoder(_givenTypes, _targetTypes, _encodeAsLibraryTypes) : - m_context.abiFunctions().tupleEncoderPacked(_givenTypes, _targetTypes); + m_context.abiFunctions().tupleEncoderReversed(_givenTypes, _targetTypes, _encodeAsLibraryTypes) : + m_context.abiFunctions().tupleEncoderPackedReversed(_givenTypes, _targetTypes); m_context.callYulFunction(encoderName, sizeOnStack(_givenTypes) + 1, 1); } diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 4e0ebb929..f0c2ae0e3 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -1125,13 +1125,12 @@ string YulUtilFunctions::mappingIndexAccessFunction(MappingType const& _mappingT return m_functionCollector.createFunction(functionName, [&]() { if (_mappingType.keyType()->isDynamicallySized()) return Whiskers(R"( - function (slot ) -> dataSlot { - dataSlot := (slot ) + function (slot , ) -> dataSlot { + dataSlot := ( , slot) } )") ("functionName", functionName) ("key", _keyType.sizeOnStack() > 0 ? "key" : "") - ("comma", _keyType.sizeOnStack() > 0 ? "," : "") ("hash", packedHashFunction( {&_keyType, TypeProvider::uint256()}, {_mappingType.keyType(), TypeProvider::uint256()} diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index bac4fea66..2a86eafb1 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -482,10 +482,10 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract) { // - (4, calldatasize()) - () + let := (4, calldatasize()) + let := () let memPos := (0) - let memEnd := (memPos ) + let memEnd := (memPos , ) return(memPos, sub(memEnd, memPos)) } @@ -507,13 +507,11 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract) unsigned paramVars = make_shared(type->parameterTypes())->sizeOnStack(); unsigned retVars = make_shared(type->returnParameterTypes())->sizeOnStack(); - templ["assignToParams"] = paramVars == 0 ? "" : "let " + suffixedVariableNameList("param_", 0, paramVars) + " := "; - templ["assignToRetParams"] = retVars == 0 ? "" : "let " + suffixedVariableNameList("ret_", 0, retVars) + " := "; ABIFunctions abiFunctions(m_evmVersion, m_context.revertStrings(), m_context.functionCollector()); templ["abiDecode"] = abiFunctions.tupleDecoder(type->parameterTypes()); templ["params"] = suffixedVariableNameList("param_", 0, paramVars); - templ["retParams"] = suffixedVariableNameList("ret_", retVars, 0); + templ["retParams"] = suffixedVariableNameList("ret_", 0, retVars); if (FunctionDefinition const* funDef = dynamic_cast(&type->declaration())) templ["function"] = m_context.enqueueFunctionForCodeGeneration(*funDef); @@ -524,7 +522,6 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract) templ["allocate"] = m_utils.allocationFunction(); templ["abiEncode"] = abiFunctions.tupleEncoder(type->returnParameterTypes(), type->returnParameterTypes(), false); - templ["comma"] = retVars == 0 ? "" : ", "; } t("cases", functions); if (FunctionDefinition const* fallback = _contract.fallbackFunction()) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 6bfe35395..20023865e 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -742,8 +742,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) { string vars = IRVariable(arg).commaSeparatedList(); if (!vars.empty()) - // In reverse because abi_encode expects it like that. - nonIndexedArgs = ", " + move(vars) + nonIndexedArgs; + nonIndexedArgs += ", " + move(vars); nonIndexedArgTypes.push_back(arg.annotation().type); nonIndexedParamTypes.push_back(paramTypes[i]); } @@ -1023,7 +1022,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) t("releaseTemporaryMemory", m_utils.releaseTemporaryMemoryFunction()); t("object", m_context.creationObjectName(*contract)); t("abiEncode", - m_context.abiFunctions().tupleEncoder(argumentTypes, functionType->parameterTypes(),false) + m_context.abiFunctions().tupleEncoder(argumentTypes, functionType->parameterTypes(), false) ); t("constructorParams", constructorParams); t("value", functionType->valueSet() ? IRVariable(_functionCall.expression()).part("value").name() : "0"); diff --git a/test/cmdlineTests/yul_string_format_ascii/output.json b/test/cmdlineTests/yul_string_format_ascii/output.json index 215146d1d..83511d5d6 100644 --- a/test/cmdlineTests/yul_string_format_ascii/output.json +++ b/test/cmdlineTests/yul_string_format_ascii/output.json @@ -38,7 +38,7 @@ object \"C_10\" { abi_decode_tuple_(4, calldatasize()) let ret_0 := fun_f_9() let memPos := allocateMemory(0) - let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0) + let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0) return(memPos, sub(memEnd, memPos)) } diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json index 7b2291843..69c2091dc 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json @@ -38,7 +38,7 @@ object \"C_10\" { abi_decode_tuple_(4, calldatasize()) let ret_0 := fun_f_9() let memPos := allocateMemory(0) - let memEnd := abi_encode_tuple_t_bytes32__to_t_bytes32__fromStack(memPos , ret_0) + let memEnd := abi_encode_tuple_t_bytes32__to_t_bytes32__fromStack(memPos , ret_0) return(memPos, sub(memEnd, memPos)) } diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json index ef647f39e..8742ef645 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json @@ -38,7 +38,7 @@ object \"C_10\" { abi_decode_tuple_(4, calldatasize()) let ret_0 := fun_f_9() let memPos := allocateMemory(0) - let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0) + let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0) return(memPos, sub(memEnd, memPos)) } diff --git a/test/cmdlineTests/yul_string_format_ascii_long/output.json b/test/cmdlineTests/yul_string_format_ascii_long/output.json index 8243cd93e..4e6b565d0 100644 --- a/test/cmdlineTests/yul_string_format_ascii_long/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_long/output.json @@ -38,7 +38,7 @@ object \"C_10\" { abi_decode_tuple_(4, calldatasize()) let ret_0 := fun_f_9() let memPos := allocateMemory(0) - let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0) + let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0) return(memPos, sub(memEnd, memPos)) } diff --git a/test/cmdlineTests/yul_string_format_hex/output.json b/test/cmdlineTests/yul_string_format_hex/output.json index 70f2fc3de..f98417556 100644 --- a/test/cmdlineTests/yul_string_format_hex/output.json +++ b/test/cmdlineTests/yul_string_format_hex/output.json @@ -38,7 +38,7 @@ object \"C_10\" { abi_decode_tuple_(4, calldatasize()) let ret_0 := fun_f_9() let memPos := allocateMemory(0) - let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0) + let memEnd := abi_encode_tuple_t_bytes4__to_t_bytes4__fromStack(memPos , ret_0) return(memPos, sub(memEnd, memPos)) } diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_static_short_reencode.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_static_short_reencode.sol index d5802d1b1..c777b12fd 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_static_short_reencode.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_static_short_reencode.sol @@ -7,6 +7,8 @@ contract C { return this.f(x); } } +// ==== +// compileViaYul: also // ---- // g(uint256[][2][]): 0x20, 0x01, 0x20, 0x40, 0x60, 0x00, 0x00 -> 42 // g(uint256[][2][]): 0x20, 0x01, 0x20, 0x00, 0x00 -> 42 diff --git a/test/libsolidity/semanticTests/functionTypes/pass_function_types_externally.sol b/test/libsolidity/semanticTests/functionTypes/pass_function_types_externally.sol index ebef9a254..2cb6428f7 100644 --- a/test/libsolidity/semanticTests/functionTypes/pass_function_types_externally.sol +++ b/test/libsolidity/semanticTests/functionTypes/pass_function_types_externally.sol @@ -16,6 +16,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(uint256): 7 -> 8 // f2(uint256): 7 -> 8 From 50e59f10084176c9e797617fcd3c178f12af89ab Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Wed, 6 May 2020 18:26:54 +0200 Subject: [PATCH 31/89] trigger error when runtimeCode is called on contracts with immutables --- Changelog.md | 2 +- libsolidity/analysis/TypeChecker.cpp | 16 +++++++++++++--- .../syntaxTests/immutable/creationCode.sol | 9 +++++++++ .../syntaxTests/immutable/runtimeCode.sol | 11 +++++++++++ .../immutable/runtimeCodeInheritance.sol | 13 +++++++++++++ 5 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 test/libsolidity/syntaxTests/immutable/creationCode.sol create mode 100644 test/libsolidity/syntaxTests/immutable/runtimeCode.sol create mode 100644 test/libsolidity/syntaxTests/immutable/runtimeCodeInheritance.sol diff --git a/Changelog.md b/Changelog.md index 98a0ca408..d17bbadf8 100644 --- a/Changelog.md +++ b/Changelog.md @@ -10,7 +10,7 @@ Compiler Features: Bugfixes: * ABI: Skip ``private`` or ``internal`` constructors. - + * Type Checker: Disallow accessing ``runtimeCode`` for contract types that contain immutable state variables. diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 7277714b8..71b3f3a3c 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -2663,9 +2663,19 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) )) { annotation.isPure = true; - m_scope->annotation().contractDependencies.insert( - &dynamic_cast(*magicType->typeArgument()).contractDefinition() - ); + ContractType const& accessedContractType = dynamic_cast(*magicType->typeArgument()); + m_scope->annotation().contractDependencies.insert(&accessedContractType.contractDefinition()); + + if ( + memberName == "runtimeCode" && + !accessedContractType.immutableVariables().empty() + ) + m_errorReporter.typeError( + 9274_error, + _memberAccess.location(), + "\"runtimeCode\" is not available for contracts containing immutable variables." + ); + if (contractDependenciesAreCyclic(*m_scope)) m_errorReporter.typeError( 4224_error, diff --git a/test/libsolidity/syntaxTests/immutable/creationCode.sol b/test/libsolidity/syntaxTests/immutable/creationCode.sol new file mode 100644 index 000000000..aa747ba3e --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/creationCode.sol @@ -0,0 +1,9 @@ +contract A { + address public immutable user = address(0x0); +} + +contract Test { + function test() public pure returns(bytes memory) { + return type(A).creationCode; + } +} diff --git a/test/libsolidity/syntaxTests/immutable/runtimeCode.sol b/test/libsolidity/syntaxTests/immutable/runtimeCode.sol new file mode 100644 index 000000000..7db3245dc --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/runtimeCode.sol @@ -0,0 +1,11 @@ +contract A { + address public immutable user = address(0x0); +} + +contract Test { + function test() public pure returns(bytes memory) { + return type(A).runtimeCode; + } +} +// ---- +// TypeError: (153-172): "runtimeCode" is not available for contracts containing immutable variables. diff --git a/test/libsolidity/syntaxTests/immutable/runtimeCodeInheritance.sol b/test/libsolidity/syntaxTests/immutable/runtimeCodeInheritance.sol new file mode 100644 index 000000000..aec4acd2e --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/runtimeCodeInheritance.sol @@ -0,0 +1,13 @@ +contract Base { + address public immutable user = address(0x0); +} + +contract Derived is Base {} + +contract Test { + function test() public pure returns(bytes memory) { + return type(Derived).runtimeCode; + } +} +// ---- +// TypeError: (185-210): "runtimeCode" is not available for contracts containing immutable variables. From eb4926cb48be1a2b13d2822f2f6baa0c1b6a46ff Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Tue, 5 May 2020 16:53:30 +0200 Subject: [PATCH 32/89] run addMissingFunctions only once --- Changelog.md | 1 + libsolidity/codegen/Compiler.cpp | 3 ++ libsolidity/codegen/CompilerContext.cpp | 3 ++ libsolidity/codegen/CompilerContext.h | 3 ++ libsolidity/codegen/ContractCompiler.cpp | 5 ++-- .../missing_functions_duplicate_bug.sol | 28 +++++++++++++++++++ 6 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 test/libsolidity/syntaxTests/missing_functions_duplicate_bug.sol diff --git a/Changelog.md b/Changelog.md index d17bbadf8..086e80ee9 100644 --- a/Changelog.md +++ b/Changelog.md @@ -11,6 +11,7 @@ Compiler Features: Bugfixes: * ABI: Skip ``private`` or ``internal`` constructors. * Type Checker: Disallow accessing ``runtimeCode`` for contract types that contain immutable state variables. + * Fixed an "Assembly Exception in Bytecode" error where requested functions were generated twice. diff --git a/libsolidity/codegen/Compiler.cpp b/libsolidity/codegen/Compiler.cpp index 78198fff0..f343f2377 100644 --- a/libsolidity/codegen/Compiler.cpp +++ b/libsolidity/codegen/Compiler.cpp @@ -49,6 +49,9 @@ void Compiler::compileContract( m_runtimeSub = creationCompiler.compileConstructor(_contract, _otherCompilers); m_context.optimise(m_optimiserSettings); + + solAssert(m_context.requestedYulFunctionsRan(), "requestedYulFunctions() was not called."); + solAssert(m_runtimeContext.requestedYulFunctionsRan(), "requestedYulFunctions() was not called."); } std::shared_ptr Compiler::runtimeAssemblyPtr() const diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 2d81e833b..9431ecec6 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -192,6 +192,9 @@ void CompilerContext::appendMissingLowLevelFunctions() pair> CompilerContext::requestedYulFunctions() { + solAssert(!m_requestedYulFunctionsRan, "requestedYulFunctions called more than once."); + m_requestedYulFunctionsRan = true; + set empty; swap(empty, m_externallyUsedYulFunctions); return {m_yulFunctionCollector.requestedFunctions(), std::move(empty)}; diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index 0720a8f3b..51d3afe1c 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -167,6 +167,7 @@ public: /// Clears the internal list, i.e. calling it again will result in an /// empty return value. std::pair> requestedYulFunctions(); + bool requestedYulFunctionsRan() const { return m_requestedYulFunctionsRan; } /// Returns the distance of the given local variable from the bottom of the stack (of the current function). unsigned baseStackOffsetOfVariable(Declaration const& _declaration) const; @@ -389,6 +390,8 @@ private: YulUtilFunctions m_yulUtilFunctions; /// The queue of low-level functions to generate. std::queue>> m_lowLevelFunctionGenerationQueue; + /// Flag to check that requestedYulFunctions() was called exactly once + bool m_requestedYulFunctionsRan = false; }; } diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index d095c1eac..319d7a7ad 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -103,8 +103,6 @@ void ContractCompiler::compileContract( // and adds the function to the compilation queue. Additionally internal functions, // which are referenced directly or indirectly will be added. appendFunctionSelector(_contract); - // This processes the above populated queue until it is empty. - appendMissingFunctions(); } size_t ContractCompiler::compileConstructor( @@ -215,6 +213,9 @@ size_t ContractCompiler::deployLibrary(ContractDefinition const& _contract) solAssert(!!m_runtimeCompiler, ""); solAssert(_contract.isLibrary(), "Tried to deploy contract as library."); + appendMissingFunctions(); + m_runtimeCompiler->appendMissingFunctions(); + CompilerContext::LocationSetter locationSetter(m_context, _contract); solAssert(m_context.runtimeSub() != size_t(-1), "Runtime sub not registered"); diff --git a/test/libsolidity/syntaxTests/missing_functions_duplicate_bug.sol b/test/libsolidity/syntaxTests/missing_functions_duplicate_bug.sol new file mode 100644 index 000000000..c233cd69c --- /dev/null +++ b/test/libsolidity/syntaxTests/missing_functions_duplicate_bug.sol @@ -0,0 +1,28 @@ +pragma solidity ^0.6.0; + +pragma experimental ABIEncoderV2; + +contract Ownable { + address private _owner; + + modifier onlyOwner() { + require(msg.sender == _owner, "Ownable: caller is not the owner"); + _; + } + + function renounceOwnership() public onlyOwner { } +} + +library VoteTiming { + function init(uint phaseLength) internal pure { + require(true, ""); + } +} + +contract Voting is Ownable { + constructor() public { + VoteTiming.init(1); + } +} +// ---- +// Warning: (324-340): Unused function parameter. Remove or comment out the variable name to silence this warning. From 3e9fa7e388628400ec6a0e2c71bc05db93bf3a95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 7 May 2020 17:16:50 +0200 Subject: [PATCH 33/89] yulopti: Print errors to stderr rather than stdout --- test/tools/yulopti.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/tools/yulopti.cpp b/test/tools/yulopti.cpp index de074e642..c61b24c3e 100644 --- a/test/tools/yulopti.cpp +++ b/test/tools/yulopti.cpp @@ -61,7 +61,7 @@ class YulOpti public: void printErrors() { - SourceReferenceFormatter formatter(cout); + SourceReferenceFormatter formatter(cerr); for (auto const& error: m_errors) formatter.printErrorInformation(*error); @@ -74,7 +74,7 @@ public: m_ast = yul::Parser(errorReporter, m_dialect).parse(scanner, false); if (!m_ast || !errorReporter.errors().empty()) { - cout << "Error parsing source." << endl; + cerr << "Error parsing source." << endl; printErrors(); return false; } @@ -86,7 +86,7 @@ public: ); if (!analyzer.analyze(*m_ast) || !errorReporter.errors().empty()) { - cout << "Error analyzing source." << endl; + cerr << "Error analyzing source." << endl; printErrors(); return false; } @@ -182,7 +182,7 @@ public: break; } default: - cout << "Unknown option." << endl; + cerr << "Unknown option." << endl; } source = AsmPrinter{m_dialect}(*m_ast); } From d3d152087086d4d9a29668f646d9efede23b2328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 7 May 2020 17:19:37 +0200 Subject: [PATCH 34/89] yulopti: Add an error message to assetion triggered when an optimizer step abbreviation conflicts with yulopti controls --- test/tools/yulopti.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/tools/yulopti.cpp b/test/tools/yulopti.cpp index c61b24c3e..b6fd3e2ad 100644 --- a/test/tools/yulopti.cpp +++ b/test/tools/yulopti.cpp @@ -119,7 +119,15 @@ public: for (auto const& optionAndDescription: _extraOptions) { - yulAssert(_optimizationSteps.count(optionAndDescription.first) == 0, ""); + yulAssert( + _optimizationSteps.count(optionAndDescription.first) == 0, + "ERROR: Conflict between yulopti controls and Yul optimizer step abbreviations.\n" + "Character '" + string(1, optionAndDescription.first) + "' is assigned to both " + + optionAndDescription.second + " and " + _optimizationSteps.at(optionAndDescription.first) + " step.\n" + "This is most likely caused by someone adding a new step abbreviation to " + "OptimiserSuite::stepNameToAbbreviationMap() and not realizing that it's used by yulopti.\n" + "Please update the code to use a different character and recompile yulopti." + ); printPair(optionAndDescription); } From 156bfadad3747235f000363dbb3821e30b4d2021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 7 May 2020 17:27:24 +0200 Subject: [PATCH 35/89] yulopti: Fix conflict between 'l' in yulopti and OptimiserSuite and make future conflicts less likely - OptimizerSuite uses letters so switching to punctuation marks in yulopti should help. --- test/tools/yulopti.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/tools/yulopti.cpp b/test/tools/yulopti.cpp index b6fd3e2ad..9f5d56085 100644 --- a/test/tools/yulopti.cpp +++ b/test/tools/yulopti.cpp @@ -154,9 +154,9 @@ public: } map const& abbreviationMap = OptimiserSuite::stepAbbreviationToNameMap(); map const& extraOptions = { - {'q', "quit"}, - {'l', "VarNameCleaner"}, - {'p', "StackCompressor"}, + {'#', "quit"}, + {',', "VarNameCleaner"}, + {';', "StackCompressor"}, }; printUsageBanner(abbreviationMap, extraOptions, 4); @@ -175,14 +175,14 @@ public: } else switch (option) { - case 'q': + case '#': return; - case 'l': + case ',': VarNameCleaner::run(context, *m_ast); // VarNameCleaner destroys the unique names guarantee of the disambiguator. disambiguated = false; break; - case 'p': + case ';': { Object obj; obj.code = m_ast; From f38cf85482b9a5bd8aedc5b92ed55f129302e7f6 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 7 May 2020 17:29:42 +0200 Subject: [PATCH 36/89] Use vector of slots. --- libsolidity/codegen/ir/IRGenerator.cpp | 54 +++++++++---------- libsolidity/codegen/ir/IRGenerator.h | 5 +- .../codegen/ir/IRGeneratorForStatements.cpp | 44 +++++++-------- libsolidity/codegen/ir/IRVariable.h | 3 +- .../standard_ir_requested/output.json | 2 +- .../yul_string_format_ascii/output.json | 2 +- .../output.json | 2 +- .../output.json | 2 +- .../yul_string_format_ascii_long/output.json | 2 +- .../yul_string_format_hex/output.json | 2 +- .../constructor_arguments_internal.sol | 2 + 11 files changed, 57 insertions(+), 63 deletions(-) diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index bfd8ce2d1..3211fb4df 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -169,24 +169,24 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function) string functionName = m_context.functionName(_function); return m_context.functionCollector().createFunction(functionName, [&]() { Whiskers t(R"( - function () { + function () -> { } )"); t("functionName", functionName); - string params; + vector params; for (auto const& varDecl: _function.parameters()) - params += (params.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl).commaSeparatedList(); - t("params", params); - string retParams; + params += m_context.addLocalVariable(*varDecl).stackSlots(); + t("params", joinHumanReadable(params)); + vector retParams; string retInit; for (auto const& varDecl: _function.returnParameters()) { - retParams += (retParams.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl).commaSeparatedList(); + retParams += m_context.addLocalVariable(*varDecl).stackSlots(); retInit += generateInitialAssignment(*varDecl); } - t("returns", retParams.empty() ? "" : " -> " + retParams); + t("retParams", joinHumanReadable(retParams)); t("initReturnVariables", retInit); t("body", generate(_function.body())); return t.render(); @@ -300,17 +300,17 @@ string IRGenerator::generateInitialAssignment(VariableDeclaration const& _varDec return generator.code(); } -pair> IRGenerator::evaluateConstructorArguments( +pair>> IRGenerator::evaluateConstructorArguments( ContractDefinition const& _contract ) { - map constructorParams; + map> constructorParams; vector>const *>> baseConstructorArguments; for (ASTPointer const& base: _contract.baseContracts()) if (FunctionDefinition const* baseConstructor = dynamic_cast( base->name().annotation().referencedDeclaration - )->constructor(); baseConstructor && base->arguments()) + )->constructor(); baseConstructor && base->arguments()) baseConstructorArguments.emplace_back( dynamic_cast(baseConstructor->scope()), base->arguments() @@ -338,11 +338,11 @@ pair> IRGenerator::evaluateConstr { vector params; for (size_t i = 0; i < arguments->size(); ++i) - params.emplace_back(generator.evaluateExpression( - *(arguments->at(i)), - *(baseContract->constructor()->parameters()[i]->type()) - ).commaSeparatedList()); - constructorParams[baseContract] = joinHumanReadable(params); + params += generator.evaluateExpression( + *(arguments->at(i)), + *(baseContract->constructor()->parameters()[i]->type()) + ).stackSlots(); + constructorParams[baseContract] = std::move(params); } } @@ -363,16 +363,16 @@ string IRGenerator::initStateVariables(ContractDefinition const& _contract) void IRGenerator::generateImplicitConstructors(ContractDefinition const& _contract) { auto listAllParams = [&]( - map const& baseParams) -> string + map> const& baseParams) -> vector { vector params; for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts) if (baseParams.count(contract)) - params.emplace_back(baseParams.at(contract)); - return joinHumanReadable(params); + params += baseParams.at(contract); + return params; }; - map baseConstructorParams; + map> baseConstructorParams; for (size_t i = 0; i < _contract.annotation().linearizedBaseContracts.size(); ++i) { ContractDefinition const* contract = _contract.annotation().linearizedBaseContracts[i]; @@ -387,16 +387,16 @@ void IRGenerator::generateImplicitConstructors(ContractDefinition const& _contra } )"); - string params; + vector params; if (contract->constructor()) for (ASTPointer const& varDecl: contract->constructor()->parameters()) - params += (params.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl).commaSeparatedList(); - t("params", params); - string baseParamsString = listAllParams(baseConstructorParams); - t("baseParams", baseParamsString); - t("comma", !params.empty() && !baseParamsString.empty() ? ", " : ""); + params += m_context.addLocalVariable(*varDecl).stackSlots(); + t("params", joinHumanReadable(params)); + vector baseParams = listAllParams(baseConstructorParams); + t("baseParams", joinHumanReadable(baseParams)); + t("comma", !params.empty() && !baseParams.empty() ? ", " : ""); t("functionName", implicitConstructorName(*contract)); - pair> evaluatedArgs = evaluateConstructorArguments(*contract); + pair>> evaluatedArgs = evaluateConstructorArguments(*contract); baseConstructorParams.insert(evaluatedArgs.second.begin(), evaluatedArgs.second.end()); t("evalBaseArguments", evaluatedArgs.first); if (i < _contract.annotation().linearizedBaseContracts.size() - 1) @@ -404,7 +404,7 @@ void IRGenerator::generateImplicitConstructors(ContractDefinition const& _contra t("hasNextConstructor", true); ContractDefinition const* nextContract = _contract.annotation().linearizedBaseContracts[i + 1]; t("nextConstructor", implicitConstructorName(*nextContract)); - t("nextParams", listAllParams(baseConstructorParams)); + t("nextParams", joinHumanReadable(listAllParams(baseConstructorParams))); } else t("hasNextConstructor", false); diff --git a/libsolidity/codegen/ir/IRGenerator.h b/libsolidity/codegen/ir/IRGenerator.h index a4298a902..642cfcdfb 100644 --- a/libsolidity/codegen/ir/IRGenerator.h +++ b/libsolidity/codegen/ir/IRGenerator.h @@ -81,9 +81,8 @@ private: /// Evaluates constructor's arguments for all base contracts (listed in inheritance specifiers) of /// @a _contract /// @returns Pair of expressions needed to evaluate params and list of parameters in a map contract -> params - std::pair> evaluateConstructorArguments( - ContractDefinition const& _contract - ); + std::pair>> + evaluateConstructorArguments(ContractDefinition const& _contract); /// Initializes state variables of /// @a _contract diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 10761fd35..7415a0977 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -637,13 +637,6 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) break; case FunctionType::Kind::Internal: { - vector args; - for (size_t i = 0; i < arguments.size(); ++i) - if (functionType->takesArbitraryParameters()) - args.emplace_back(IRVariable(*arguments[i]).commaSeparatedList()); - else - args.emplace_back(convert(*arguments[i], *parameterTypes[i]).commaSeparatedList()); - optional functionDef; if (auto memberAccess = dynamic_cast(&_functionCall.expression())) { @@ -681,6 +674,13 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) solAssert(functionDef.has_value(), ""); solAssert(functionDef.value() == nullptr || functionDef.value()->isImplemented(), ""); + vector args; + for (size_t i = 0; i < arguments.size(); ++i) + if (functionType->takesArbitraryParameters()) + args += IRVariable(*arguments[i]).stackSlots(); + else + args += convert(*arguments[i], *parameterTypes[i]).stackSlots(); + if (functionDef.value() != nullptr) define(_functionCall) << m_context.enqueueFunctionForCodeGeneration(*functionDef.value()) << @@ -716,7 +716,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) ABIFunctions abi(m_context.evmVersion(), m_context.revertStrings(), m_context.functionCollector()); vector indexedArgs; - string nonIndexedArgs; + vector nonIndexedArgs; TypePointers nonIndexedArgTypes; TypePointers nonIndexedParamTypes; if (!event.isAnonymous()) @@ -739,9 +739,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) } else { - string vars = IRVariable(arg).commaSeparatedList(); - if (!vars.empty()) - nonIndexedArgs += ", " + move(vars); + nonIndexedArgs += IRVariable(arg).stackSlots(); nonIndexedArgTypes.push_back(arg.annotation().type); nonIndexedParamTypes.push_back(paramTypes[i]); } @@ -756,7 +754,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) templ("end", m_context.newYulVariable()); templ("freeMemory", freeMemory()); templ("encode", abi.tupleEncoder(nonIndexedArgTypes, nonIndexedParamTypes)); - templ("nonIndexedArgs", nonIndexedArgs); + templ("nonIndexedArgs", joinHumanReadablePrefixed(nonIndexedArgs)); templ("log", "log" + to_string(indexedArgs.size())); templ("indexedArgs", joinHumanReadablePrefixed(indexedArgs | boost::adaptors::transformed([&](auto const& _arg) { return _arg.commaSeparatedList(); @@ -813,8 +811,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) templ("allocateTemporary", m_utils.allocationTemporaryMemoryFunction()); templ( "argumentVars", - (type(*arguments.front()).sizeOnStack() > 0 ? ", " : "") + - IRVariable{*arguments.front()}.commaSeparatedList() + joinHumanReadablePrefixed(IRVariable{*arguments.front()}.stackSlots()) ); templ("encode", m_context.abiFunctions().tupleEncoder( {&type(*arguments.front())}, @@ -991,11 +988,11 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) ); TypePointers argumentTypes; - string constructorParams; + vector constructorParams; for (ASTPointer const& arg: arguments) { argumentTypes.push_back(arg->annotation().type); - constructorParams += ", " + IRVariable{*arg}.commaSeparatedList(); + constructorParams += IRVariable{*arg}.stackSlots(); } ContractDefinition const* contract = @@ -1023,7 +1020,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) t("abiEncode", m_context.abiFunctions().tupleEncoder(argumentTypes, functionType->parameterTypes(), false) ); - t("constructorParams", constructorParams); + t("constructorParams", joinHumanReadablePrefixed(constructorParams)); t("value", functionType->valueSet() ? IRVariable(_functionCall.expression()).part("value").name() : "0"); t("saltSet", functionType->saltSet()); if (functionType->saltSet()) @@ -1398,14 +1395,11 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess) solAssert(keyType.sizeOnStack() <= 1, ""); string slot = m_context.newYulVariable(); - Whiskers templ("let := ( )\n"); + Whiskers templ("let := (,)\n"); templ("slot", slot); templ("indexAccess", m_utils.mappingIndexAccessFunction(mappingType, keyType)); templ("base", IRVariable(_indexAccess.baseExpression()).commaSeparatedList()); - if (keyType.sizeOnStack() == 0) - templ("key", ""); - else - templ("key", ", " + IRVariable(*_indexAccess.indexExpression()).commaSeparatedList()); + templ("key", IRVariable(*_indexAccess.indexExpression()).commaSeparatedList()); m_code << templ.render(); setLValue(_indexAccess, IRLValue{ *_indexAccess.annotation().type, @@ -1678,10 +1672,8 @@ void IRGeneratorForStatements::appendExternalFunctionCall( for (auto const& arg: _arguments) { argumentTypes.emplace_back(&type(*arg)); - if (IRVariable(*arg).type().sizeOnStack() > 0) - argumentStrings.emplace_back(IRVariable(*arg).commaSeparatedList()); + argumentStrings += IRVariable(*arg).stackSlots(); } - string argumentString = argumentStrings.empty() ? ""s : (", " + joinHumanReadable(argumentStrings)); solUnimplementedAssert(funKind != FunctionType::Kind::ECRecover, ""); @@ -1796,7 +1788,7 @@ void IRGeneratorForStatements::appendExternalFunctionCall( } else templ("encodeArgs", abi.tupleEncoder(argumentTypes, funType.parameterTypes(), encodeForLibraryCall)); - templ("argumentString", argumentString); + templ("argumentString", joinHumanReadablePrefixed(argumentStrings)); // Output data will replace input data, unless we have ECRecover (then, output // area will be 32 bytes just before input area). diff --git a/libsolidity/codegen/ir/IRVariable.h b/libsolidity/codegen/ir/IRVariable.h index ba4b1b93a..dbf37704c 100644 --- a/libsolidity/codegen/ir/IRVariable.h +++ b/libsolidity/codegen/ir/IRVariable.h @@ -69,10 +69,11 @@ public: /// The returned IRVariable is itself typed with the type of the stack slot as defined /// in ``m_type.stackItems()`` and may again occupy multiple stack slots. IRVariable part(std::string const& _slot) const; -private: + /// @returns a vector containing the names of the stack slots of the variable. std::vector stackSlots() const; +private: /// @returns a name consisting of the base name appended with an underscore and @æ _suffix, /// unless @a _suffix is empty, in which case the base name itself is returned. std::string suffixedName(std::string const& _suffix) const; diff --git a/test/cmdlineTests/standard_ir_requested/output.json b/test/cmdlineTests/standard_ir_requested/output.json index 69b95a683..f63075090 100644 --- a/test/cmdlineTests/standard_ir_requested/output.json +++ b/test/cmdlineTests/standard_ir_requested/output.json @@ -65,7 +65,7 @@ object \"C_6\" { mstore(64, newFreePtr) } - function fun_f_5() { + function fun_f_5() { } diff --git a/test/cmdlineTests/yul_string_format_ascii/output.json b/test/cmdlineTests/yul_string_format_ascii/output.json index 83511d5d6..0609704c5 100644 --- a/test/cmdlineTests/yul_string_format_ascii/output.json +++ b/test/cmdlineTests/yul_string_format_ascii/output.json @@ -107,7 +107,7 @@ object \"C_10\" { } } - function fun_f_9() -> vloc__4_mpos { + function fun_f_9() -> vloc__4_mpos { let zero_value_for_type_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr() vloc__4_mpos := zero_value_for_type_t_string_memory_ptr_1_mpos diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json index 69c2091dc..1bc00b338 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json @@ -79,7 +79,7 @@ object \"C_10\" { converted := 0x6162636162630000000000000000000000000000000000000000000000000000 } - function fun_f_9() -> vloc__4 { + function fun_f_9() -> vloc__4 { let zero_value_for_type_t_bytes32_1 := zero_value_for_split_t_bytes32() vloc__4 := zero_value_for_type_t_bytes32_1 diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json index 8742ef645..fdef77781 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json @@ -83,7 +83,7 @@ object \"C_10\" { converted := shift_left_224(cleanup_t_rational_1633837924_by_1(value)) } - function fun_f_9() -> vloc__4 { + function fun_f_9() -> vloc__4 { let zero_value_for_type_t_bytes4_1 := zero_value_for_split_t_bytes4() vloc__4 := zero_value_for_type_t_bytes4_1 diff --git a/test/cmdlineTests/yul_string_format_ascii_long/output.json b/test/cmdlineTests/yul_string_format_ascii_long/output.json index 4e6b565d0..2a845796d 100644 --- a/test/cmdlineTests/yul_string_format_ascii_long/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_long/output.json @@ -111,7 +111,7 @@ object \"C_10\" { } } - function fun_f_9() -> vloc__4_mpos { + function fun_f_9() -> vloc__4_mpos { let zero_value_for_type_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr() vloc__4_mpos := zero_value_for_type_t_string_memory_ptr_1_mpos diff --git a/test/cmdlineTests/yul_string_format_hex/output.json b/test/cmdlineTests/yul_string_format_hex/output.json index f98417556..784baf2f4 100644 --- a/test/cmdlineTests/yul_string_format_hex/output.json +++ b/test/cmdlineTests/yul_string_format_hex/output.json @@ -83,7 +83,7 @@ object \"C_10\" { converted := shift_left_224(cleanup_t_rational_2864434397_by_1(value)) } - function fun_f_9() -> vloc__4 { + function fun_f_9() -> vloc__4 { let zero_value_for_type_t_bytes4_1 := zero_value_for_split_t_bytes4() vloc__4 := zero_value_for_type_t_bytes4_1 diff --git a/test/libsolidity/semanticTests/constructor/constructor_arguments_internal.sol b/test/libsolidity/semanticTests/constructor/constructor_arguments_internal.sol index 756478e34..b29498083 100644 --- a/test/libsolidity/semanticTests/constructor/constructor_arguments_internal.sol +++ b/test/libsolidity/semanticTests/constructor/constructor_arguments_internal.sol @@ -33,6 +33,8 @@ contract Main { } } +// ==== +// compileViaYul: also // ---- // getFlag() -> true // getName() -> "abc" From 75ca072ae6861ce7446a502ef984672f8a040c16 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 7 May 2020 18:18:40 +0200 Subject: [PATCH 37/89] Assertion about getters for non-value type immutables. --- libsolidity/codegen/ir/IRGenerator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index bfd8ce2d1..e5d14d57e 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -203,7 +203,7 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) if (auto const* mappingType = dynamic_cast(type)) return m_context.functionCollector().createFunction(functionName, [&]() { - solAssert(!_varDecl.isConstant(), ""); + solAssert(!_varDecl.isConstant() && !_varDecl.immutable(), ""); pair slot_offset = m_context.storageLocationOfVariable(_varDecl); solAssert(slot_offset.second == 0, ""); FunctionType funType(_varDecl); From a0e291bd06c7db80dd29d18b01319caf8f3e66d2 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 29 Apr 2020 11:29:49 +0200 Subject: [PATCH 38/89] Implement Yul IR generation for abi.encode* --- .../codegen/ir/IRGeneratorForStatements.cpp | 89 +++++++++++++++++++ libsolidity/codegen/ir/IRVariable.cpp | 2 +- .../semanticTests/abiEncoderV1/abi_encode.sol | 2 + .../abiEncoderV1/abi_encode_rational.sol | 2 + .../abi_encode_empty_string_v2.sol | 2 + .../abiEncoderV2/abi_encode_rational_v2.sol | 2 + .../abiEncoderV2/calldata_array_dynamic.sol | 1 + .../calldata_array_dynamic_index_access.sol | 1 + .../calldata_array_multi_dynamic.sol | 1 + .../abiEncoderV2/calldata_array_static.sol | 1 + .../calldata_array_static_index_access.sol | 1 + .../calldata_array_struct_dynamic.sol | 1 + .../calldata_array_two_dynamic.sol | 1 + .../calldata_array_two_static.sol | 1 + .../abiEncoderV2/calldata_struct_dynamic.sol | 1 + .../abiEncoderV2/calldata_struct_simple.sol | 1 + .../semanticTests/array/reusing_memory.sol | 2 + .../keccak256_multiple_arguments.sol | 2 + ...ltiple_arguments_with_numeric_literals.sol | 2 + ...ultiple_arguments_with_string_literals.sol | 2 + .../tryCatch/invalid_error_encoding.sol | 1 + 21 files changed, 117 insertions(+), 1 deletion(-) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 7415a0977..05cfcc2db 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -781,6 +781,94 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) break; } + case FunctionType::Kind::ABIEncode: + case FunctionType::Kind::ABIEncodePacked: + case FunctionType::Kind::ABIEncodeWithSelector: + case FunctionType::Kind::ABIEncodeWithSignature: + { + bool const isPacked = functionType->kind() == FunctionType::Kind::ABIEncodePacked; + solAssert(functionType->padArguments() != isPacked, ""); + bool const hasSelectorOrSignature = + functionType->kind() == FunctionType::Kind::ABIEncodeWithSelector || + functionType->kind() == FunctionType::Kind::ABIEncodeWithSignature; + + TypePointers argumentTypes; + TypePointers targetTypes; + vector argumentVars; + for (size_t i = 0; i < arguments.size(); ++i) + { + // ignore selector + if (hasSelectorOrSignature && i == 0) + continue; + argumentTypes.emplace_back(&type(*arguments[i])); + targetTypes.emplace_back(type(*arguments[i]).fullEncodingType(false, true, isPacked)); + argumentVars += IRVariable(*arguments[i]).stackSlots(); + } + + string selector; + if (functionType->kind() == FunctionType::Kind::ABIEncodeWithSignature) + { + // hash the signature + Type const& selectorType = type(*arguments.front()); + if (auto const* stringType = dynamic_cast(&selectorType)) + { + FixedHash<4> hash(keccak256(stringType->value())); + selector = formatNumber(u256(FixedHash<4>::Arith(hash)) << (256 - 32)); + } + else + { + // Used to reset the free memory pointer later. + string freeMemoryPre = m_context.newYulVariable(); + m_code << "let " << freeMemoryPre << " := " << freeMemory() << "\n"; + IRVariable array = convert(*arguments[0], *TypeProvider::bytesMemory()); + IRVariable hashVariable(m_context.newYulVariable(), *TypeProvider::fixedBytes(32)); + + define(hashVariable) << + "keccak256(" << + m_utils.arrayDataAreaFunction(*TypeProvider::bytesMemory()) << + "(" << + array.commaSeparatedList() << + "), " << + m_utils.arrayLengthFunction(*TypeProvider::bytesMemory()) << + "(" << + array.commaSeparatedList() << + "))\n"; + IRVariable selectorVariable(m_context.newYulVariable(), *TypeProvider::fixedBytes(4)); + define(selectorVariable, hashVariable); + m_code << "mstore(" << to_string(CompilerUtils::freeMemoryPointer) << ", " << freeMemoryPre << ")\n"; + } + } + else if (functionType->kind() == FunctionType::Kind::ABIEncodeWithSelector) + selector = convert(*arguments.front(), *TypeProvider::fixedBytes(4)).name(); + + Whiskers templ(R"( + let := () + let := add(, 0x20) + + mstore(, ) + := add(, 4) + + let := () + mstore(, sub(, add(, 0x20))) + mstore(, ()) + )"); + templ("data", IRVariable(_functionCall).part("mpos").name()); + templ("allocateTemporary", m_utils.allocationTemporaryMemoryFunction()); + templ("mpos", m_context.newYulVariable()); + templ("mend", m_context.newYulVariable()); + templ("selector", selector); + templ("encode", + isPacked ? + m_context.abiFunctions().tupleEncoderPacked(argumentTypes, targetTypes) : + m_context.abiFunctions().tupleEncoder(argumentTypes, targetTypes, false) + ); + templ("arguments", joinHumanReadablePrefixed(argumentVars)); + templ("freeMemPtr", to_string(CompilerUtils::freeMemoryPointer)); + templ("roundUp", m_utils.roundUpFunction()); + + m_code << templ.render(); + break; + } case FunctionType::Kind::Revert: { solAssert(arguments.size() == parameterTypes.size(), ""); @@ -843,6 +931,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) solAssert(arguments.size() == 1, ""); ArrayType const* arrayType = TypeProvider::bytesMemory(); + auto array = convert(*arguments[0], *arrayType); define(_functionCall) << diff --git a/libsolidity/codegen/ir/IRVariable.cpp b/libsolidity/codegen/ir/IRVariable.cpp index dac1087f0..d92a5fb53 100644 --- a/libsolidity/codegen/ir/IRVariable.cpp +++ b/libsolidity/codegen/ir/IRVariable.cpp @@ -89,7 +89,7 @@ string IRVariable::name() const { solAssert(m_type.sizeOnStack() == 1, ""); auto const& [itemName, type] = m_type.stackItems().front(); - solAssert(!type, ""); + solAssert(!type, "Expected null type for name " + itemName); return suffixedName(itemName); } diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_encode.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode.sol index ac17cf80e..61c6658ac 100644 --- a/test/libsolidity/semanticTests/abiEncoderV1/abi_encode.sol +++ b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode.sol @@ -28,6 +28,8 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f0() -> 0x20, 0x0 // f1() -> 0x20, 0x40, 0x1, 0x2 diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_rational.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_rational.sol index 704fd54dc..133645cff 100644 --- a/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_rational.sol +++ b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_rational.sol @@ -5,5 +5,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> 0x20, 0x40, 0x1, -2 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_empty_string_v2.sol b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_empty_string_v2.sol index 373334ee7..405d34c5a 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_empty_string_v2.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_empty_string_v2.sol @@ -9,5 +9,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> 0x40, 0xa0, 0x40, 0x20, 0x0, 0x0 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_rational_v2.sol b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_rational_v2.sol index 55047880a..1074a1d04 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_rational_v2.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_rational_v2.sol @@ -8,5 +8,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> 0x20, 0x40, 0x1, -2 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic.sol index b2076b370..c47af87f4 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic.sol @@ -21,6 +21,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >homestead // ---- // f(uint256[]): 32, 3, 23, 42, 87 -> 32, 160, 32, 3, 23, 42, 87 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_index_access.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_index_access.sol index f2224c803..92067f8db 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_index_access.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_dynamic_index_access.sol @@ -21,6 +21,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >homestead // ---- // f(uint256[]): 32, 3, 42, 23, 87 -> 32, 160, 32, 3, 42, 23, 87 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_multi_dynamic.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_multi_dynamic.sol index f981a6e46..f50f59d1f 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_multi_dynamic.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_multi_dynamic.sol @@ -21,6 +21,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >homestead // ---- // f(uint256[][]): 0x20, 2, 0x40, 0xC0, 3, 13, 17, 23, 4, 27, 31, 37, 41 -> 32, 416, 32, 2, 64, 192, 3, 13, 17, 23, 4, 27, 31, 37, 41 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static.sol index 9c6386e31..3a6fd9151 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static.sol @@ -15,6 +15,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >homestead // ---- // f(uint256[3]): 23, 42, 87 -> 32, 96, 23, 42, 87 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static_index_access.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static_index_access.sol index 4bf181db3..d23dfecfb 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static_index_access.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_static_index_access.sol @@ -15,6 +15,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >homestead // ---- // f(uint256[3]): 23, 42, 87 -> 32, 96, 23, 42, 87 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_struct_dynamic.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_struct_dynamic.sol index 02322d504..ce2f7a390 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_struct_dynamic.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_struct_dynamic.sol @@ -10,6 +10,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >homestead // ---- // f((uint256[])[]): 32, 1, 32, 32, 3, 17, 42, 23 -> 32, 256, 32, 1, 32, 32, 3, 17, 42, 23 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_two_dynamic.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_two_dynamic.sol index 16ba40630..51674081e 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_two_dynamic.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_two_dynamic.sol @@ -12,6 +12,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >homestead // ---- // f(uint256[],uint256[],bool): 0x60, 0xE0, true, 3, 23, 42, 87, 2, 51, 72 -> 32, 160, 0x20, 3, 23, 42, 87 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_two_static.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_two_static.sol index a4d1af66d..45a89c483 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_two_static.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array_two_static.sol @@ -12,6 +12,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >homestead // ---- // f(uint256[3],uint256[2],bool): 23, 42, 87, 51, 72, true -> 32, 96, 23, 42, 87 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_struct_dynamic.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_struct_dynamic.sol index 29ff15692..0ae57dbed 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_struct_dynamic.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_struct_dynamic.sol @@ -12,6 +12,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >homestead // ---- // f((uint256[])): 0x20, 0x20, 3, 42, 23, 17 -> 32, 192, 0x20, 0x20, 3, 42, 23, 17 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_struct_simple.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_struct_simple.sol index f369321c3..6d747fdf0 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_struct_simple.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_struct_simple.sol @@ -12,6 +12,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >homestead // ---- // f((uint256)): 3 -> 32, 32, 3 diff --git a/test/libsolidity/semanticTests/array/reusing_memory.sol b/test/libsolidity/semanticTests/array/reusing_memory.sol index b2876eeb3..994a31db9 100644 --- a/test/libsolidity/semanticTests/array/reusing_memory.sol +++ b/test/libsolidity/semanticTests/array/reusing_memory.sol @@ -22,5 +22,7 @@ contract Main { return map[a]; } } +// ==== +// compileViaYul: also // ---- // f(uint256): 0x34 -> 0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 diff --git a/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments.sol b/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments.sol index 972aee839..4a31c6715 100644 --- a/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments.sol +++ b/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments.sol @@ -3,5 +3,7 @@ contract c { d = keccak256(abi.encodePacked(a, b, c)); } } +// ==== +// compileViaYul: also // ---- // foo(uint256,uint256,uint256): 0xa, 0xc, 0xd -> 0xbc740a98aae5923e8f04c9aa798c9ee82f69e319997699f2782c40828db9fd81 diff --git a/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments_with_numeric_literals.sol b/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments_with_numeric_literals.sol index 01397f55f..958975966 100644 --- a/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments_with_numeric_literals.sol +++ b/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments_with_numeric_literals.sol @@ -3,5 +3,7 @@ contract c { d = keccak256(abi.encodePacked(a, b, uint8(145))); } } +// ==== +// compileViaYul: also // ---- // foo(uint256,uint16): 0xa, 0xc -> 0x88acd45f75907e7c560318bc1a5249850a0999c4896717b1167d05d116e6dbad diff --git a/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments_with_string_literals.sol b/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments_with_string_literals.sol index b157178fb..c4e0b7d09 100644 --- a/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments_with_string_literals.sol +++ b/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments_with_string_literals.sol @@ -7,6 +7,8 @@ contract c { d = keccak256(abi.encodePacked(a, b, uint8(145), "foo")); } } +// ==== +// compileViaYul: also // ---- // foo() -> 0x41b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d // bar(uint256,uint16): 0xa, 0xc -> 0x6990f36476dc412b1c4baa48e2d9f4aa4bb313f61fda367c8fdbbb2232dc6146 diff --git a/test/libsolidity/semanticTests/tryCatch/invalid_error_encoding.sol b/test/libsolidity/semanticTests/tryCatch/invalid_error_encoding.sol index 2bfc23191..1b89213cf 100644 --- a/test/libsolidity/semanticTests/tryCatch/invalid_error_encoding.sol +++ b/test/libsolidity/semanticTests/tryCatch/invalid_error_encoding.sol @@ -149,6 +149,7 @@ contract C { } // ==== // EVMVersion: >=byzantium +// compileViaYul: also // ---- // f1() -> 2 // f1a() -> 2 From 704b334cf69139ba067e54c62a6e45da212a3d18 Mon Sep 17 00:00:00 2001 From: Harikrishnan Mulackal Date: Wed, 6 May 2020 19:27:22 +0530 Subject: [PATCH 39/89] Updated external test repos --- test/externalTests/colony.sh | 4 ++-- test/externalTests/gnosis.sh | 5 ++--- test/externalTests/zeppelin.sh | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/test/externalTests/colony.sh b/test/externalTests/colony.sh index 66231eb99..559703ae7 100755 --- a/test/externalTests/colony.sh +++ b/test/externalTests/colony.sh @@ -34,12 +34,12 @@ function colony_test FORCE_ABIv2=false CONFIG="truffle.js" - truffle_setup https://github.com/erak/colonyNetwork.git develop_060 + truffle_setup https://github.com/solidity-external-tests/colonyNetwork.git develop_060 run_install install_fn cd lib rm -Rf dappsys - git clone https://github.com/erak/dappsys-monolithic.git -b master_060 dappsys + git clone https://github.com/solidity-external-tests/dappsys-monolithic.git -b master_060 dappsys cd .. truffle_run_test compile_fn test_fn diff --git a/test/externalTests/gnosis.sh b/test/externalTests/gnosis.sh index b2bb657cb..b78877211 100755 --- a/test/externalTests/gnosis.sh +++ b/test/externalTests/gnosis.sh @@ -33,10 +33,10 @@ function gnosis_safe_test OPTIMIZER_LEVEL=1 CONFIG="truffle.js" - truffle_setup https://github.com/erak/safe-contracts.git development_060 + truffle_setup https://github.com/solidity-external-tests/safe-contracts.git development_060 force_truffle_version - sed -i 's|github:gnosis/mock-contract#sol_0_5_0|github:erak/mock-contract#master_060|g' package.json + sed -i 's|github:gnosis/mock-contract#sol_0_5_0|github:solidity-external-tests/mock-contract#master_060|g' package.json run_install install_fn replace_libsolc_call @@ -45,4 +45,3 @@ function gnosis_safe_test } external_test Gnosis-Safe gnosis_safe_test - diff --git a/test/externalTests/zeppelin.sh b/test/externalTests/zeppelin.sh index 49b6c3e42..7c82cd281 100755 --- a/test/externalTests/zeppelin.sh +++ b/test/externalTests/zeppelin.sh @@ -33,7 +33,7 @@ function zeppelin_test OPTIMIZER_LEVEL=1 CONFIG="truffle-config.js" - truffle_setup https://github.com/erak/openzeppelin-contracts.git master_060 + truffle_setup https://github.com/OpenZeppelin/openzeppelin-contracts.git master run_install install_fn truffle_run_test compile_fn test_fn From f56fd5bde8c5b0e3ed7d2d13ce2e6ccac5064da4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 8 May 2020 19:40:54 +0200 Subject: [PATCH 40/89] cmdlineTests.sh: Allow using input.yul instead of input.sol in command-line tests --- test/cmdlineTests.sh | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index 077aa5c19..07e249492 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -245,7 +245,18 @@ printTask "Running general commandline tests..." stdoutExpectationFile="${tdir}/output.json" args="--standard-json "$(cat ${tdir}/args 2>/dev/null || true) else - inputFile="${tdir}input.sol" + if [[ -e "${tdir}input.yul" && -e "${tdir}input.sol" ]] + then + printError "Ambiguous input. Found both input.sol and input.yul." + exit 1 + fi + + if [ -e "${tdir}input.yul" ] + then + inputFile="${tdir}input.yul" + else + inputFile="${tdir}input.sol" + fi stdin="" stdout="$(cat ${tdir}/output 2>/dev/null || true)" stdoutExpectationFile="${tdir}/output" From d932c58b56cb03a4427f89c1236ee39ff7cebc84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 8 May 2020 15:54:17 +0200 Subject: [PATCH 41/89] CommandLineInterface: Replace hard-coded option names with constants where available --- solc/CommandLineInterface.cpp | 50 ++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 537b2096b..0166a5df6 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -699,7 +699,7 @@ void CommandLineInterface::createFile(string const& _fileName, string const& _da string pathName = (p / _fileName).string(); if (fs::exists(pathName) && !m_args.count(g_strOverwrite)) { - serr() << "Refusing to overwrite existing file \"" << pathName << "\" (use --overwrite to force)." << endl; + serr() << "Refusing to overwrite existing file \"" << pathName << "\" (use --" << g_strOverwrite << " to force)." << endl; m_error = true; return; } @@ -719,10 +719,10 @@ bool CommandLineInterface::parseArguments(int _argc, char** _argv) g_hasOutput = false; // Declare the supported options. - po::options_description desc(R"(solc, the Solidity commandline compiler. + po::options_description desc((R"(solc, the Solidity commandline compiler. This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you -are welcome to redistribute it under certain conditions. See 'solc --license' +are welcome to redistribute it under certain conditions. See 'solc --)" + g_strLicense + R"(' for details. Usage: solc [options] [input_file...] @@ -732,9 +732,9 @@ at standard output or in files in the output directory, if specified. Imports are automatically read from the filesystem, but it is also possible to remap paths using the context:prefix=path syntax. Example: -solc --bin -o /tmp/solcoutput dapp-bin=/usr/local/lib/dapp-bin contract.sol +solc --)" + g_argBinary + R"( -o /tmp/solcoutput dapp-bin=/usr/local/lib/dapp-bin contract.sol -Allowed options)", +Allowed options)").c_str(), po::options_description::m_default_line_length, po::options_description::m_default_line_length - 23 ); @@ -780,20 +780,27 @@ Allowed options)", ) ( g_argImportAst.c_str(), - "Import ASTs to be compiled, assumes input holds the AST in compact JSON format. " - "Supported Inputs is the output of the --standard-json or the one produced by --combined-json ast,compact-format" + ("Import ASTs to be compiled, assumes input holds the AST in compact JSON format. " + "Supported Inputs is the output of the --" + g_argStandardJSON + " or the one produced by " + "--" + g_argCombinedJson + " " + g_strAst + "," + g_strCompactJSON).c_str() ) ( g_argAssemble.c_str(), - "Switch to assembly mode, ignoring all options except --machine, --yul-dialect and --optimize and assumes input is assembly." + ("Switch to assembly mode, ignoring all options except " + "--" + g_argMachine + ", --" + g_strYulDialect + " and --" + g_argOptimize + " " + "and assumes input is assembly.").c_str() ) ( g_argYul.c_str(), - "Switch to Yul mode, ignoring all options except --machine, --yul-dialect and --optimize and assumes input is Yul." + ("Switch to Yul mode, ignoring all options except " + "--" + g_argMachine + ", --" + g_strYulDialect + " and --" + g_argOptimize + " " + "and assumes input is Yul.").c_str() ) ( g_argStrictAssembly.c_str(), - "Switch to strict assembly mode, ignoring all options except --machine, --yul-dialect and --optimize and assumes input is strict assembly." + ("Switch to strict assembly mode, ignoring all options except " + "--" + g_argMachine + ", --" + g_strYulDialect + " and --" + g_argOptimize + " " + "and assumes input is strict assembly.").c_str() ) ( g_strYulDialect.c_str(), @@ -807,8 +814,8 @@ Allowed options)", ) ( g_argLink.c_str(), - "Switch to linker mode, ignoring all options apart from --libraries " - "and modify binaries in place." + ("Switch to linker mode, ignoring all options apart from --" + g_argLibraries + " " + "and modify binaries in place.").c_str() ) ( g_argMetadataHash.c_str(), @@ -835,7 +842,7 @@ Allowed options)", "Set for how many contract runs to optimize. " "Lower values will optimize more for initial deployment cost, higher values will optimize more for high-frequency usage." ) - (g_strOptimizeYul.c_str(), "Legacy option, ignored. Use the general --optimize to enable Yul optimizer.") + (g_strOptimizeYul.c_str(), ("Legacy option, ignored. Use the general --" + g_argOptimize + " to enable Yul optimizer.").c_str()) (g_strNoOptimizeYul.c_str(), "Disable Yul optimizer in Solidity.") ( g_strYulOptimizations.c_str(), @@ -933,7 +940,7 @@ Allowed options)", for (string const& item: boost::split(requests, m_args[g_argCombinedJson].as(), boost::is_any_of(","))) if (!g_combinedJsonArgs.count(item)) { - serr() << "Invalid option to --combined-json: " << item << endl; + serr() << "Invalid option to --" << g_argCombinedJson << ": " << item << endl; return false; } } @@ -1047,7 +1054,7 @@ bool CommandLineInterface::processInput() std::optional versionOption = langutil::EVMVersion::fromString(versionOptionStr); if (!versionOption) { - serr() << "Invalid option for --evm-version: " << versionOptionStr << endl; + serr() << "Invalid option for --" << g_strEVMVersion << ": " << versionOptionStr << endl; return false; } m_evmVersion = *versionOption; @@ -1064,12 +1071,12 @@ bool CommandLineInterface::processInput() bool optimize = m_args.count(g_argOptimize); if (m_args.count(g_strOptimizeYul)) { - serr() << "--optimize-yul is invalid in assembly mode. Use --optimize instead." << endl; + serr() << "--" << g_strOptimizeYul << " is invalid in assembly mode. Use --" << g_argOptimize << " instead." << endl; return false; } if (m_args.count(g_strNoOptimizeYul)) { - serr() << "--no-optimize-yul is invalid in assembly mode. Optimization is disabled by default and can be enabled with --optimize." << endl; + serr() << "--" << g_strNoOptimizeYul << " is invalid in assembly mode. Optimization is disabled by default and can be enabled with --" << g_argOptimize << "." << endl; return false; } if (m_args.count(g_argMachine)) @@ -1083,7 +1090,7 @@ bool CommandLineInterface::processInput() targetMachine = Machine::Ewasm; else { - serr() << "Invalid option for --machine: " << machine << endl; + serr() << "Invalid option for --" << g_argMachine << ": " << machine << endl; return false; } } @@ -1099,13 +1106,14 @@ bool CommandLineInterface::processInput() inputLanguage = Input::Ewasm; if (targetMachine != Machine::Ewasm) { - serr() << "If you select Ewasm as --yul-dialect, --machine has to be Ewasm as well." << endl; + serr() << "If you select Ewasm as --" << g_strYulDialect << ", "; + serr() << "--" << g_argMachine << " has to be Ewasm as well." << endl; return false; } } else { - serr() << "Invalid option for --yul-dialect: " << dialect << endl; + serr() << "Invalid option for --" << g_strYulDialect << ": " << dialect << endl; return false; } } @@ -1142,7 +1150,7 @@ bool CommandLineInterface::processInput() m_metadataHash = CompilerStack::MetadataHash::None; else { - serr() << "Invalid option for --metadata-hash: " << hashStr << endl; + serr() << "Invalid option for --" << g_argMetadataHash << ": " << hashStr << endl; return false; } } From 5d4b9022f0795763bf4daa1df200de550024cbee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 8 May 2020 22:03:32 +0200 Subject: [PATCH 42/89] yul-phaser README: --no-optimize-yul options is not really necessary --- tools/yulPhaser/README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tools/yulPhaser/README.md b/tools/yulPhaser/README.md index abc2a0e47..45a7ec0ec 100644 --- a/tools/yulPhaser/README.md +++ b/tools/yulPhaser/README.md @@ -66,14 +66,11 @@ tools/yul-phaser *.yul \ `yul-phaser` can process the intermediate representation produced by `solc`: ``` bash -solc/solc \ - --ir \ - --no-optimize-yul \ - --output-dir +solc/solc --ir --output-dir ``` After running this command you'll find one or more .yul files in the output directory. -These files contain whole Yul objects rather than just raw Yul programs but `yul-phaser` is prepared to handle them. +These files contain whole Yul objects rather than just raw Yul programs but `yul-phaser` is prepared to handle them too. ### How to choose good parameters Choosing good parameters for a genetic algorithm is not a trivial task but phaser's defaults are generally enough to find a sequence that gives results comparable or better than one hand-crafted by an experienced developer for a given set of programs. From 6a582278309a963767ed31fea5ac8e6de108aa3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 8 May 2020 18:20:14 +0200 Subject: [PATCH 43/89] CommandLineInterface: Make --yul-optimizations work in strict assembly mode --- Changelog.md | 1 + docs/yul.rst | 3 +- solc/CommandLineInterface.cpp | 46 +++++++--- solc/CommandLineInterface.h | 7 +- .../standard_yul_optimiserSteps/input.json | 26 ++++++ .../standard_yul_optimiserSteps/output.json | 30 +++++++ .../strict_asm_optimizer_steps/args | 1 + .../strict_asm_optimizer_steps/err | 1 + .../strict_asm_optimizer_steps/input.yul | 27 ++++++ .../strict_asm_optimizer_steps/output | 88 +++++++++++++++++++ 10 files changed, 217 insertions(+), 13 deletions(-) create mode 100644 test/cmdlineTests/standard_yul_optimiserSteps/input.json create mode 100644 test/cmdlineTests/standard_yul_optimiserSteps/output.json create mode 100644 test/cmdlineTests/strict_asm_optimizer_steps/args create mode 100644 test/cmdlineTests/strict_asm_optimizer_steps/err create mode 100644 test/cmdlineTests/strict_asm_optimizer_steps/input.yul create mode 100644 test/cmdlineTests/strict_asm_optimizer_steps/output diff --git a/Changelog.md b/Changelog.md index 086e80ee9..714f9b526 100644 --- a/Changelog.md +++ b/Changelog.md @@ -5,6 +5,7 @@ Language Features: Compiler Features: + * Commandline Interface: Don't ignore `--yul-optimizations` in assembly mode. diff --git a/docs/yul.rst b/docs/yul.rst index c200558b0..3c7e0ba4d 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -1041,8 +1041,7 @@ Optimization step sequence -------------------------- By default the Yul optimizer applies its predefined sequence of optimization steps to the generated assembly. -You can override this sequence and supply your own using the `--yul-optimizations` option when compiling -in Solidity mode: +You can override this sequence and supply your own using the `--yul-optimizations` option: .. code-block:: sh diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 0166a5df6..1342ef1f6 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -787,19 +787,19 @@ Allowed options)").c_str(), ( g_argAssemble.c_str(), ("Switch to assembly mode, ignoring all options except " - "--" + g_argMachine + ", --" + g_strYulDialect + " and --" + g_argOptimize + " " + "--" + g_argMachine + ", --" + g_strYulDialect + ", --" + g_argOptimize + " and --" + g_strYulOptimizations + " " "and assumes input is assembly.").c_str() ) ( g_argYul.c_str(), ("Switch to Yul mode, ignoring all options except " - "--" + g_argMachine + ", --" + g_strYulDialect + " and --" + g_argOptimize + " " + "--" + g_argMachine + ", --" + g_strYulDialect + ", --" + g_argOptimize + " and --" + g_strYulOptimizations + " " "and assumes input is Yul.").c_str() ) ( g_argStrictAssembly.c_str(), ("Switch to strict assembly mode, ignoring all options except " - "--" + g_argMachine + ", --" + g_strYulDialect + " and --" + g_argOptimize + " " + "--" + g_argMachine + ", --" + g_strYulDialect + ", --" + g_argOptimize + " and --" + g_strYulOptimizations + " " "and assumes input is strict assembly.").c_str() ) ( @@ -1079,6 +1079,29 @@ bool CommandLineInterface::processInput() serr() << "--" << g_strNoOptimizeYul << " is invalid in assembly mode. Optimization is disabled by default and can be enabled with --" << g_argOptimize << "." << endl; return false; } + + optional yulOptimiserSteps; + if (m_args.count(g_strYulOptimizations)) + { + if (!optimize) + { + serr() << "--" << g_strYulOptimizations << " is invalid if Yul optimizer is disabled" << endl; + return false; + } + + try + { + yul::OptimiserSuite::validateSequence(m_args[g_strYulOptimizations].as()); + } + catch (yul::OptimizerException const& _exception) + { + serr() << "Invalid optimizer step sequence in --" << g_strYulOptimizations << ": " << _exception.what() << endl; + return false; + } + + yulOptimiserSteps = m_args[g_strYulOptimizations].as(); + } + if (m_args.count(g_argMachine)) { string machine = m_args[g_argMachine].as(); @@ -1130,7 +1153,7 @@ bool CommandLineInterface::processInput() "Warning: Yul is still experimental. Please use the output with care." << endl; - return assemble(inputLanguage, targetMachine, optimize); + return assemble(inputLanguage, targetMachine, optimize, yulOptimiserSteps); } if (m_args.count(g_argLink)) { @@ -1542,18 +1565,21 @@ string CommandLineInterface::objectWithLinkRefsHex(evmasm::LinkerObject const& _ bool CommandLineInterface::assemble( yul::AssemblyStack::Language _language, yul::AssemblyStack::Machine _targetMachine, - bool _optimize + bool _optimize, + optional _yulOptimiserSteps ) { + solAssert(_optimize || !_yulOptimiserSteps.has_value(), ""); + bool successful = true; map assemblyStacks; for (auto const& src: m_sourceCodes) { - auto& stack = assemblyStacks[src.first] = yul::AssemblyStack( - m_evmVersion, - _language, - _optimize ? OptimiserSettings::full() : OptimiserSettings::minimal() - ); + OptimiserSettings settings = _optimize ? OptimiserSettings::full() : OptimiserSettings::minimal(); + if (_yulOptimiserSteps.has_value()) + settings.yulOptimiserSteps = _yulOptimiserSteps.value(); + + auto& stack = assemblyStacks[src.first] = yul::AssemblyStack(m_evmVersion, _language, settings); try { if (!stack.parseAndAnalyze(src.first, src.second)) diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index f6972cf04..446ea8224 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -56,7 +56,12 @@ private: /// @returns the full object with library placeholder hints in hex. static std::string objectWithLinkRefsHex(evmasm::LinkerObject const& _obj); - bool assemble(yul::AssemblyStack::Language _language, yul::AssemblyStack::Machine _targetMachine, bool _optimize); + bool assemble( + yul::AssemblyStack::Language _language, + yul::AssemblyStack::Machine _targetMachine, + bool _optimize, + std::optional _yulOptimiserSteps = std::nullopt + ); void outputCompilationResults(); diff --git a/test/cmdlineTests/standard_yul_optimiserSteps/input.json b/test/cmdlineTests/standard_yul_optimiserSteps/input.json new file mode 100644 index 000000000..1015496f9 --- /dev/null +++ b/test/cmdlineTests/standard_yul_optimiserSteps/input.json @@ -0,0 +1,26 @@ +{ + "language": "Yul", + "sources": + { + "A": + { + "content": "{ let x := mload(0) sstore(add(x, 0), 0) }" + } + }, + "settings": + { + "optimizer": { + "enabled": true, + "details": { + "yul": true, + "yulDetails": { + "optimizerSteps": "dhfoDgvulfnTUtnIf" + } + } + }, + "outputSelection": + { + "*": { "*": ["*"], "": [ "*" ] } + } + } +} diff --git a/test/cmdlineTests/standard_yul_optimiserSteps/output.json b/test/cmdlineTests/standard_yul_optimiserSteps/output.json new file mode 100644 index 000000000..383ad8557 --- /dev/null +++ b/test/cmdlineTests/standard_yul_optimiserSteps/output.json @@ -0,0 +1,30 @@ +{"contracts":{"A":{"object":{"evm":{"assembly":" /* \"A\":17:18 */ + 0x00 + /* \"A\":11:19 */ + mload + /* \"A\":38:39 */ + 0x00 + /* \"A\":34:35 */ + 0x00 + /* \"A\":31:32 */ + dup3 + /* \"A\":27:36 */ + add + /* \"A\":20:40 */ + sstore + pop +","bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}},"ir":"object \"object\" { + code { + let x := mload(0) + sstore(add(x, 0), 0) + } +} +","irOptimized":"object \"object\" { + code { + { + let x := mload(0) + sstore(add(x, 0), 0) + } + } +} +"}}},"errors":[{"component":"general","formattedMessage":"Yul is still experimental. Please use the output with care.","message":"Yul is still experimental. Please use the output with care.","severity":"warning","type":"Warning"}]} diff --git a/test/cmdlineTests/strict_asm_optimizer_steps/args b/test/cmdlineTests/strict_asm_optimizer_steps/args new file mode 100644 index 000000000..ade406ee4 --- /dev/null +++ b/test/cmdlineTests/strict_asm_optimizer_steps/args @@ -0,0 +1 @@ +--strict-assembly --optimize --yul-optimizations dhfoDgvulfnTUtnIf diff --git a/test/cmdlineTests/strict_asm_optimizer_steps/err b/test/cmdlineTests/strict_asm_optimizer_steps/err new file mode 100644 index 000000000..014a1178f --- /dev/null +++ b/test/cmdlineTests/strict_asm_optimizer_steps/err @@ -0,0 +1 @@ +Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/strict_asm_optimizer_steps/input.yul b/test/cmdlineTests/strict_asm_optimizer_steps/input.yul new file mode 100644 index 000000000..b1c756df3 --- /dev/null +++ b/test/cmdlineTests/strict_asm_optimizer_steps/input.yul @@ -0,0 +1,27 @@ +object "C_6" { + code { + mstore(64, 128) + if callvalue() { revert(0, 0) } + codecopy(0, dataoffset("C_6_deployed"), datasize("C_6_deployed")) + return(0, datasize("C_6_deployed")) + } + object "C_6_deployed" { + code { + { + mstore(64, 128) + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + pop(selector) + } + pop(iszero(calldatasize())) + revert(0, 0) + } + + function shift_right_224_unsigned(value) -> newValue + { + newValue := shr(224, value) + } + } + } +} diff --git a/test/cmdlineTests/strict_asm_optimizer_steps/output b/test/cmdlineTests/strict_asm_optimizer_steps/output new file mode 100644 index 000000000..369be348c --- /dev/null +++ b/test/cmdlineTests/strict_asm_optimizer_steps/output @@ -0,0 +1,88 @@ + +======= strict_asm_optimizer_steps/input.yul (EVM) ======= + +Pretty printed source: +object "C_6" { + code { + { + mstore(64, 128) + if callvalue() { revert(0, 0) } + codecopy(0, dataoffset("C_6_deployed"), datasize("C_6_deployed")) + return(0, datasize("C_6_deployed")) + } + } + object "C_6_deployed" { + code { + { + mstore(64, 128) + pop(iszero(lt(calldatasize(), 4))) + revert(0, 0) + } + } + } +} + + +Binary representation: +60806040523415600f5760006000fd5b6010601d60003960106000f3fe608060405260043610155060006000fd + +Text representation: + /* "strict_asm_optimizer_steps/input.yul":45:48 */ + 0x80 + /* "strict_asm_optimizer_steps/input.yul":41:43 */ + 0x40 + /* "strict_asm_optimizer_steps/input.yul":34:49 */ + mstore + /* "strict_asm_optimizer_steps/input.yul":61:72 */ + callvalue + /* "strict_asm_optimizer_steps/input.yul":58:60 */ + iszero + tag_1 + jumpi + /* "strict_asm_optimizer_steps/input.yul":85:86 */ + 0x00 + /* "strict_asm_optimizer_steps/input.yul":82:83 */ + 0x00 + /* "strict_asm_optimizer_steps/input.yul":75:87 */ + revert + /* "strict_asm_optimizer_steps/input.yul":58:60 */ +tag_1: + /* "strict_asm_optimizer_steps/input.yul":98:163 */ + dataSize(sub_0) + dataOffset(sub_0) + /* "strict_asm_optimizer_steps/input.yul":107:108 */ + 0x00 + /* "strict_asm_optimizer_steps/input.yul":98:163 */ + codecopy + /* "strict_asm_optimizer_steps/input.yul":172:207 */ + dataSize(sub_0) + /* "strict_asm_optimizer_steps/input.yul":179:180 */ + 0x00 + /* "strict_asm_optimizer_steps/input.yul":172:207 */ + return +stop + +sub_0: assembly { + /* "strict_asm_optimizer_steps/input.yul":298:301 */ + 0x80 + /* "strict_asm_optimizer_steps/input.yul":294:296 */ + 0x40 + /* "strict_asm_optimizer_steps/input.yul":287:302 */ + mstore + /* "strict_asm_optimizer_steps/input.yul":348:349 */ + 0x04 + /* "strict_asm_optimizer_steps/input.yul":332:346 */ + calldatasize + /* "strict_asm_optimizer_steps/input.yul":329:350 */ + lt + /* "strict_asm_optimizer_steps/input.yul":322:351 */ + iszero + /* "strict_asm_optimizer_steps/input.yul":319:321 */ + pop + /* "strict_asm_optimizer_steps/input.yul":570:571 */ + 0x00 + /* "strict_asm_optimizer_steps/input.yul":567:568 */ + 0x00 + /* "strict_asm_optimizer_steps/input.yul":560:572 */ + revert +} From dc5612467f94bfa94b48caf7fc2f09154cdaf7e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 4 May 2020 21:25:57 +0200 Subject: [PATCH 44/89] docs/yul: Use backtick syntax correct for RST in the docs for --yul-optimizations --- docs/yul.rst | 62 ++++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/docs/yul.rst b/docs/yul.rst index 3c7e0ba4d..f2e09d22e 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -1041,13 +1041,13 @@ Optimization step sequence -------------------------- By default the Yul optimizer applies its predefined sequence of optimization steps to the generated assembly. -You can override this sequence and supply your own using the `--yul-optimizations` option: +You can override this sequence and supply your own using the ``--yul-optimizations`` option: .. code-block:: sh solc --optimize --ir-optimized --yul-optimizations 'dhfoD[xarrscLMcCTU]uljmul' -By enclosing part of the sequence in square brackets (`[]`) you tell the optimizer to repeatedly +By enclosing part of the sequence in square brackets (``[]``) you tell the optimizer to repeatedly apply that part until it no longer improves the size of the resulting assembly. You can use brackets multiple times in a single sequence but they cannot be nested. @@ -1056,37 +1056,37 @@ The following optimization steps are available: ============ =============================== Abbreviation Full name ============ =============================== -f `BlockFlattener` -l `CircularReferencesPruner` -c `CommonSubexpressionEliminator` -C `ConditionalSimplifier` -U `ConditionalUnsimplifier` -n `ControlFlowSimplifier` -D `DeadCodeEliminator` -v `EquivalentFunctionCombiner` -e `ExpressionInliner` -j `ExpressionJoiner` -s `ExpressionSimplifier` -x `ExpressionSplitter` -I `ForLoopConditionIntoBody` -O `ForLoopConditionOutOfBody` -o `ForLoopInitRewriter` -i `FullInliner` -g `FunctionGrouper` -h `FunctionHoister` -T `LiteralRematerialiser` -L `LoadResolver` -M `LoopInvariantCodeMotion` -r `RedundantAssignEliminator` -m `Rematerialiser` -V `SSAReverser` -a `SSATransform` -t `StructuralSimplifier` -u `UnusedPruner` -d `VarDeclInitializer` +``f`` ``BlockFlattener`` +``l`` ``CircularReferencesPruner`` +``c`` ``CommonSubexpressionEliminator`` +``C`` ``ConditionalSimplifier`` +``U`` ``ConditionalUnsimplifier`` +``n`` ``ControlFlowSimplifier`` +``D`` ``DeadCodeEliminator`` +``v`` ``EquivalentFunctionCombiner`` +``e`` ``ExpressionInliner`` +``j`` ``ExpressionJoiner`` +``s`` ``ExpressionSimplifier`` +``x`` ``ExpressionSplitter`` +``I`` ``ForLoopConditionIntoBody`` +``O`` ``ForLoopConditionOutOfBody`` +``o`` ``ForLoopInitRewriter`` +``i`` ``FullInliner`` +``g`` ``FunctionGrouper`` +``h`` ``FunctionHoister`` +``T`` ``LiteralRematerialiser`` +``L`` ``LoadResolver`` +``M`` ``LoopInvariantCodeMotion`` +``r`` ``RedundantAssignEliminator`` +``m`` ``Rematerialiser`` +``V`` ``SSAReverser`` +``a`` ``SSATransform`` +``t`` ``StructuralSimplifier`` +``u`` ``UnusedPruner`` +``d`` ``VarDeclInitializer`` ============ =============================== -Some steps depend on properties ensured by `BlockFlattener`, `FunctionGrouper`, `ForLoopInitRewriter`. +Some steps depend on properties ensured by ``BlockFlattener``, ``FunctionGrouper``, ``ForLoopInitRewriter``. For this reason the Yul optimizer always applies them before applying any steps supplied by the user. From e8aec6de54bbebdd78c81e6100bc70c3d05ff624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 8 May 2020 20:59:04 +0200 Subject: [PATCH 45/89] More information about --yul-optimizations option in READMEs and docs --- docs/yul.rst | 3 +++ libyul/optimiser/README.md | 12 ++++++++++++ tools/yulPhaser/README.md | 9 ++++++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/docs/yul.rst b/docs/yul.rst index f2e09d22e..2e8bc4a10 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -1047,6 +1047,9 @@ You can override this sequence and supply your own using the ``--yul-optimizatio solc --optimize --ir-optimized --yul-optimizations 'dhfoD[xarrscLMcCTU]uljmul' +The order of steps is significant and affects the quality of the output. +Moreover, applying a step may uncover new optimization opportunities for others that were already +applied so repeating steps is often beneficial. By enclosing part of the sequence in square brackets (``[]``) you tell the optimizer to repeatedly apply that part until it no longer improves the size of the resulting assembly. You can use brackets multiple times in a single sequence but they cannot be nested. diff --git a/libyul/optimiser/README.md b/libyul/optimiser/README.md index 58cc006b4..4bd3d6a36 100644 --- a/libyul/optimiser/README.md +++ b/libyul/optimiser/README.md @@ -4,6 +4,7 @@ planned state of the optimiser. Table of Contents: +- [Selecting optimisations](#selecting-optimisations) - [Preprocessing](#preprocessing) - [Pseudo-SSA Transformation](#pseudo-ssa-transformation) - [Tools](#tools) @@ -33,6 +34,17 @@ the following transformation steps are the main components: - [Redundant Assign Eliminator](#redundant-assign-eliminator) - [Full Function Inliner](#full-function-inliner) +## Selecting optimisations + +By default the optimiser applies its predefined sequence of optimisation steps to the generated assembly. +You can override this sequence and supply your own using the `--yul-optimizations` option: + +``` bash +solc --optimize --ir-optimized --yul-optimizations 'dhfoD[xarrscLMcCTU]uljmul' +``` + +There's a [table listing available abbreviations in the optimiser docs](/docs/yul.rst#optimization-step-sequence). + ## Preprocessing The preprocessing components perform transformations to get the program diff --git a/tools/yulPhaser/README.md b/tools/yulPhaser/README.md index 45a7ec0ec..3bc72b537 100644 --- a/tools/yulPhaser/README.md +++ b/tools/yulPhaser/README.md @@ -9,7 +9,7 @@ The input is a set of one or more [Yul](/docs/yul.rst) programs and each sequenc Optimised programs are given numeric scores according to the selected metric. Optimisation step sequences are presented in an abbreviated form - as strings of letters where each character represents one step. -The abbreviations are defined in [`OptimiserSuite::stepNameToAbbreviationMap()`](/libyul/optimiser/Suite.cpp#L388-L423). +There's a [table listing available abbreviations in the optimiser docs](/docs/yul.rst#optimization-step-sequence). ### How to use it The application has sensible defaults for most parameters. @@ -72,6 +72,13 @@ solc/solc --ir --output-dir After running this command you'll find one or more .yul files in the output directory. These files contain whole Yul objects rather than just raw Yul programs but `yul-phaser` is prepared to handle them too. +#### Using optimisation step sequences with the compiler +You can tell Yul optimiser to use a specific sequence for your code by passing `--yul-optimizations` option to `solc`: + +``` bash +solc/solc --optimize --ir-optimized --yul-optimizations +``` + ### How to choose good parameters Choosing good parameters for a genetic algorithm is not a trivial task but phaser's defaults are generally enough to find a sequence that gives results comparable or better than one hand-crafted by an experienced developer for a given set of programs. The difficult part is providing a fairly representative set of input files. From 6965f199fd11cada51c5a97ceb72cc5e14534a17 Mon Sep 17 00:00:00 2001 From: a3d4 Date: Sat, 9 May 2020 00:24:58 +0200 Subject: [PATCH 46/89] Groundwork. Prepare for automatic tagging of errors in parser-based classes [Not compilable until the next commit] --- liblangutil/ParserBase.cpp | 20 ++++++++++---------- liblangutil/ParserBase.h | 11 ++++++----- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/liblangutil/ParserBase.cpp b/liblangutil/ParserBase.cpp index c3a15794b..d57db0994 100644 --- a/liblangutil/ParserBase.cpp +++ b/liblangutil/ParserBase.cpp @@ -143,27 +143,27 @@ void ParserBase::decreaseRecursionDepth() m_recursionDepth--; } -void ParserBase::parserWarning(string const& _description) +void ParserBase::parserWarning(ErrorId _error, string const& _description) { - m_errorReporter.warning(6635_error, currentLocation(), _description); + m_errorReporter.warning(_error, currentLocation(), _description); } -void ParserBase::parserError(SourceLocation const& _location, string const& _description) +void ParserBase::parserError(ErrorId _error, SourceLocation const& _location, string const& _description) { - m_errorReporter.parserError(2314_error, _location, _description); + m_errorReporter.parserError(_error, _location, _description); } -void ParserBase::parserError(string const& _description) +void ParserBase::parserError(ErrorId _error, string const& _description) { - parserError(currentLocation(), _description); + parserError(_error, currentLocation(), _description); } -void ParserBase::fatalParserError(string const& _description) +void ParserBase::fatalParserError(ErrorId _error, string const& _description) { - fatalParserError(currentLocation(), _description); + fatalParserError(_error, currentLocation(), _description); } -void ParserBase::fatalParserError(SourceLocation const& _location, string const& _description) +void ParserBase::fatalParserError(ErrorId _error, SourceLocation const& _location, string const& _description) { - m_errorReporter.fatalParserError(1957_error, _location, _description); + m_errorReporter.fatalParserError(_error, _location, _description); } diff --git a/liblangutil/ParserBase.h b/liblangutil/ParserBase.h index 575a049e2..8a8073696 100644 --- a/liblangutil/ParserBase.h +++ b/liblangutil/ParserBase.h @@ -32,6 +32,7 @@ namespace solidity::langutil class ErrorReporter; class Scanner; +struct ErrorId; class ParserBase { @@ -88,17 +89,17 @@ protected: /// Creates a @ref ParserError and annotates it with the current position and the /// given @a _description. - void parserError(std::string const& _description); - void parserError(SourceLocation const& _location, std::string const& _description); + void parserError(ErrorId _error, std::string const& _description); + void parserError(ErrorId _error, SourceLocation const& _location, std::string const& _description); /// Creates a @ref ParserWarning and annotates it with the current position and the /// given @a _description. - void parserWarning(std::string const& _description); + void parserWarning(ErrorId _error, std::string const& _description); /// Creates a @ref ParserError and annotates it with the current position and the /// given @a _description. Throws the FatalError. - void fatalParserError(std::string const& _description); - void fatalParserError(SourceLocation const& _location, std::string const& _description); + void fatalParserError(ErrorId _error, std::string const& _description); + void fatalParserError(ErrorId _error, SourceLocation const& _location, std::string const& _description); std::shared_ptr m_scanner; /// The reference to the list of errors and warning to add errors/warnings during parsing From c3e519a151c0533962d0025c0640c6f4d5eee1e1 Mon Sep 17 00:00:00 2001 From: a3d4 Date: Sat, 9 May 2020 01:28:55 +0200 Subject: [PATCH 47/89] Add unique IDs to error reporting calls --- liblangutil/ParserBase.cpp | 14 +++---- libsolidity/parsing/Parser.cpp | 76 ++++++++++++++++++---------------- libyul/AsmParser.cpp | 21 +++++----- libyul/ObjectParser.cpp | 12 +++--- 4 files changed, 65 insertions(+), 58 deletions(-) diff --git a/liblangutil/ParserBase.cpp b/liblangutil/ParserBase.cpp index d57db0994..f0ebefd93 100644 --- a/liblangutil/ParserBase.cpp +++ b/liblangutil/ParserBase.cpp @@ -77,9 +77,9 @@ void ParserBase::expectToken(Token _value, bool _advance) { string const expectedToken = ParserBase::tokenName(_value); if (m_parserErrorRecovery) - parserError("Expected " + expectedToken + " but got " + tokenName(tok)); + parserError(6635_error, "Expected " + expectedToken + " but got " + tokenName(tok)); else - fatalParserError("Expected " + expectedToken + " but got " + tokenName(tok)); + fatalParserError(2314_error, "Expected " + expectedToken + " but got " + tokenName(tok)); // Do not advance so that recovery can sync or make use of the current token. // This is especially useful if the expected token // is the only one that is missing and is at the end of a construct. @@ -108,21 +108,21 @@ void ParserBase::expectTokenOrConsumeUntil(Token _value, string const& _currentN // rollback to where the token started, and raise exception to be caught at a higher level. m_scanner->setPosition(startPosition); m_inParserRecovery = true; - fatalParserError(errorLoc, msg); + fatalParserError(1957_error, errorLoc, msg); } else { if (m_inParserRecovery) - parserWarning("Recovered in " + _currentNodeName + " at " + expectedToken + "."); + parserWarning(3796_error, "Recovered in " + _currentNodeName + " at " + expectedToken + "."); else - parserError(errorLoc, msg + "Recovered at next " + expectedToken); + parserError(1054_error, errorLoc, msg + "Recovered at next " + expectedToken); m_inParserRecovery = false; } } else if (m_inParserRecovery) { string expectedToken = ParserBase::tokenName(_value); - parserWarning("Recovered in " + _currentNodeName + " at " + expectedToken + "."); + parserWarning(3347_error, "Recovered in " + _currentNodeName + " at " + expectedToken + "."); m_inParserRecovery = false; } @@ -134,7 +134,7 @@ void ParserBase::increaseRecursionDepth() { m_recursionDepth++; if (m_recursionDepth >= 1200) - fatalParserError("Maximum recursion depth reached during parsing."); + fatalParserError(7319_error, "Maximum recursion depth reached during parsing."); } void ParserBase::decreaseRecursionDepth() diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index d24b0e69f..f726e6dc9 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -103,7 +103,7 @@ ASTPointer Parser::parse(shared_ptr const& _scanner) nodes.push_back(parseEnumDefinition()); break; default: - fatalParserError(string("Expected pragma, import directive or contract/interface/library/struct/enum definition.")); + fatalParserError(7858_error, string("Expected pragma, import directive or contract/interface/library/struct/enum definition.")); } } solAssert(m_recursionDepth == 0, ""); @@ -163,7 +163,7 @@ ASTPointer Parser::parsePragmaDirective() { Token token = m_scanner->currentToken(); if (token == Token::Illegal) - parserError("Token incompatible with Solidity parser as part of pragma directive."); + parserError(6281_error, "Token incompatible with Solidity parser as part of pragma directive."); else { string literal = m_scanner->currentLiteral(); @@ -241,18 +241,18 @@ ASTPointer Parser::parseImportDirective() unitAlias = expectIdentifierToken(); } else - fatalParserError("Expected string literal (path), \"*\" or alias list."); + fatalParserError(9478_error, "Expected string literal (path), \"*\" or alias list."); // "from" is not a keyword but parsed as an identifier because of backwards // compatibility and because it is a really common word. if (m_scanner->currentToken() != Token::Identifier || m_scanner->currentLiteral() != "from") - fatalParserError("Expected \"from\"."); + fatalParserError(8208_error, "Expected \"from\"."); m_scanner->next(); if (m_scanner->currentToken() != Token::StringLiteral) - fatalParserError("Expected import path."); + fatalParserError(6845_error, "Expected import path."); path = getLiteralAndAdvance(); } if (path->empty()) - fatalParserError("Import path cannot be empty."); + fatalParserError(6326_error, "Import path cannot be empty."); nodeFactory.markEndPosition(); expectToken(Token::Semicolon); return nodeFactory.createNode(path, unitAlias, move(symbolAliases)); @@ -279,7 +279,7 @@ std::pair Parser::parseContractKind() kind = ContractKind::Library; break; default: - parserError("Expected keyword \"contract\", \"interface\" or \"library\"."); + parserError(3515_error, "Expected keyword \"contract\", \"interface\" or \"library\"."); return std::make_pair(ContractKind::Contract, abstract); } m_scanner->next(); @@ -344,7 +344,7 @@ ASTPointer Parser::parseContractDefinition() else if (currentTokenValue == Token::Using) subNodes.push_back(parseUsingDirective()); else - fatalParserError(string("Function, variable, struct or modifier declaration expected.")); + fatalParserError(9182_error, string("Function, variable, struct or modifier declaration expected.")); } } catch (FatalError const&) @@ -463,6 +463,7 @@ StateMutability Parser::parseStateMutability() case Token::Constant: stateMutability = StateMutability::View; parserError( + 7698_error, "The state mutability modifier \"constant\" was removed in version 0.5.0. " "Use \"view\" or \"pure\" instead." ); @@ -495,7 +496,8 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _isStateVari // Detect this and return early. if (_isStateVariable && (result.visibility == Visibility::External || result.visibility == Visibility::Internal)) break; - parserError(string( + parserError( + 9439_error,string( "Visibility already specified as \"" + Declaration::visibilityToString(result.visibility) + "\"." @@ -509,7 +511,8 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _isStateVari { if (result.stateMutability != StateMutability::NonPayable) { - parserError(string( + parserError( + 9680_error,string( "State mutability already specified as \"" + stateMutabilityToString(result.stateMutability) + "\"." @@ -522,14 +525,14 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _isStateVari else if (!_isStateVariable && token == Token::Override) { if (result.overrides) - parserError("Override already specified."); + parserError(1827_error, "Override already specified."); result.overrides = parseOverrideSpecifier(); } else if (!_isStateVariable && token == Token::Virtual) { if (result.isVirtual) - parserError("Virtual already specified."); + parserError(6879_error, "Virtual already specified."); result.isVirtual = true; m_scanner->next(); @@ -577,9 +580,9 @@ ASTPointer Parser::parseFunctionDefinition() "the \"function\" keyword to define it." }; if (m_scanner->currentToken() == Token::Constructor) - parserError(message); + parserError(3323_error, message); else - parserWarning(message); + parserWarning(3445_error, message); m_scanner->next(); } else @@ -660,10 +663,10 @@ ASTPointer Parser::parseEnumDefinition() break; expectToken(Token::Comma); if (m_scanner->currentToken() != Token::Identifier) - fatalParserError(string("Expected identifier after ','")); + fatalParserError(1612_error, string("Expected identifier after ','")); } if (members.empty()) - parserError({"enum with no members is not allowed."}); + parserError(3147_error, {"enum with no members is not allowed."}); nodeFactory.markEndPosition(); expectToken(Token::RBrace); @@ -690,6 +693,7 @@ ASTPointer Parser::parseVariableDeclaration( if (dynamic_cast(type.get()) && _options.isStateVariable && m_scanner->currentToken() == Token::LBrace) fatalParserError( + 2915_error, "Expected a state variable declaration. If you intended this as a fallback function " "or a function to handle plain ether transactions, use the \"fallback\" keyword " "or the \"receive\" keyword instead." @@ -710,7 +714,8 @@ ASTPointer Parser::parseVariableDeclaration( nodeFactory.markEndPosition(); if (visibility != Visibility::Default) { - parserError(string( + parserError( + 4110_error,string( "Visibility already specified as \"" + Declaration::visibilityToString(visibility) + "\"." @@ -723,7 +728,7 @@ ASTPointer Parser::parseVariableDeclaration( else if (_options.isStateVariable && token == Token::Override) { if (overrides) - parserError("Override already specified."); + parserError(9125_error, "Override already specified."); overrides = parseOverrideSpecifier(); } @@ -735,6 +740,7 @@ ASTPointer Parser::parseVariableDeclaration( { if (mutability != VariableDeclaration::Mutability::Mutable) parserError( + 3109_error, string("Mutability already set to ") + (mutability == VariableDeclaration::Mutability::Constant ? "\"constant\"" : "\"immutable\"") ); @@ -746,9 +752,9 @@ ASTPointer Parser::parseVariableDeclaration( else if (_options.allowLocationSpecifier && TokenTraits::isLocationSpecifier(token)) { if (location != VariableDeclaration::Location::Unspecified) - parserError(string("Location already specified.")); + parserError(3548_error, string("Location already specified.")); else if (!type) - parserError(string("Location specifier needs explicit type name.")); + parserError(7439_error, string("Location specifier needs explicit type name.")); else { switch (token) @@ -837,13 +843,13 @@ ASTPointer Parser::parseModifierDefinition() if (m_scanner->currentToken() == Token::Override) { if (overrides) - parserError("Override already specified."); + parserError(9102_error, "Override already specified."); overrides = parseOverrideSpecifier(); } else if (m_scanner->currentToken() == Token::Virtual) { if (isVirtual) - parserError("Virtual already specified."); + parserError(2662_error, "Virtual already specified."); isVirtual = true; m_scanner->next(); @@ -991,7 +997,7 @@ ASTPointer Parser::parseTypeName(bool _allowVar) } else { - parserError("State mutability can only be specified for address types."); + parserError(9106_error, "State mutability can only be specified for address types."); m_scanner->next(); } } @@ -1000,7 +1006,7 @@ ASTPointer Parser::parseTypeName(bool _allowVar) else if (token == Token::Var) { if (!_allowVar) - parserError(string("Expected explicit type name.")); + parserError(7059_error, string("Expected explicit type name.")); m_scanner->next(); } else if (token == Token::Function) @@ -1010,7 +1016,7 @@ ASTPointer Parser::parseTypeName(bool _allowVar) else if (token == Token::Identifier) type = parseUserDefinedTypeName(); else - fatalParserError(string("Expected type name")); + fatalParserError(3546_error, string("Expected type name")); if (type) // Parse "[...]" postfixes for arrays. @@ -1053,7 +1059,7 @@ ASTPointer Parser::parseMapping() m_scanner->next(); } else - fatalParserError(string("Expected elementary type name or identifier for mapping key type")); + fatalParserError(1005_error, string("Expected elementary type name or identifier for mapping key type")); expectToken(Token::Arrow); bool const allowVar = false; ASTPointer valueType = parseTypeName(allowVar); @@ -1079,7 +1085,7 @@ ASTPointer Parser::parseParameterList( while (m_scanner->currentToken() != Token::RParen) { if (m_scanner->currentToken() == Token::Comma && m_scanner->peekNextToken() == Token::RParen) - fatalParserError("Unexpected trailing comma in parameter list."); + fatalParserError(7591_error, "Unexpected trailing comma in parameter list."); expectToken(Token::Comma); parameters.push_back(parseVariableDeclaration(options)); } @@ -1214,7 +1220,7 @@ ASTPointer Parser::parseInlineAssembly(ASTPointer con if (m_scanner->currentToken() == Token::StringLiteral) { if (m_scanner->currentLiteral() != "evmasm") - fatalParserError("Only \"evmasm\" supported."); + fatalParserError(4531_error, "Only \"evmasm\" supported."); // This can be used in the future to set the dialect. m_scanner->next(); } @@ -1377,7 +1383,7 @@ ASTPointer Parser::parseEmitStatement(ASTPointer const ASTNodeFactory eventCallNodeFactory(*this); if (m_scanner->currentToken() != Token::Identifier) - fatalParserError("Expected event name or path."); + fatalParserError(5620_error, "Expected event name or path."); IndexAccessedPath iap; while (true) @@ -1845,7 +1851,7 @@ ASTPointer Parser::parsePrimaryExpression() nodeFactory.markEndPosition(); m_scanner->next(); if (m_scanner->currentToken() == Token::Illegal) - fatalParserError(to_string(m_scanner->currentError())); + fatalParserError(5428_error, to_string(m_scanner->currentError())); expression = nodeFactory.createNode(token, make_shared(literal)); break; } @@ -1876,7 +1882,7 @@ ASTPointer Parser::parsePrimaryExpression() if (m_scanner->currentToken() != Token::Comma && m_scanner->currentToken() != oppositeToken) components.push_back(parseExpression()); else if (isArray) - parserError("Expected expression (inline array elements cannot be omitted)."); + parserError(4799_error, "Expected expression (inline array elements cannot be omitted)."); else components.push_back(ASTPointer()); @@ -1891,7 +1897,7 @@ ASTPointer Parser::parsePrimaryExpression() break; } case Token::Illegal: - fatalParserError(to_string(m_scanner->currentError())); + fatalParserError(8936_error, to_string(m_scanner->currentError())); break; default: if (TokenTraits::isElementaryTypeName(token)) @@ -1907,7 +1913,7 @@ ASTPointer Parser::parsePrimaryExpression() m_scanner->next(); } else - fatalParserError(string("Expected primary expression.")); + fatalParserError(6933_error, string("Expected primary expression.")); break; } return expression; @@ -1965,7 +1971,7 @@ pair>, vector>> Parser::pars m_scanner->peekNextToken() == Token::RBrace ) { - parserError("Unexpected trailing comma."); + parserError(2074_error, "Unexpected trailing comma."); m_scanner->next(); } @@ -2084,7 +2090,7 @@ ASTPointer Parser::typeNameFromIndexAccessStructure(Parser::IndexAcces for (auto const& lengthExpression: _iap.indices) { if (lengthExpression.end) - parserError(lengthExpression.location, "Expected array length expression."); + parserError(5464_error, lengthExpression.location, "Expected array length expression."); nodeFactory.setLocation(lengthExpression.location); type = nodeFactory.createNode(type, lengthExpression.start); } diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index 13b96839b..19574446d 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -122,11 +122,11 @@ Statement Parser::parseStatement() if (currentToken() == Token::Default) _switch.cases.emplace_back(parseCase()); if (currentToken() == Token::Default) - fatalParserError("Only one default case allowed."); + fatalParserError(6931_error, "Only one default case allowed."); else if (currentToken() == Token::Case) - fatalParserError("Case not allowed after default case."); + fatalParserError(4904_error, "Case not allowed after default case."); if (_switch.cases.empty()) - fatalParserError("Switch statement without any cases."); + fatalParserError(2418_error, "Switch statement without any cases."); _switch.location.end = _switch.cases.back().body.location.end; return Statement{move(_switch)}; } @@ -184,6 +184,7 @@ Statement Parser::parseStatement() auto const token = currentToken() == Token::Comma ? "," : ":="; fatalParserError( + 2856_error, std::string("Variable name must precede \"") + token + "\"" + @@ -194,7 +195,7 @@ Statement Parser::parseStatement() auto const& identifier = std::get(elementary); if (m_dialect.builtin(identifier.name)) - fatalParserError("Cannot assign to builtin function \"" + identifier.name.str() + "\"."); + fatalParserError(6272_error, "Cannot assign to builtin function \"" + identifier.name.str() + "\"."); variableNames.emplace_back(identifier); @@ -218,7 +219,7 @@ Statement Parser::parseStatement() return Statement{std::move(assignment)}; } default: - fatalParserError("Call or assignment expected."); + fatalParserError(6913_error, "Call or assignment expected."); break; } @@ -250,7 +251,7 @@ Case Parser::parseCase() advance(); ElementaryOperation literal = parseElementaryOperation(); if (!holds_alternative(literal)) - fatalParserError("Literal expected."); + fatalParserError(4805_error, "Literal expected."); _case.value = make_unique(std::get(std::move(literal))); } else @@ -353,7 +354,7 @@ Parser::ElementaryOperation Parser::parseElementaryOperation() break; case Token::Number: if (!isValidNumberLiteral(currentLiteral())) - fatalParserError("Invalid number literal."); + fatalParserError(4828_error, "Invalid number literal."); kind = LiteralKind::Number; break; case Token::TrueLiteral: @@ -382,7 +383,7 @@ Parser::ElementaryOperation Parser::parseElementaryOperation() break; } default: - fatalParserError("Literal or identifier expected."); + fatalParserError(1856_error, "Literal or identifier expected."); } return ret; } @@ -472,7 +473,7 @@ Expression Parser::parseCall(Parser::ElementaryOperation&& _initialOp) else if (holds_alternative(_initialOp)) ret = std::move(std::get(_initialOp)); else - fatalParserError("Function name expected."); + fatalParserError(9980_error, "Function name expected."); expectToken(Token::LParen); if (currentToken() != Token::RParen) @@ -525,7 +526,7 @@ YulString Parser::expectAsmIdentifier() } if (m_dialect.builtin(name)) - fatalParserError("Cannot use builtin function name \"" + name.str() + "\" as identifier name."); + fatalParserError(5568_error, "Cannot use builtin function name \"" + name.str() + "\" as identifier name."); advance(); return name; } diff --git a/libyul/ObjectParser.cpp b/libyul/ObjectParser.cpp index 74c339f18..7e50fa88e 100644 --- a/libyul/ObjectParser.cpp +++ b/libyul/ObjectParser.cpp @@ -66,7 +66,7 @@ shared_ptr ObjectParser::parseObject(Object* _containingObject) RecursionGuard guard(*this); if (currentToken() != Token::Identifier || currentLiteral() != "object") - fatalParserError("Expected keyword \"object\"."); + fatalParserError(4294_error, "Expected keyword \"object\"."); advance(); shared_ptr ret = make_shared(); @@ -83,7 +83,7 @@ shared_ptr ObjectParser::parseObject(Object* _containingObject) else if (currentToken() == Token::Identifier && currentLiteral() == "data") parseData(*ret); else - fatalParserError("Expected keyword \"data\" or \"object\" or \"}\"."); + fatalParserError(8143_error, "Expected keyword \"data\" or \"object\" or \"}\"."); } if (_containingObject) addNamedSubObject(*_containingObject, ret->name, ret); @@ -96,7 +96,7 @@ shared_ptr ObjectParser::parseObject(Object* _containingObject) shared_ptr ObjectParser::parseCode() { if (currentToken() != Token::Identifier || currentLiteral() != "code") - fatalParserError("Expected keyword \"code\"."); + fatalParserError(4846_error, "Expected keyword \"code\"."); advance(); return parseBlock(); @@ -133,11 +133,11 @@ YulString ObjectParser::parseUniqueName(Object const* _containingObject) expectToken(Token::StringLiteral, false); YulString name{currentLiteral()}; if (name.empty()) - parserError("Object name cannot be empty."); + parserError(3287_error, "Object name cannot be empty."); else if (_containingObject && _containingObject->name == name) - parserError("Object name cannot be the same as the name of the containing object."); + parserError(8311_error, "Object name cannot be the same as the name of the containing object."); else if (_containingObject && _containingObject->subIndexByName.count(name)) - parserError("Object name \"" + name.str() + "\" already exists inside the containing object."); + parserError(8794_error, "Object name \"" + name.str() + "\" already exists inside the containing object."); advance(); return name; } From 0b09a7768977e0502cd98882ab1fb190fb1e3d59 Mon Sep 17 00:00:00 2001 From: a3d4 Date: Sat, 9 May 2020 01:45:02 +0200 Subject: [PATCH 48/89] Removed minor parameter redundancy --- libsolidity/parsing/Parser.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index f726e6dc9..99b9a2cac 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -103,7 +103,7 @@ ASTPointer Parser::parse(shared_ptr const& _scanner) nodes.push_back(parseEnumDefinition()); break; default: - fatalParserError(7858_error, string("Expected pragma, import directive or contract/interface/library/struct/enum definition.")); + fatalParserError(7858_error, "Expected pragma, import directive or contract/interface/library/struct/enum definition."); } } solAssert(m_recursionDepth == 0, ""); @@ -344,7 +344,7 @@ ASTPointer Parser::parseContractDefinition() else if (currentTokenValue == Token::Using) subNodes.push_back(parseUsingDirective()); else - fatalParserError(9182_error, string("Function, variable, struct or modifier declaration expected.")); + fatalParserError(9182_error, "Function, variable, struct or modifier declaration expected."); } } catch (FatalError const&) @@ -497,11 +497,11 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _isStateVari if (_isStateVariable && (result.visibility == Visibility::External || result.visibility == Visibility::Internal)) break; parserError( - 9439_error,string( + 9439_error, "Visibility already specified as \"" + Declaration::visibilityToString(result.visibility) + "\"." - )); + ); m_scanner->next(); } else @@ -512,11 +512,11 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _isStateVari if (result.stateMutability != StateMutability::NonPayable) { parserError( - 9680_error,string( + 9680_error, "State mutability already specified as \"" + stateMutabilityToString(result.stateMutability) + "\"." - )); + ); m_scanner->next(); } else @@ -663,10 +663,10 @@ ASTPointer Parser::parseEnumDefinition() break; expectToken(Token::Comma); if (m_scanner->currentToken() != Token::Identifier) - fatalParserError(1612_error, string("Expected identifier after ','")); + fatalParserError(1612_error, "Expected identifier after ','"); } if (members.empty()) - parserError(3147_error, {"enum with no members is not allowed."}); + parserError(3147_error, "enum with no members is not allowed."); nodeFactory.markEndPosition(); expectToken(Token::RBrace); @@ -715,11 +715,11 @@ ASTPointer Parser::parseVariableDeclaration( if (visibility != Visibility::Default) { parserError( - 4110_error,string( + 4110_error, "Visibility already specified as \"" + Declaration::visibilityToString(visibility) + "\"." - )); + ); m_scanner->next(); } else @@ -752,9 +752,9 @@ ASTPointer Parser::parseVariableDeclaration( else if (_options.allowLocationSpecifier && TokenTraits::isLocationSpecifier(token)) { if (location != VariableDeclaration::Location::Unspecified) - parserError(3548_error, string("Location already specified.")); + parserError(3548_error, "Location already specified."); else if (!type) - parserError(7439_error, string("Location specifier needs explicit type name.")); + parserError(7439_error, "Location specifier needs explicit type name."); else { switch (token) @@ -1006,7 +1006,7 @@ ASTPointer Parser::parseTypeName(bool _allowVar) else if (token == Token::Var) { if (!_allowVar) - parserError(7059_error, string("Expected explicit type name.")); + parserError(7059_error, "Expected explicit type name."); m_scanner->next(); } else if (token == Token::Function) @@ -1016,7 +1016,7 @@ ASTPointer Parser::parseTypeName(bool _allowVar) else if (token == Token::Identifier) type = parseUserDefinedTypeName(); else - fatalParserError(3546_error, string("Expected type name")); + fatalParserError(3546_error, "Expected type name"); if (type) // Parse "[...]" postfixes for arrays. @@ -1059,7 +1059,7 @@ ASTPointer Parser::parseMapping() m_scanner->next(); } else - fatalParserError(1005_error, string("Expected elementary type name or identifier for mapping key type")); + fatalParserError(1005_error, "Expected elementary type name or identifier for mapping key type"); expectToken(Token::Arrow); bool const allowVar = false; ASTPointer valueType = parseTypeName(allowVar); @@ -1913,7 +1913,7 @@ ASTPointer Parser::parsePrimaryExpression() m_scanner->next(); } else - fatalParserError(6933_error, string("Expected primary expression.")); + fatalParserError(6933_error, "Expected primary expression."); break; } return expression; From 591a5fff07ed5cebc1cb236d74e2cc572d05cec1 Mon Sep 17 00:00:00 2001 From: Djordje Mijovic Date: Mon, 11 May 2020 09:26:27 +0200 Subject: [PATCH 49/89] isoltest: WhiskersError and YulException treated differently when enforcing viaYul --- test/libsolidity/SemanticTest.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/libsolidity/SemanticTest.cpp b/test/libsolidity/SemanticTest.cpp index ab454cb28..33d40c899 100644 --- a/test/libsolidity/SemanticTest.cpp +++ b/test/libsolidity/SemanticTest.cpp @@ -13,6 +13,8 @@ */ #include +#include +#include #include #include #include @@ -27,6 +29,7 @@ using namespace std; using namespace solidity; +using namespace solidity::yul; using namespace solidity::util; using namespace solidity::util::formatting; using namespace solidity::frontend::test; @@ -201,6 +204,16 @@ TestCase::TestResult SemanticTest::run(ostream& _stream, string const& _linePref return TestResult::Failure; } } + catch (WhiskersError const&) + { + // this is an error in Whiskers template, so should be thrown anyway + throw; + } + catch (YulException const&) + { + // this should be an error in yul compilation or translation + throw; + } catch (boost::exception const&) { if (compileViaYul && !m_runWithYul) From e54c4eecfc4e973625cb54d1c5b59c982ab30cbb Mon Sep 17 00:00:00 2001 From: Harikrishnan Mulackal Date: Thu, 7 May 2020 21:54:37 +0530 Subject: [PATCH 50/89] implemented type(X).min and type(X).max for all integer types --- libsolidity/analysis/GlobalContext.cpp | 8 +- libsolidity/analysis/TypeChecker.cpp | 32 ++- libsolidity/analysis/ViewPureChecker.cpp | 2 + libsolidity/ast/TypeProvider.cpp | 8 +- libsolidity/ast/Types.cpp | 53 +++- libsolidity/ast/Types.h | 3 + libsolidity/codegen/ExpressionCompiler.cpp | 10 + .../codegen/ir/IRGeneratorForStatements.cpp | 20 +- .../semanticTests/integer/basic.sol | 24 ++ .../libsolidity/semanticTests/integer/int.sol | 245 ++++++++++++++++++ .../semanticTests/integer/uint.sol | 244 +++++++++++++++++ .../syntaxTests/metaTypes/typeRecursive.sol | 4 +- .../metaTypes/unsupportedArgForType.sol | 2 +- 13 files changed, 626 insertions(+), 29 deletions(-) create mode 100644 test/libsolidity/semanticTests/integer/basic.sol create mode 100644 test/libsolidity/semanticTests/integer/int.sol create mode 100644 test/libsolidity/semanticTests/integer/uint.sol diff --git a/libsolidity/analysis/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp index a0764edba..ddde7358e 100644 --- a/libsolidity/analysis/GlobalContext.cpp +++ b/libsolidity/analysis/GlobalContext.cpp @@ -100,11 +100,13 @@ inline vector> constructMagicVariable magicVarDecl("sha3", TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)), magicVarDecl("suicide", TypeProvider::function(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)), magicVarDecl("tx", TypeProvider::magic(MagicType::Kind::Transaction)), + // Accepts a MagicType that can be any contract type or an Integer type and returns a + // MagicType. The TypeChecker handles the correctness of the input and output types. magicVarDecl("type", TypeProvider::function( - strings{"address"} /* accepts any contract type, handled by the type checker */, - strings{} /* returns a MagicType, handled by the type checker */, + strings{}, + strings{}, FunctionType::Kind::MetaType, - false, + true, StateMutability::Pure )), }; diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index b4030c0c4..b65d22b5e 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -214,17 +214,28 @@ TypePointers TypeChecker::typeCheckMetaTypeFunctionAndRetrieveReturnType(Functio return {}; } TypePointer firstArgType = type(*arguments.front()); - if ( - firstArgType->category() != Type::Category::TypeType || - dynamic_cast(*firstArgType).actualType()->category() != TypeType::Category::Contract - ) + + bool wrongType = false; + if (firstArgType->category() == Type::Category::TypeType) + { + TypeType const* typeTypePtr = dynamic_cast(firstArgType); + Type::Category typeCategory = typeTypePtr->actualType()->category(); + if ( + typeCategory != Type::Category::Contract && + typeCategory != Type::Category::Integer + ) + wrongType = true; + } + else + wrongType = true; + + if (wrongType) { m_errorReporter.typeError( arguments.front()->location(), - "Invalid type for argument in function call. " - "Contract type required, but " + - type(*arguments.front())->toString(true) + - " provided." + "Invalid type for argument in the function call. " + "A contract type or an integer type is required, but " + + type(*arguments.front())->toString(true) + " provided." ); return {}; } @@ -2600,6 +2611,11 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) annotation.isPure = true; else if (magicType->kind() == MagicType::Kind::MetaType && memberName == "interfaceId") annotation.isPure = true; + else if ( + magicType->kind() == MagicType::Kind::MetaType && + (memberName == "min" || memberName == "max") + ) + annotation.isPure = true; } return false; diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp index 0d87fdbc2..87b9dcef6 100644 --- a/libsolidity/analysis/ViewPureChecker.cpp +++ b/libsolidity/analysis/ViewPureChecker.cpp @@ -357,6 +357,8 @@ void ViewPureChecker::endVisit(MemberAccess const& _memberAccess) {MagicType::Kind::MetaType, "runtimeCode"}, {MagicType::Kind::MetaType, "name"}, {MagicType::Kind::MetaType, "interfaceId"}, + {MagicType::Kind::MetaType, "min"}, + {MagicType::Kind::MetaType, "max"}, }; set static const payableMembers{ {MagicType::Kind::Message, "value"} diff --git a/libsolidity/ast/TypeProvider.cpp b/libsolidity/ast/TypeProvider.cpp index 7dd895cbe..6fd778403 100644 --- a/libsolidity/ast/TypeProvider.cpp +++ b/libsolidity/ast/TypeProvider.cpp @@ -556,7 +556,13 @@ MagicType const* TypeProvider::magic(MagicType::Kind _kind) MagicType const* TypeProvider::meta(Type const* _type) { - solAssert(_type && _type->category() == Type::Category::Contract, "Only contracts supported for now."); + solAssert( + _type && ( + _type->category() == Type::Category::Contract || + _type->category() == Type::Category::Integer + ), + "Only contracts or integer types supported for now." + ); return createAndGet(_type); } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 7ee12d6dd..aa888d26b 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -556,6 +556,22 @@ string IntegerType::toString(bool) const return prefix + util::toString(m_bits); } +u256 IntegerType::min() const +{ + if (isSigned()) + return s2u(s256(minValue())); + else + return u256(minValue()); +} + +u256 IntegerType::max() const +{ + if (isSigned()) + return s2u(s256(maxValue())); + else + return u256(maxValue()); +} + bigint IntegerType::minValue() const { if (isSigned()) @@ -3763,20 +3779,35 @@ MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const case Kind::MetaType: { solAssert( - m_typeArgument && m_typeArgument->category() == Type::Category::Contract, - "Only contracts supported for now" + m_typeArgument && ( + m_typeArgument->category() == Type::Category::Contract || + m_typeArgument->category() == Type::Category::Integer + ), + "Only contracts or integer types supported for now" ); - ContractDefinition const& contract = dynamic_cast(*m_typeArgument).contractDefinition(); - if (contract.canBeDeployed()) + + if (m_typeArgument->category() == Type::Category::Contract) + { + ContractDefinition const& contract = dynamic_cast(*m_typeArgument).contractDefinition(); + if (contract.canBeDeployed()) + return MemberList::MemberMap({ + {"creationCode", TypeProvider::array(DataLocation::Memory)}, + {"runtimeCode", TypeProvider::array(DataLocation::Memory)}, + {"name", TypeProvider::stringMemory()}, + }); + else + return MemberList::MemberMap({ + {"interfaceId", TypeProvider::fixedBytes(4)}, + }); + } + else if (m_typeArgument->category() == Type::Category::Integer) + { + IntegerType const* integerTypePointer = dynamic_cast(m_typeArgument); return MemberList::MemberMap({ - {"creationCode", TypeProvider::array(DataLocation::Memory)}, - {"runtimeCode", TypeProvider::array(DataLocation::Memory)}, - {"name", TypeProvider::stringMemory()}, - }); - else - return MemberList::MemberMap({ - {"interfaceId", TypeProvider::fixedBytes(4)}, + {"min", integerTypePointer}, + {"max", integerTypePointer}, }); + } } } solAssert(false, "Unknown kind of magic."); diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 974bae4a3..d549d4f24 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -452,6 +452,9 @@ public: unsigned numBits() const { return m_bits; } bool isSigned() const { return m_modifier == Modifier::Signed; } + u256 min() const; + u256 max() const; + bigint minValue() const; bigint maxValue() const; diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 14b0d763b..e33fa608a 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1591,6 +1591,16 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) result ^= fromBigEndian(function.first.ref()); m_context << (u256{result} << (256 - 32)); } + else if (member == "min" || member == "max") + { + MagicType const* arg = dynamic_cast(_memberAccess.expression().annotation().type); + IntegerType const* integerType = dynamic_cast(arg->typeArgument()); + + if (member == "min") + m_context << integerType->min(); + else + m_context << integerType->max(); + } else if ((set{"encode", "encodePacked", "encodeWithSelector", "encodeWithSignature", "decode"}).count(member)) { // no-op diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index f795e0e98..8e7d9b18b 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -477,12 +477,16 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp) return false; } + if (commonType->category() == Type::Category::RationalNumber) + { + define(_binOp) << toCompactHexWithPrefix(commonType->literalValue(nullptr)) << "\n"; + return false; // skip sub-expressions + } + _binOp.leftExpression().accept(*this); _binOp.rightExpression().accept(*this); - if (commonType->category() == Type::Category::RationalNumber) - define(_binOp) << toCompactHexWithPrefix(commonType->literalValue(nullptr)) << "\n"; - else if (TokenTraits::isCompareOp(op)) + if (TokenTraits::isCompareOp(op)) { if (auto type = dynamic_cast(commonType)) { @@ -1175,6 +1179,16 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) result ^= fromBigEndian(function.first.ref()); define(_memberAccess) << formatNumber(u256{result} << (256 - 32)) << "\n"; } + else if (member == "min" || member == "max") + { + MagicType const* arg = dynamic_cast(_memberAccess.expression().annotation().type); + IntegerType const* integerType = dynamic_cast(arg->typeArgument()); + + if (member == "min") + define(_memberAccess) << formatNumber(integerType->min()) << "\n"; + else + define(_memberAccess) << formatNumber(integerType->max()) << "\n"; + } else if (set{"encode", "encodePacked", "encodeWithSelector", "encodeWithSignature", "decode"}.count(member)) { // no-op diff --git a/test/libsolidity/semanticTests/integer/basic.sol b/test/libsolidity/semanticTests/integer/basic.sol new file mode 100644 index 000000000..7c31e3888 --- /dev/null +++ b/test/libsolidity/semanticTests/integer/basic.sol @@ -0,0 +1,24 @@ +contract C { + function basic() public pure returns(bool) { + uint uint_min = type(uint).min; + require(uint_min == 0); + + uint uint_max = type(uint).max; + require(uint_max == 2**256 - 1); + require(uint_max == 115792089237316195423570985008687907853269984665640564039457584007913129639935); + + int int_min = type(int).min; + require(int_min == -2**255); + require(int_min == -57896044618658097711785492504343953926634992332820282019728792003956564819968); + + int int_max = type(int).max; + require(int_max == 2**255 -1); + require(int_max == 57896044618658097711785492504343953926634992332820282019728792003956564819967); + + return true; + } +} +// ==== +// compileViaYul: also +// ---- +// basic() -> true diff --git a/test/libsolidity/semanticTests/integer/int.sol b/test/libsolidity/semanticTests/integer/int.sol new file mode 100644 index 000000000..79d685645 --- /dev/null +++ b/test/libsolidity/semanticTests/integer/int.sol @@ -0,0 +1,245 @@ +contract test { + + function intMinA() public pure returns (bool) { + + int8 int8_min = type(int8).min; + require(int8_min == -2**7); + + int16 int16_min = type(int16).min; + require(int16_min == -2**15); + + int24 int24_min = type(int24).min; + require(int24_min == -2**23); + + int32 int32_min = type(int32).min; + require(int32_min == -2**31); + + int40 int40_min = type(int40).min; + require(int40_min == -2**39); + + int48 int48_min = type(int48).min; + require(int48_min == -2**47); + + int56 int56_min = type(int56).min; + require(int56_min == -2**55); + + int64 int64_min = type(int64).min; + require(int64_min == -2**63); + + return true; + } + + function intMinB() public pure returns(bool) { + + int72 int72_min = type(int72).min; + require(int72_min == -2**71); + + int80 int80_min = type(int80).min; + require(int80_min == -2**79); + + int88 int88_min = type(int88).min; + require(int88_min == -2**87); + + int96 int96_min = type(int96).min; + require(int96_min == -2**95); + + int104 int104_min = type(int104).min; + require(int104_min == -2**103); + + int112 int112_min = type(int112).min; + require(int112_min == -2**111); + + int120 int120_min = type(int120).min; + require(int120_min == -2**119); + + int128 int128_min = type(int128).min; + require(int128_min == -2**127); + + return true; + } + + function intMinC() public pure returns (bool) { + + int136 int136_min = type(int136).min; + require(int136_min == -2**135); + + int144 int144_min = type(int144).min; + require(int144_min == -2**143); + + int152 int152_min = type(int152).min; + require(int152_min == -2**151); + + int160 int160_min = type(int160).min; + require(int160_min == -2**159); + + int168 int168_min = type(int168).min; + require(int168_min == -2**167); + + int176 int176_min = type(int176).min; + require(int176_min == -2**175); + + int184 int184_min = type(int184).min; + require(int184_min == -2**183); + + int192 int192_min = type(int192).min; + require(int192_min == -2**191); + + return true; + } + + function intMinD() public pure returns(bool) { + + int200 int200_min = type(int200).min; + require(int200_min == -2**199); + + int208 int208_min = type(int208).min; + require(int208_min == -2**207); + + int216 int216_min = type(int216).min; + require(int216_min == -2**215); + + int224 int224_min = type(int224).min; + require(int224_min == -2**223); + + int232 int232_min = type(int232).min; + require(int232_min == -2**231); + + int240 int240_min = type(int240).min; + require(int240_min == -2**239); + + int248 int248_min = type(int248).min; + require(int248_min == -2**247); + + int256 int256_min = type(int256).min; + require(int256_min == -2**255); + + return true; + } + + function intMaxA() public pure returns (bool) { + + int8 int8_max = type(int8).max; + require(int8_max == 2**7-1); + + int16 int16_max = type(int16).max; + require(int16_max == 2**15-1); + + int24 int24_max = type(int24).max; + require(int24_max == 2**23-1); + + int32 int32_max = type(int32).max; + require(int32_max == 2**31-1); + + int40 int40_max = type(int40).max; + require(int40_max == 2**39-1); + + int48 int48_max = type(int48).max; + require(int48_max == 2**47-1); + + int56 int56_max = type(int56).max; + require(int56_max == 2**55-1); + + int64 int64_max = type(int64).max; + require(int64_max == 2**63-1); + + return true; + } + + function intMaxB() public pure returns(bool) { + + int72 int72_max = type(int72).max; + require(int72_max == 2**71-1); + + int80 int80_max = type(int80).max; + require(int80_max == 2**79-1); + + int88 int88_max = type(int88).max; + require(int88_max == 2**87-1); + + int96 int96_max = type(int96).max; + require(int96_max == 2**95-1); + + int104 int104_max = type(int104).max; + require(int104_max == 2**103-1); + + int112 int112_max = type(int112).max; + require(int112_max == 2**111-1); + + int120 int120_max = type(int120).max; + require(int120_max == 2**119-1); + + int128 int128_max = type(int128).max; + require(int128_max == 2**127-1); + + return true; + } + + function intMaxC() public pure returns (bool) { + + int136 int136_max = type(int136).max; + require(int136_max == 2**135-1); + + int144 int144_max = type(int144).max; + require(int144_max == 2**143-1); + + int152 int152_max = type(int152).max; + require(int152_max == 2**151-1); + + int160 int160_max = type(int160).max; + require(int160_max == 2**159-1); + + int168 int168_max = type(int168).max; + require(int168_max == 2**167-1); + + int176 int176_max = type(int176).max; + require(int176_max == 2**175-1); + + int184 int184_max = type(int184).max; + require(int184_max == 2**183-1); + + int192 int192_max = type(int192).max; + require(int192_max == 2**191-1); + + return true; + } + + function intMaxD() public pure returns(bool) { + + int200 int200_max = type(int200).max; + require(int200_max == 2**199-1); + + int208 int208_max = type(int208).max; + require(int208_max == 2**207-1); + + int216 int216_max = type(int216).max; + require(int216_max == 2**215-1); + + int224 int224_max = type(int224).max; + require(int224_max == 2**223-1); + + int232 int232_max = type(int232).max; + require(int232_max == 2**231-1); + + int240 int240_max = type(int240).max; + require(int240_max == 2**239-1); + + int248 int248_max = type(int248).max; + require(int248_max == 2**247-1); + + int256 int256_max = type(int256).max; + require(int256_max == 2**255-1); + + return true; + } +} +// ==== +// compileViaYul: also +// ---- +// intMinA() -> true +// intMinB() -> true +// intMinC() -> true +// intMinD() -> true +// intMaxA() -> true +// intMaxB() -> true +// intMaxC() -> true +// intMaxD() -> true diff --git a/test/libsolidity/semanticTests/integer/uint.sol b/test/libsolidity/semanticTests/integer/uint.sol new file mode 100644 index 000000000..a2f3746c2 --- /dev/null +++ b/test/libsolidity/semanticTests/integer/uint.sol @@ -0,0 +1,244 @@ +contract test { + + function uintMinA() public pure returns(bool) { + + uint8 uint8_min = type(uint8).min; + require(uint8_min == 0); + + uint16 uint16_min = type(uint16).min; + require(uint16_min == 0); + + uint24 uint24_min = type(uint24).min; + require(uint24_min == 0); + + uint32 uint32_min = type(uint32).min; + require(uint32_min == 0); + + uint40 uint40_min = type(uint40).min; + require(uint40_min == 0); + + uint48 uint48_min = type(uint48).min; + require(uint48_min == 0); + + uint56 uint56_min = type(uint56).min; + require(uint56_min == 0); + + uint64 uint64_min = type(uint64).min; + require(uint64_min == 0); + + return true; + } + + function uintMinB() public pure returns(bool) { + + uint72 uint72_min = type(uint72).min; + require(uint72_min == 0); + + uint80 uint80_min = type(uint80).min; + require(uint80_min == 0); + + uint88 uint88_min = type(uint88).min; + require(uint88_min == 0); + + uint96 uint96_min = type(uint96).min; + require(uint96_min == 0); + + uint104 uint104_min = type(uint104).min; + require(uint104_min == 0); + + uint112 uint112_min = type(uint112).min; + require(uint112_min == 0); + + uint120 uint120_min = type(uint120).min; + require(uint120_min == 0); + + uint128 uint128_min = type(uint128).min; + require(uint128_min == 0); + + return true; + } + + function uintMinC() public pure returns(bool) { + + uint136 uint136_min = type(uint136).min; + require(uint136_min == 0); + + uint144 uint144_min = type(uint144).min; + require(uint144_min == 0); + + uint152 uint152_min = type(uint152).min; + require(uint152_min == 0); + + uint160 uint160_min = type(uint160).min; + require(uint160_min == 0); + + uint168 uint168_min = type(uint168).min; + require(uint168_min == 0); + + uint176 uint176_min = type(uint176).min; + require(uint176_min == 0); + + uint184 uint184_min = type(uint184).min; + require(uint184_min == 0); + + uint192 uint192_min = type(uint192).min; + require(uint192_min == 0); + + return true; + } + + function uintMinD() public pure returns(bool) { + + uint200 uint200_min = type(uint200).min; + require(uint200_min == 0); + + uint208 uint208_min = type(uint208).min; + require(uint208_min == 0); + + uint216 uint216_min = type(uint216).min; + require(uint216_min == 0); + + uint224 uint224_min = type(uint224).min; + require(uint224_min == 0); + + uint232 uint232_min = type(uint232).min; + require(uint232_min == 0); + + uint240 uint240_min = type(uint240).min; + require(uint240_min == 0); + + uint248 uint248_min = type(uint248).min; + require(uint248_min == 0); + + uint256 uint256_min = type(uint256).min; + require(uint256_min == 0); + + return true; + } + + function uintMaxA() public pure returns (bool) { + + uint8 uint8_max = type(uint8).max; + require(uint8_max == 2**8-1); + + uint16 uint16_max = type(uint16).max; + require(uint16_max == 2**16-1); + + uint24 uint24_max = type(uint24).max; + require(uint24_max == 2**24-1); + + uint32 uint32_max = type(uint32).max; + require(uint32_max == 2**32-1); + + uint40 uint40_max = type(uint40).max; + require(uint40_max == 2**40-1); + + uint48 uint48_max = type(uint48).max; + require(uint48_max == 2**48-1); + + uint56 uint56_max = type(uint56).max; + require(uint56_max == 2**56-1); + + uint64 uint64_max = type(uint64).max; + require(uint64_max == 2**64-1); + + return true; + } + + function uintMaxB() public pure returns (bool) { + + uint72 uint72_max = type(uint72).max; + require(uint72_max == 2**72-1); + + uint80 uint80_max = type(uint80).max; + require(uint80_max == 2**80-1); + + uint88 uint88_max = type(uint88).max; + require(uint88_max == 2**88-1); + + uint96 uint96_max = type(uint96).max; + require(uint96_max == 2**96-1); + + uint104 uint104_max = type(uint104).max; + require(uint104_max == 2**104-1); + + uint112 uint112_max = type(uint112).max; + require(uint112_max == 2**112-1); + + uint120 uint120_max = type(uint120).max; + require(uint120_max == 2**120-1); + + uint128 uint128_max = type(uint128).max; + require(uint128_max == 2**128-1); + + return true; + } + + function uintMaxC() public pure returns (bool) { + + uint136 uint136_max = type(uint136).max; + require(uint136_max == 2**136-1); + + uint144 uint144_max = type(uint144).max; + require(uint144_max == 2**144-1); + + uint152 uint152_max = type(uint152).max; + require(uint152_max == 2**152-1); + + uint160 uint160_max = type(uint160).max; + require(uint160_max == 2**160-1); + + uint168 uint168_max = type(uint168).max; + require(uint168_max == 2**168-1); + + uint176 uint176_max = type(uint176).max; + require(uint176_max == 2**176-1); + + uint184 uint184_max = type(uint184).max; + require(uint184_max == 2**184-1); + + uint192 uint192_max = type(uint192).max; + require(uint192_max == 2**192-1); + + return true; + } + + function uintMaxD() public pure returns(bool) { + uint200 uint200_max = type(uint200).max; + require(uint200_max == 2**200-1); + + uint208 uint208_max = type(uint208).max; + require(uint208_max == 2**208-1); + + uint216 uint216_max = type(uint216).max; + require(uint216_max == 2**216-1); + + uint224 uint224_max = type(uint224).max; + require(uint224_max == 2**224-1); + + uint232 uint232_max = type(uint232).max; + require(uint232_max == 2**232-1); + + uint240 uint240_max = type(uint240).max; + require(uint240_max == 2**240-1); + + uint248 uint248_max = type(uint248).max; + require(uint248_max == 2**248-1); + + uint256 uint256_max = type(uint256).max; + require(uint256_max == 2**256-1); + + return true; + } +} +// ==== +// compileViaYul: also +// ---- +// uintMinA() -> true +// uintMinB() -> true +// uintMinC() -> true +// uintMinD() -> true +// uintMaxA() -> true +// uintMaxB() -> true +// uintMaxC() -> true +// uintMaxD() -> true diff --git a/test/libsolidity/syntaxTests/metaTypes/typeRecursive.sol b/test/libsolidity/syntaxTests/metaTypes/typeRecursive.sol index 0ce06786e..903338a43 100644 --- a/test/libsolidity/syntaxTests/metaTypes/typeRecursive.sol +++ b/test/libsolidity/syntaxTests/metaTypes/typeRecursive.sol @@ -4,5 +4,5 @@ contract Test { } } // ---- -// TypeError: (65-75): Invalid type for argument in function call. Contract type required, but type(contract Test) provided. -// TypeError: (60-76): Invalid type for argument in function call. Contract type required, but tuple() provided. +// TypeError: (65-75): Invalid type for argument in the function call. A contract type or an integer type is required, but type(contract Test) provided. +// TypeError: (60-76): Invalid type for argument in the function call. A contract type or an integer type is required, but tuple() provided. diff --git a/test/libsolidity/syntaxTests/metaTypes/unsupportedArgForType.sol b/test/libsolidity/syntaxTests/metaTypes/unsupportedArgForType.sol index 5c27d42f2..94f498922 100644 --- a/test/libsolidity/syntaxTests/metaTypes/unsupportedArgForType.sol +++ b/test/libsolidity/syntaxTests/metaTypes/unsupportedArgForType.sol @@ -6,4 +6,4 @@ contract Test { } } // ---- -// TypeError: (154-155): Invalid type for argument in function call. Contract type required, but type(struct Test.S) provided. +// TypeError: (154-155): Invalid type for argument in the function call. A contract type or an integer type is required, but type(struct Test.S) provided. From 338e55be10982f2ea054f7c6aba9139d0e749852 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 11 May 2020 10:44:20 +0100 Subject: [PATCH 51/89] Add header guard to two files --- libyul/AsmJsonConverter.h | 2 ++ tools/solidityUpgrade/SourceTransform.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/libyul/AsmJsonConverter.h b/libyul/AsmJsonConverter.h index 360fa6a36..b350689fc 100644 --- a/libyul/AsmJsonConverter.h +++ b/libyul/AsmJsonConverter.h @@ -20,6 +20,8 @@ * Converts inline assembly AST to JSON format */ +#pragma once + #include #include #include diff --git a/tools/solidityUpgrade/SourceTransform.h b/tools/solidityUpgrade/SourceTransform.h index 2b42471c1..a33a1d97e 100644 --- a/tools/solidityUpgrade/SourceTransform.h +++ b/tools/solidityUpgrade/SourceTransform.h @@ -15,6 +15,8 @@ along with solidity. If not, see . */ +#pragma once + #include #include From e4e200f29f83f1c6d55036b76ce5d76dae00fed4 Mon Sep 17 00:00:00 2001 From: Harikrishnan Mulackal Date: Mon, 11 May 2020 14:13:51 +0530 Subject: [PATCH 52/89] Changelog and tests --- Changelog.md | 2 +- .../semanticTests/arithmetics/addmod_mulmod.sol | 2 ++ .../array/create_memory_array_too_large.sol | 2 ++ .../syntaxTests/metaTypes/contract_min.sol | 7 +++++++ .../syntaxTests/metaTypes/int_name.sol | 7 +++++++ .../syntaxTests/metaTypes/integer.sol | 12 ++++++++++++ .../syntaxTests/metaTypes/integer_err.sol | 15 +++++++++++++++ .../syntaxTests/metaTypes/integer_pure.sol | 16 ++++++++++++++++ 8 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 test/libsolidity/syntaxTests/metaTypes/contract_min.sol create mode 100644 test/libsolidity/syntaxTests/metaTypes/int_name.sol create mode 100644 test/libsolidity/syntaxTests/metaTypes/integer.sol create mode 100644 test/libsolidity/syntaxTests/metaTypes/integer_err.sol create mode 100644 test/libsolidity/syntaxTests/metaTypes/integer_pure.sol diff --git a/Changelog.md b/Changelog.md index 0b3749be9..52dcb07da 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,7 +1,7 @@ ### 0.6.8 (unreleased) Language Features: - + * Implemented ``type(X).min`` and ``type(X).max`` for every integer type ``X`` that returns the smallest and largest value representable by the type. Compiler Features: diff --git a/test/libsolidity/semanticTests/arithmetics/addmod_mulmod.sol b/test/libsolidity/semanticTests/arithmetics/addmod_mulmod.sol index d1e9f5c20..ea2aa3d8f 100644 --- a/test/libsolidity/semanticTests/arithmetics/addmod_mulmod.sol +++ b/test/libsolidity/semanticTests/arithmetics/addmod_mulmod.sol @@ -8,5 +8,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // test() -> 0 diff --git a/test/libsolidity/semanticTests/array/create_memory_array_too_large.sol b/test/libsolidity/semanticTests/array/create_memory_array_too_large.sol index c42f84862..541a037a2 100644 --- a/test/libsolidity/semanticTests/array/create_memory_array_too_large.sol +++ b/test/libsolidity/semanticTests/array/create_memory_array_too_large.sol @@ -19,6 +19,8 @@ contract C { y[0] = 23; return x[2]; }} +// ==== +// compileViaYul: also // ---- // f() -> FAILURE // g() -> FAILURE diff --git a/test/libsolidity/syntaxTests/metaTypes/contract_min.sol b/test/libsolidity/syntaxTests/metaTypes/contract_min.sol new file mode 100644 index 000000000..a922593b3 --- /dev/null +++ b/test/libsolidity/syntaxTests/metaTypes/contract_min.sol @@ -0,0 +1,7 @@ +contract Min { + function contractMin() public { + type(Min).min; + } +} +// ---- +// TypeError: (50-63): Member "min" not found or not visible after argument-dependent lookup in type(contract Min). diff --git a/test/libsolidity/syntaxTests/metaTypes/int_name.sol b/test/libsolidity/syntaxTests/metaTypes/int_name.sol new file mode 100644 index 000000000..b6c4f49a5 --- /dev/null +++ b/test/libsolidity/syntaxTests/metaTypes/int_name.sol @@ -0,0 +1,7 @@ +contract test { + function intName() public { + type(int).name; + } +} +// ---- +// TypeError: (47-61): Member "name" not found or not visible after argument-dependent lookup in type(int256). diff --git a/test/libsolidity/syntaxTests/metaTypes/integer.sol b/test/libsolidity/syntaxTests/metaTypes/integer.sol new file mode 100644 index 000000000..31bd069ec --- /dev/null +++ b/test/libsolidity/syntaxTests/metaTypes/integer.sol @@ -0,0 +1,12 @@ +contract Test { + function basic() public pure { + uint uintMax = type(uint).max; + uintMax; + int intMax = type(int).max; + intMax; + uint uintMin = type(uint).min; + uintMin; + int intMin = type(int).min; + intMin; + } +} diff --git a/test/libsolidity/syntaxTests/metaTypes/integer_err.sol b/test/libsolidity/syntaxTests/metaTypes/integer_err.sol new file mode 100644 index 000000000..5a0610638 --- /dev/null +++ b/test/libsolidity/syntaxTests/metaTypes/integer_err.sol @@ -0,0 +1,15 @@ +contract Test { + function assignment() public { + uint8 uint8Min = type(int).min; + uint uintMin = type(int).min; + + if (type(int).min == 2**256 - 1) { + uintMin; + } + + } +} +// ---- +// TypeError: (59-89): Type int256 is not implicitly convertible to expected type uint8. +// TypeError: (99-127): Type int256 is not implicitly convertible to expected type uint256. +// TypeError: (142-169): Operator == not compatible with types int256 and int_const 1157...(70 digits omitted)...9935 diff --git a/test/libsolidity/syntaxTests/metaTypes/integer_pure.sol b/test/libsolidity/syntaxTests/metaTypes/integer_pure.sol new file mode 100644 index 000000000..2eb115e0f --- /dev/null +++ b/test/libsolidity/syntaxTests/metaTypes/integer_pure.sol @@ -0,0 +1,16 @@ +contract test { + + function viewAssignment() public view { + int min = type(int).min; + min; + } + + function assignment() public { + int max = type(int).max; + max; + } + +} +// ---- +// Warning: (21-112): Function state mutability can be restricted to pure +// Warning: (118-200): Function state mutability can be restricted to pure From c31a93b3f24e17ee8676de3e76b0cdab9cb7cc01 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Sun, 26 Apr 2020 00:35:28 +0100 Subject: [PATCH 53/89] Remove boost::filesystem where it is not needed A two uses in CommonIO remain for the compiler (plus testing/tools use it extensively) --- libsolidity/CMakeLists.txt | 2 +- libsolidity/formal/CHCSmtLib2Interface.cpp | 1 - libsolidity/formal/SMTLib2Interface.cpp | 1 - libsolutil/CommonIO.h | 1 - test/CMakeLists.txt | 2 +- tools/CMakeLists.txt | 2 +- 6 files changed, 3 insertions(+), 6 deletions(-) diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index fe1bbad7a..5db82b368 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -166,7 +166,7 @@ if (NOT (${Z3_FOUND} OR ${CVC4_FOUND})) endif() add_library(solidity ${sources} ${z3_SRCS} ${cvc4_SRCS}) -target_link_libraries(solidity PUBLIC yul evmasm langutil solutil Boost::boost Boost::filesystem Boost::system) +target_link_libraries(solidity PUBLIC yul evmasm langutil solutil Boost::boost Boost::system) if (${Z3_FOUND}) target_link_libraries(solidity PUBLIC z3::libz3) diff --git a/libsolidity/formal/CHCSmtLib2Interface.cpp b/libsolidity/formal/CHCSmtLib2Interface.cpp index 1b58b791e..4b52b7d5a 100644 --- a/libsolidity/formal/CHCSmtLib2Interface.cpp +++ b/libsolidity/formal/CHCSmtLib2Interface.cpp @@ -21,7 +21,6 @@ #include #include -#include #include #include diff --git a/libsolidity/formal/SMTLib2Interface.cpp b/libsolidity/formal/SMTLib2Interface.cpp index 76527baeb..339a0a8ad 100644 --- a/libsolidity/formal/SMTLib2Interface.cpp +++ b/libsolidity/formal/SMTLib2Interface.cpp @@ -21,7 +21,6 @@ #include #include -#include #include #include diff --git a/libsolutil/CommonIO.h b/libsolutil/CommonIO.h index be763c42f..38c8f564a 100644 --- a/libsolutil/CommonIO.h +++ b/libsolutil/CommonIO.h @@ -24,7 +24,6 @@ #pragma once #include -#include #include #include diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d63d9aec5..ff545faf3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -187,7 +187,7 @@ add_executable(soltest ${sources} ${libsolidity_util_sources} ${yul_phaser_sources} ) -target_link_libraries(soltest PRIVATE libsolc yul solidity yulInterpreter evmasm solutil Boost::boost Boost::program_options Boost::unit_test_framework evmc) +target_link_libraries(soltest PRIVATE libsolc yul solidity yulInterpreter evmasm solutil Boost::boost Boost::filesystem Boost::program_options Boost::unit_test_framework evmc) # Special compilation flag for Visual Studio (version 2019 at least affected) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 241a80f46..f6b87c9f6 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -42,6 +42,6 @@ add_executable(yul-phaser yulPhaser/SimulationRNG.h yulPhaser/SimulationRNG.cpp ) -target_link_libraries(yul-phaser PRIVATE solidity Boost::program_options) +target_link_libraries(yul-phaser PRIVATE solidity Boost::filesystem Boost::program_options) install(TARGETS yul-phaser DESTINATION "${CMAKE_INSTALL_BINDIR}") From ad1d2558eb9835eebd984b5e5e80f63a758a2104 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 11 May 2020 11:36:11 +0100 Subject: [PATCH 54/89] Drop Boost::system from libsolidity --- libsolidity/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index 5db82b368..96ccff9e4 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -166,7 +166,7 @@ if (NOT (${Z3_FOUND} OR ${CVC4_FOUND})) endif() add_library(solidity ${sources} ${z3_SRCS} ${cvc4_SRCS}) -target_link_libraries(solidity PUBLIC yul evmasm langutil solutil Boost::boost Boost::system) +target_link_libraries(solidity PUBLIC yul evmasm langutil solutil Boost::boost) if (${Z3_FOUND}) target_link_libraries(solidity PUBLIC z3::libz3) From 091abcea8cbe42d0e3082d276b8ffae99c745e24 Mon Sep 17 00:00:00 2001 From: Harikrishnan Mulackal Date: Mon, 11 May 2020 16:19:55 +0530 Subject: [PATCH 55/89] Updated docs for type(X).min and type(X).max --- docs/cheatsheet.rst | 2 ++ docs/types/value-types.rst | 3 +++ docs/units-and-global-variables.rst | 16 ++++++++++++---- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/docs/cheatsheet.rst b/docs/cheatsheet.rst index 5d6169a48..e8ecb0af6 100644 --- a/docs/cheatsheet.rst +++ b/docs/cheatsheet.rst @@ -122,6 +122,8 @@ Global Variables - ``type(C).creationCode`` (``bytes memory``): creation bytecode of the given contract, see :ref:`Type Information`. - ``type(C).runtimeCode`` (``bytes memory``): runtime bytecode of the given contract, see :ref:`Type Information`. - ``type(I).interfaceId`` (``bytes4``): value containing the EIP-165 interface identifier of the given interface, see :ref:`Type Information`. +- ``type(X).min`` (``X``): the minimum value representable by the integer type ``X``, see :ref:`Type Information`. +- ``type(X).max`` (``X``): the maximum value representable by the integer type ``X``, see :ref:`Type Information`. .. note:: Do not rely on ``block.timestamp``, ``now`` and ``blockhash`` as a source of randomness, diff --git a/docs/types/value-types.rst b/docs/types/value-types.rst index 0301a8ad5..65cbd5504 100644 --- a/docs/types/value-types.rst +++ b/docs/types/value-types.rst @@ -40,6 +40,9 @@ Operators: * Shift operators: ``<<`` (left shift), ``>>`` (right shift) * Arithmetic operators: ``+``, ``-``, unary ``-``, ``*``, ``/``, ``%`` (modulo), ``**`` (exponentiation) +For an integer type ``X``, you can use ``type(X).min`` and ``type(X).max`` to +access the minimum and maximum value representable by the type. + .. warning:: Integers in Solidity are restricted to a certain range. For example, with ``uint32``, this is ``0`` up to ``2**32 - 1``. diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst index 54eed07a9..22c6fc12d 100644 --- a/docs/units-and-global-variables.rst +++ b/docs/units-and-global-variables.rst @@ -294,10 +294,11 @@ Furthermore, all functions of the current contract are callable directly includi Type Information ---------------- -The expression ``type(X)`` can be used to retrieve information about the -type ``X``. Currently, there is limited support for this feature, but -it might be expanded in the future. The following properties are -available for a contract type ``C``: +The expression ``type(X)`` can be used to retrieve information about the type +``X``. Currently, there is limited support for this feature (``X`` can be either +a contract or an integer type) but it might be expanded in the future. + +The following properties are available for a contract type ``C``: ``type(C).name`` The name of the contract. @@ -328,3 +329,10 @@ for an interface type ``I``: interface identifier of the given interface ``I``. This identifier is defined as the ``XOR`` of all function selectors defined within the interface itself - excluding all inherited functions. +The following properties are available for an integer type ``I``: + +``type(I).min`` + The smallest value representable by type ``I``. + +``type(I).max`` + The largest value representable by type ``I``. From 76dfda7c1c03e728d96a29e2a4db5dc2a56bf7a8 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 11 May 2020 12:38:49 +0100 Subject: [PATCH 56/89] Replace boost:variant with std::variant in StandardCompiler --- libsolidity/interface/StandardCompiler.cpp | 18 +++++++++--------- libsolidity/interface/StandardCompiler.h | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 15989dcf3..65b948bb2 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -32,7 +32,7 @@ #include #include -#include +#include #include #include @@ -491,7 +491,7 @@ std::optional checkOutputSelection(Json::Value const& _outputSelect } /// Validates the optimizer settings and returns them in a parsed object. /// On error returns the json-formatted error message. -boost::variant parseOptimizerSettings(Json::Value const& _jsonInput) +std::variant parseOptimizerSettings(Json::Value const& _jsonInput) { if (auto result = checkOptimizerKeys(_jsonInput)) return *result; @@ -552,7 +552,7 @@ boost::variant parseOptimizerSettings(Json::Valu } -boost::variant StandardCompiler::parseInput(Json::Value const& _input) +std::variant StandardCompiler::parseInput(Json::Value const& _input) { InputsAndSettings ret; @@ -740,10 +740,10 @@ boost::variant StandardCompile if (settings.isMember("optimizer")) { auto optimiserSettings = parseOptimizerSettings(settings["optimizer"]); - if (optimiserSettings.type() == typeid(Json::Value)) - return boost::get(std::move(optimiserSettings)); // was an error + if (std::holds_alternative(optimiserSettings)) + return std::get(std::move(optimiserSettings)); // was an error else - ret.optimiserSettings = boost::get(std::move(optimiserSettings)); + ret.optimiserSettings = std::get(std::move(optimiserSettings)); } Json::Value jsonLibraries = settings.get("libraries", Json::Value(Json::objectValue)); @@ -1155,9 +1155,9 @@ Json::Value StandardCompiler::compile(Json::Value const& _input) noexcept try { auto parsed = parseInput(_input); - if (parsed.type() == typeid(Json::Value)) - return boost::get(std::move(parsed)); - InputsAndSettings settings = boost::get(std::move(parsed)); + if (std::holds_alternative(parsed)) + return std::get(std::move(parsed)); + InputsAndSettings settings = std::get(std::move(parsed)); if (settings.language == "Solidity") return compileSolidity(std::move(settings)); else if (settings.language == "Yul") diff --git a/libsolidity/interface/StandardCompiler.h b/libsolidity/interface/StandardCompiler.h index 885417d8b..d1a1489c3 100644 --- a/libsolidity/interface/StandardCompiler.h +++ b/libsolidity/interface/StandardCompiler.h @@ -24,9 +24,9 @@ #include -#include #include #include +#include namespace solidity::frontend { @@ -73,7 +73,7 @@ private: /// Parses the input json (and potentially invokes the read callback) and either returns /// it in condensed form or an error as a json object. - boost::variant parseInput(Json::Value const& _input); + std::variant parseInput(Json::Value const& _input); Json::Value compileSolidity(InputsAndSettings _inputsAndSettings); Json::Value compileYul(InputsAndSettings _inputsAndSettings); From 81397dc2c51e2a077a72009025ef736dc374de59 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 11 May 2020 13:15:53 +0100 Subject: [PATCH 57/89] Remove "using boost*;" statements --- libyul/Utilities.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/libyul/Utilities.cpp b/libyul/Utilities.cpp index 8789381b7..a797258eb 100644 --- a/libyul/Utilities.cpp +++ b/libyul/Utilities.cpp @@ -38,9 +38,6 @@ using namespace solidity; using namespace solidity::yul; using namespace solidity::util; -using boost::split; -using boost::is_any_of; - string solidity::yul::reindent(string const& _code) { int constexpr indentationWidth = 4; @@ -55,7 +52,7 @@ string solidity::yul::reindent(string const& _code) }; vector lines; - split(lines, _code, is_any_of("\n")); + boost::split(lines, _code, boost::is_any_of("\n")); for (string& line: lines) boost::trim(line); From fe431320033d341c782297f38e5e1fb42c791ead Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Mon, 11 May 2020 14:59:06 +0200 Subject: [PATCH 58/89] Fix clang v10 compilation errors --- libsolidity/analysis/GlobalContext.cpp | 2 +- libsolidity/analysis/ImmutableValidator.cpp | 2 +- libsolidity/codegen/ContractCompiler.cpp | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libsolidity/analysis/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp index a0764edba..d08f11979 100644 --- a/libsolidity/analysis/GlobalContext.cpp +++ b/libsolidity/analysis/GlobalContext.cpp @@ -123,7 +123,7 @@ vector GlobalContext::declarations() const { vector declarations; declarations.reserve(m_magicVariables.size()); - for (ASTPointer const& variable: m_magicVariables) + for (ASTPointer const& variable: m_magicVariables) declarations.push_back(variable.get()); return declarations; } diff --git a/libsolidity/analysis/ImmutableValidator.cpp b/libsolidity/analysis/ImmutableValidator.cpp index 0fad0a66d..e4fcfadcf 100644 --- a/libsolidity/analysis/ImmutableValidator.cpp +++ b/libsolidity/analysis/ImmutableValidator.cpp @@ -43,7 +43,7 @@ void ImmutableValidator::analyze() visitCallableIfNew(*contract->constructor()); for (ContractDefinition const* contract: linearizedContracts) - for (std::shared_ptr const inheritSpec: contract->baseContracts()) + for (std::shared_ptr const& inheritSpec: contract->baseContracts()) if (auto args = inheritSpec->arguments()) ASTNode::listAccept(*args, *this); diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 319d7a7ad..678921824 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -587,13 +587,13 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) if (!_function.isConstructor()) // adding 1 for return address. m_context.adjustStackOffset(parametersSize + 1); - for (ASTPointer const& variable: _function.parameters()) + for (ASTPointer const& variable: _function.parameters()) { m_context.addVariable(*variable, parametersSize); parametersSize -= variable->annotation().type->sizeOnStack(); } - for (ASTPointer const& variable: _function.returnParameters()) + for (ASTPointer const& variable: _function.returnParameters()) appendStackVariableInitialisation(*variable); if (_function.isConstructor()) @@ -650,7 +650,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) if (stackLayout[i] != i) solAssert(false, "Invalid stack layout on cleanup."); - for (ASTPointer const& variable: _function.parameters() + _function.returnParameters()) + for (ASTPointer const& variable: _function.parameters() + _function.returnParameters()) m_context.removeVariable(*variable); m_context.adjustStackOffset(-(int)c_returnValuesSize); From c0bf5292367b26bb014fa7cde4524c1dd4997ad0 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 4 May 2020 12:50:31 +0200 Subject: [PATCH 59/89] Support bare calls. --- .../codegen/ir/IRGeneratorForStatements.cpp | 193 +++++++++++------- .../codegen/ir/IRGeneratorForStatements.h | 7 + libsolidity/codegen/ir/IRVariable.cpp | 2 +- .../abiEncoderV1/abi_encode_call.sol | 2 + .../builtinFunctions/sha256_empty.sol | 2 - ...vm_exceptions_in_constructor_call_fail.sol | 2 + .../delegatecall_return_value.sol | 1 + ...elegatecall_return_value_pre_byzantium.sol | 1 + ...iccall_for_view_and_pure_pre_byzantium.sol | 1 + 9 files changed, 136 insertions(+), 75 deletions(-) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index ef971b1f4..7faf0d43c 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -706,10 +706,12 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) } case FunctionType::Kind::External: case FunctionType::Kind::DelegateCall: + appendExternalFunctionCall(_functionCall, arguments); + break; case FunctionType::Kind::BareCall: case FunctionType::Kind::BareDelegateCall: case FunctionType::Kind::BareStaticCall: - appendExternalFunctionCall(_functionCall, arguments); + appendBareCall(_functionCall, arguments); break; case FunctionType::Kind::BareCallCode: solAssert(false, "Callcode has been removed."); @@ -1755,18 +1757,20 @@ void IRGeneratorForStatements::appendExternalFunctionCall( ) { FunctionType const& funType = dynamic_cast(type(_functionCall.expression())); - solAssert( - funType.takesArbitraryParameters() || - _arguments.size() == funType.parameterTypes().size(), "" - ); - solUnimplementedAssert(!funType.bound(), ""); + solAssert(!funType.takesArbitraryParameters(), ""); + solAssert(_arguments.size() == funType.parameterTypes().size(), ""); + solAssert(!funType.isBareCall(), ""); FunctionType::Kind const funKind = funType.kind(); - solAssert(funKind != FunctionType::Kind::BareStaticCall || m_context.evmVersion().hasStaticCall(), ""); - solAssert(funKind != FunctionType::Kind::BareCallCode, "Callcode has been removed."); + solAssert( + funKind == FunctionType::Kind::External || funKind == FunctionType::Kind::DelegateCall, + "Can only be used for regular external calls." + ); - bool const isDelegateCall = funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::DelegateCall; - bool const useStaticCall = funKind == FunctionType::Kind::BareStaticCall || (funType.stateMutability() <= StateMutability::View && m_context.evmVersion().hasStaticCall()); + solUnimplementedAssert(!funType.bound(), ""); + + bool const isDelegateCall = funKind == FunctionType::Kind::DelegateCall; + bool const useStaticCall = funType.stateMutability() <= StateMutability::View && m_context.evmVersion().hasStaticCall(); ReturnInfo const returnInfo{m_context.evmVersion(), funType}; @@ -1778,7 +1782,6 @@ void IRGeneratorForStatements::appendExternalFunctionCall( argumentStrings += IRVariable(*arg).stackSlots(); } - solUnimplementedAssert(funKind != FunctionType::Kind::ECRecover, ""); if (!m_context.evmVersion().canOverchargeGasForCall()) { @@ -1790,33 +1793,19 @@ void IRGeneratorForStatements::appendExternalFunctionCall( m_code << "mstore(add(" << freeMemory() << ", " << to_string(returnInfo.estimatedReturnSize) << "), 0)\n"; } - ABIFunctions abi(m_context.evmVersion(), m_context.revertStrings(), m_context.functionCollector()); - Whiskers templ(R"( - - if iszero(extcodesize(
)) { revert(0, 0) } - + if iszero(extcodesize(
)) { revert(0, 0) } // storage for arguments and returned data let := - - - mstore(, ()) - - let := ( - - - - add(, 4) - - - ) + mstore(, ()) + let := (add(, 4) ) let := (,
, , , sub(, ), , ) if iszero() { () } - let + let if { // copy dynamic return data out @@ -1827,12 +1816,11 @@ void IRGeneratorForStatements::appendExternalFunctionCall( mstore(, add(, ())) // decode return parameters from external try-call into retVars - := (, add(, )) + := (, add(, )) } )"); templ("pos", m_context.newYulVariable()); templ("end", m_context.newYulVariable()); - templ("bareCall", funType.isBareCall()); if (_functionCall.annotation().tryCall) templ("success", m_context.trySuccessConditionVariable(_functionCall)); else @@ -1840,17 +1828,8 @@ void IRGeneratorForStatements::appendExternalFunctionCall( templ("freeMemory", freeMemory()); templ("shl28", m_utils.shiftLeftFunction(8 * (32 - 4))); - if (!funType.isBareCall()) - templ("funId", IRVariable(_functionCall.expression()).part("functionIdentifier").name()); - - if (funKind == FunctionType::Kind::ECRecover) - templ("address", "1"); - else if (funKind == FunctionType::Kind::SHA256) - templ("address", "2"); - else if (funKind == FunctionType::Kind::RIPEMD160) - templ("address", "3"); - else - templ("address", IRVariable(_functionCall.expression()).part("address").name()); + templ("funId", IRVariable(_functionCall.expression()).part("functionIdentifier").name()); + templ("address", IRVariable(_functionCall.expression()).part("address").name()); // Always use the actual return length, and not our calculated expected length, if returndatacopy is supported. // This ensures it can catch badly formatted input from external calls. @@ -1863,50 +1842,27 @@ void IRGeneratorForStatements::appendExternalFunctionCall( string const retVars = IRVariable(_functionCall).commaSeparatedList(); templ("retVars", retVars); - templ("hasRetVars", !retVars.empty()); solAssert(retVars.empty() == returnInfo.returnTypes.empty(), ""); templ("roundUp", m_utils.roundUpFunction()); - templ("abiDecode", abi.tupleDecoder(returnInfo.returnTypes, true)); + templ("abiDecode", m_context.abiFunctions().tupleDecoder(returnInfo.returnTypes, true)); templ("dynamicReturnSize", returnInfo.dynamicReturnSize); templ("freeMemoryPointer", to_string(CompilerUtils::freeMemoryPointer)); templ("noTryCall", !_functionCall.annotation().tryCall); - // If the function takes arbitrary parameters or is a bare call, copy dynamic length data in place. - // Move arguments to memory, will not update the free memory pointer (but will update the memory - // pointer on the stack). - bool encodeInPlace = funType.takesArbitraryParameters() || funType.isBareCall(); - if (funType.kind() == FunctionType::Kind::ECRecover) - // This would be the only combination of padding and in-place encoding, - // but all parameters of ecrecover are value types anyway. - encodeInPlace = false; bool encodeForLibraryCall = funKind == FunctionType::Kind::DelegateCall; - solUnimplementedAssert(encodeInPlace == !funType.padArguments(), ""); - if (encodeInPlace) - { - solUnimplementedAssert(!encodeForLibraryCall, ""); - templ("encodeArgs", abi.tupleEncoderPacked(argumentTypes, funType.parameterTypes())); - } - else - templ("encodeArgs", abi.tupleEncoder(argumentTypes, funType.parameterTypes(), encodeForLibraryCall)); + solAssert(funType.padArguments(), ""); + templ("encodeArgs", m_context.abiFunctions().tupleEncoder(argumentTypes, funType.parameterTypes(), encodeForLibraryCall)); templ("argumentString", joinHumanReadablePrefixed(argumentStrings)); - // Output data will replace input data, unless we have ECRecover (then, output - // area will be 32 bytes just before input area). - solUnimplementedAssert(funKind != FunctionType::Kind::ECRecover, ""); - solAssert(!isDelegateCall || !funType.valueSet(), "Value set for delegatecall"); solAssert(!useStaticCall || !funType.valueSet(), "Value set for staticcall"); templ("hasValue", !isDelegateCall && !useStaticCall); templ("value", funType.valueSet() ? IRVariable(_functionCall.expression()).part("value").name() : "0"); - // Check that the target contract exists (has code) for non-low-level calls. - bool checkExistence = (funKind == FunctionType::Kind::External || funKind == FunctionType::Kind::DelegateCall); - templ("checkExistence", checkExistence); - if (funType.gasSet()) templ("gas", IRVariable(_functionCall.expression()).part("gas").name()); else if (m_context.evmVersion().canOverchargeGasForCall()) @@ -1919,8 +1875,6 @@ void IRGeneratorForStatements::appendExternalFunctionCall( u256 gasNeededByCaller = evmasm::GasCosts::callGas(m_context.evmVersion()) + 10; if (funType.valueSet()) gasNeededByCaller += evmasm::GasCosts::callValueTransferGas; - if (!checkExistence) - gasNeededByCaller += evmasm::GasCosts::callNewAccountGas; // we never know templ("gas", "sub(gas(), " + formatNumber(gasNeededByCaller) + ")"); } // Order is important here, STATICCALL might overlap with DELEGATECALL. @@ -1933,8 +1887,103 @@ void IRGeneratorForStatements::appendExternalFunctionCall( templ("forwardingRevert", m_utils.forwardingRevertFunction()); - solUnimplementedAssert(funKind != FunctionType::Kind::RIPEMD160, ""); - solUnimplementedAssert(funKind != FunctionType::Kind::ECRecover, ""); + m_code << templ.render(); +} + +void IRGeneratorForStatements::appendBareCall( + FunctionCall const& _functionCall, + vector> const& _arguments +) +{ + FunctionType const& funType = dynamic_cast(type(_functionCall.expression())); + solAssert( + !funType.bound() && + !funType.takesArbitraryParameters() && + _arguments.size() == 1 && + funType.parameterTypes().size() == 1, "" + ); + FunctionType::Kind const funKind = funType.kind(); + + solAssert(funKind != FunctionType::Kind::BareStaticCall || m_context.evmVersion().hasStaticCall(), ""); + solAssert(funKind != FunctionType::Kind::BareCallCode, "Callcode has been removed."); + solAssert( + funKind == FunctionType::Kind::BareCall || + funKind == FunctionType::Kind::BareDelegateCall || + funKind == FunctionType::Kind::BareStaticCall, "" + ); + + solAssert(!_functionCall.annotation().tryCall, ""); + Whiskers templ(R"( + + let := mload() + let := sub(( , ), ) + + let := add(, 0x20) + let := mload() + + + let := (,
, , , , 0, 0) + + let := () + + )"); + + templ("freeMemoryPointer", to_string(CompilerUtils::freeMemoryPointer)); + templ("pos", m_context.newYulVariable()); + templ("length", m_context.newYulVariable()); + + templ("arg", IRVariable(*_arguments.front()).commaSeparatedList()); + Type const& argType = type(*_arguments.front()); + if (argType == *TypeProvider::bytesMemory() || argType == *TypeProvider::stringMemory()) + templ("needsEncoding", false); + else + { + templ("needsEncoding", true); + ABIFunctions abi(m_context.evmVersion(), m_context.revertStrings(), m_context.functionCollector()); + templ("encode", abi.tupleEncoderPacked({&argType}, {TypeProvider::bytesMemory()})); + } + + templ("success", IRVariable(_functionCall).tupleComponent(0).name()); + if (IRVariable(_functionCall).tupleComponent(1).type().category() == Type::Category::InaccessibleDynamic) + templ("returndataVar", ""); + else + { + templ("returndataVar", IRVariable(_functionCall).tupleComponent(1).part("mpos").name()); + templ("extractReturndataFunction", m_utils.extractReturndataFunction()); + } + + templ("address", IRVariable(_functionCall.expression()).part("address").name()); + + if (funKind == FunctionType::Kind::BareCall) + { + templ("value", funType.valueSet() ? IRVariable(_functionCall.expression()).part("value").name() : "0"); + templ("call", "call"); + } + else + { + solAssert(!funType.valueSet(), "Value set for delegatecall or staticcall."); + templ("value", ""); + if (funKind == FunctionType::Kind::BareStaticCall) + templ("call", "staticcall"); + else + templ("call", "delegatecall"); + } + + if (funType.gasSet()) + templ("gas", IRVariable(_functionCall.expression()).part("gas").name()); + else if (m_context.evmVersion().canOverchargeGasForCall()) + // Send all gas (requires tangerine whistle EVM) + templ("gas", "gas()"); + else + { + // send all gas except the amount needed to execute "SUB" and "CALL" + // @todo this retains too much gas for now, needs to be fine-tuned. + u256 gasNeededByCaller = evmasm::GasCosts::callGas(m_context.evmVersion()) + 10; + if (funType.valueSet()) + gasNeededByCaller += evmasm::GasCosts::callValueTransferGas; + gasNeededByCaller += evmasm::GasCosts::callNewAccountGas; // we never know + templ("gas", "sub(gas(), " + formatNumber(gasNeededByCaller) + ")"); + } m_code << templ.render(); } diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.h b/libsolidity/codegen/ir/IRGeneratorForStatements.h index c51b2225d..42d355ddd 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.h +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.h @@ -106,6 +106,13 @@ private: std::vector> const& _arguments ); + /// Appends code for .call / .delegatecall / .staticcall. + /// All involved expressions have already been visited. + void appendBareCall( + FunctionCall const& _functionCall, + std::vector> const& _arguments + ); + /// @returns code that evaluates to the first unused memory slot (which does not have to /// be empty). static std::string freeMemory(); diff --git a/libsolidity/codegen/ir/IRVariable.cpp b/libsolidity/codegen/ir/IRVariable.cpp index d92a5fb53..1c5ed42bf 100644 --- a/libsolidity/codegen/ir/IRVariable.cpp +++ b/libsolidity/codegen/ir/IRVariable.cpp @@ -54,7 +54,7 @@ IRVariable IRVariable::part(string const& _name) const solAssert(itemName.empty() || itemType, ""); return IRVariable{suffixedName(itemName), itemType ? *itemType : m_type}; } - solAssert(false, "Invalid stack item name."); + solAssert(false, "Invalid stack item name: " + _name); } vector IRVariable::stackSlots() const diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_call.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_call.sol index d73db5da6..d11914fce 100644 --- a/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_call.sol +++ b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_call.sol @@ -22,5 +22,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> true diff --git a/test/libsolidity/semanticTests/builtinFunctions/sha256_empty.sol b/test/libsolidity/semanticTests/builtinFunctions/sha256_empty.sol index ededa2fab..bb9fc3616 100644 --- a/test/libsolidity/semanticTests/builtinFunctions/sha256_empty.sol +++ b/test/libsolidity/semanticTests/builtinFunctions/sha256_empty.sol @@ -3,7 +3,5 @@ contract C { return sha256(""); } } -// ==== -// compileViaYul: also // ---- // f() -> 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/test/libsolidity/semanticTests/constructor/evm_exceptions_in_constructor_call_fail.sol b/test/libsolidity/semanticTests/constructor/evm_exceptions_in_constructor_call_fail.sol index 2192dabf3..4517c9702 100644 --- a/test/libsolidity/semanticTests/constructor/evm_exceptions_in_constructor_call_fail.sol +++ b/test/libsolidity/semanticTests/constructor/evm_exceptions_in_constructor_call_fail.sol @@ -14,6 +14,8 @@ contract B { } } +// ==== +// compileViaYul: also // ---- // testIt() -> // test() -> 2 diff --git a/test/libsolidity/semanticTests/functionCall/delegatecall_return_value.sol b/test/libsolidity/semanticTests/functionCall/delegatecall_return_value.sol index ffa22b8a2..0a80a9f5c 100644 --- a/test/libsolidity/semanticTests/functionCall/delegatecall_return_value.sol +++ b/test/libsolidity/semanticTests/functionCall/delegatecall_return_value.sol @@ -22,6 +22,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: >=byzantium // ---- // get() -> 0x00 diff --git a/test/libsolidity/semanticTests/functionCall/delegatecall_return_value_pre_byzantium.sol b/test/libsolidity/semanticTests/functionCall/delegatecall_return_value_pre_byzantium.sol index 498449d17..00f1f8a77 100644 --- a/test/libsolidity/semanticTests/functionCall/delegatecall_return_value_pre_byzantium.sol +++ b/test/libsolidity/semanticTests/functionCall/delegatecall_return_value_pre_byzantium.sol @@ -24,6 +24,7 @@ contract C { } } // ==== +// compileViaYul: also // EVMVersion: 0x00 diff --git a/test/libsolidity/semanticTests/various/staticcall_for_view_and_pure_pre_byzantium.sol b/test/libsolidity/semanticTests/various/staticcall_for_view_and_pure_pre_byzantium.sol index a193e8752..e9157e34c 100644 --- a/test/libsolidity/semanticTests/various/staticcall_for_view_and_pure_pre_byzantium.sol +++ b/test/libsolidity/semanticTests/various/staticcall_for_view_and_pure_pre_byzantium.sol @@ -32,6 +32,7 @@ contract D { } } // ==== +// compileViaYul: also // EVMVersion: 0x1 From 875415a1325844e42373b358c941b8cd1c0e8a83 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 11 May 2020 12:05:39 +0100 Subject: [PATCH 60/89] Replace boost/algorithm/cxx11 with C++11 features --- libsolidity/analysis/SyntaxChecker.cpp | 7 +++++-- libsolidity/analysis/TypeChecker.cpp | 7 +++++-- libsolidity/interface/CompilerStack.cpp | 2 +- libsolidity/interface/StandardCompiler.cpp | 1 - libyul/optimiser/ControlFlowSimplifier.cpp | 6 +++--- libyul/optimiser/StructuralSimplifier.cpp | 1 - libyul/optimiser/UnusedPruner.cpp | 7 +++---- 7 files changed, 17 insertions(+), 14 deletions(-) diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp index 058244cac..86204e88e 100644 --- a/libsolidity/analysis/SyntaxChecker.cpp +++ b/libsolidity/analysis/SyntaxChecker.cpp @@ -27,7 +27,6 @@ #include #include -#include #include #include @@ -335,7 +334,11 @@ bool SyntaxChecker::visit(FunctionTypeName const& _node) bool SyntaxChecker::visit(VariableDeclarationStatement const& _statement) { // Report if none of the variable components in the tuple have a name (only possible via deprecated "var") - if (boost::algorithm::all_of_equal(_statement.declarations(), nullptr)) + if (std::all_of( + _statement.declarations().begin(), + _statement.declarations().end(), + [](ASTPointer const& declaration) { return declaration == nullptr; } + )) m_errorReporter.syntaxError( 3299_error, _statement.location(), diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index b9c85f545..f38161593 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -34,7 +34,6 @@ #include #include -#include #include #include @@ -1058,7 +1057,11 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) // No initial value is only permitted for single variables with specified type. if (_statement.declarations().size() != 1 || !_statement.declarations().front()) { - if (boost::algorithm::all_of_equal(_statement.declarations(), nullptr)) + if (std::all_of( + _statement.declarations().begin(), + _statement.declarations().end(), + [](ASTPointer const& declaration) { return declaration == nullptr; } + )) { // The syntax checker has already generated an error for this case (empty LHS tuple). solAssert(m_errorReporter.hasErrors(), ""); diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 519eea81a..da561050b 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -67,7 +67,7 @@ #include -#include +#include #include using namespace std; diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 65b948bb2..0abc867e8 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -31,7 +31,6 @@ #include #include -#include #include #include diff --git a/libyul/optimiser/ControlFlowSimplifier.cpp b/libyul/optimiser/ControlFlowSimplifier.cpp index 1640fa1b0..1d6b09615 100644 --- a/libyul/optimiser/ControlFlowSimplifier.cpp +++ b/libyul/optimiser/ControlFlowSimplifier.cpp @@ -25,7 +25,6 @@ #include #include -#include using namespace std; using namespace solidity; @@ -60,8 +59,9 @@ void removeEmptyDefaultFromSwitch(Switch& _switchStmt) void removeEmptyCasesFromSwitch(Switch& _switchStmt) { - bool hasDefault = boost::algorithm::any_of( - _switchStmt.cases, + bool hasDefault = std::any_of( + _switchStmt.cases.begin(), + _switchStmt.cases.end(), [](Case const& _case) { return !_case.value; } ); diff --git a/libyul/optimiser/StructuralSimplifier.cpp b/libyul/optimiser/StructuralSimplifier.cpp index 836169701..0d5da95c1 100644 --- a/libyul/optimiser/StructuralSimplifier.cpp +++ b/libyul/optimiser/StructuralSimplifier.cpp @@ -22,7 +22,6 @@ #include #include -#include using namespace std; using namespace solidity; diff --git a/libyul/optimiser/UnusedPruner.cpp b/libyul/optimiser/UnusedPruner.cpp index 9dc7cedc3..6ed8df47c 100644 --- a/libyul/optimiser/UnusedPruner.cpp +++ b/libyul/optimiser/UnusedPruner.cpp @@ -29,8 +29,6 @@ #include #include -#include - using namespace std; using namespace solidity; using namespace solidity::yul; @@ -85,8 +83,9 @@ void UnusedPruner::operator()(Block& _block) // movable or it returns a single value. In the latter case, we // replace `let a := f()` by `pop(f())` (in pure Yul, this will be // `drop(f())`). - if (boost::algorithm::none_of( - varDecl.variables, + if (std::none_of( + varDecl.variables.begin(), + varDecl.variables.end(), [=](TypedName const& _typedName) { return used(_typedName.name); } )) { From c0c5127ed050a0a8012d8a5325bbff4ac5333e7f Mon Sep 17 00:00:00 2001 From: Harikrishnan Mulackal Date: Mon, 11 May 2020 19:05:41 +0530 Subject: [PATCH 61/89] Changed a potentially misleading name --- docs/cheatsheet.rst | 4 ++-- docs/units-and-global-variables.rst | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/cheatsheet.rst b/docs/cheatsheet.rst index e8ecb0af6..5e673f7b0 100644 --- a/docs/cheatsheet.rst +++ b/docs/cheatsheet.rst @@ -122,8 +122,8 @@ Global Variables - ``type(C).creationCode`` (``bytes memory``): creation bytecode of the given contract, see :ref:`Type Information`. - ``type(C).runtimeCode`` (``bytes memory``): runtime bytecode of the given contract, see :ref:`Type Information`. - ``type(I).interfaceId`` (``bytes4``): value containing the EIP-165 interface identifier of the given interface, see :ref:`Type Information`. -- ``type(X).min`` (``X``): the minimum value representable by the integer type ``X``, see :ref:`Type Information`. -- ``type(X).max`` (``X``): the maximum value representable by the integer type ``X``, see :ref:`Type Information`. +- ``type(T).min`` (``T``): the minimum value representable by the integer type ``T``, see :ref:`Type Information`. +- ``type(T).max`` (``T``): the maximum value representable by the integer type ``T``, see :ref:`Type Information`. .. note:: Do not rely on ``block.timestamp``, ``now`` and ``blockhash`` as a source of randomness, diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst index 22c6fc12d..d936ef246 100644 --- a/docs/units-and-global-variables.rst +++ b/docs/units-and-global-variables.rst @@ -329,10 +329,10 @@ for an interface type ``I``: interface identifier of the given interface ``I``. This identifier is defined as the ``XOR`` of all function selectors defined within the interface itself - excluding all inherited functions. -The following properties are available for an integer type ``I``: +The following properties are available for an integer type ``T``: -``type(I).min`` - The smallest value representable by type ``I``. +``type(T).min`` + The smallest value representable by type ``T``. -``type(I).max`` - The largest value representable by type ``I``. +``type(T).max`` + The largest value representable by type ``T``. From 79b217dfb3b96015d77f5dabcac0bf5a0330bc54 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 6 May 2020 17:21:44 +0200 Subject: [PATCH 62/89] Callvalue checks for implicit constructors. --- Changelog.md | 4 ++ docs/bugs.json | 8 +++ docs/bugs_by_version.json | 54 ++++++++++++++++++- libsolidity/codegen/ContractCompiler.cpp | 7 ++- .../constructor/callvalue_check.sol | 40 ++++++++++++++ .../constructor/no_callvalue_check.sol | 21 ++++++++ .../constructor/nonpayable_new.sol | 23 ++++++++ .../syntaxTests/constructor/payable_new.sol | 16 ++++++ 8 files changed, 169 insertions(+), 4 deletions(-) create mode 100644 test/libsolidity/semanticTests/constructor/callvalue_check.sol create mode 100644 test/libsolidity/semanticTests/constructor/no_callvalue_check.sol create mode 100644 test/libsolidity/syntaxTests/constructor/nonpayable_new.sol create mode 100644 test/libsolidity/syntaxTests/constructor/payable_new.sol diff --git a/Changelog.md b/Changelog.md index 086e80ee9..c3a1d3855 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,9 @@ ### 0.6.8 (unreleased) +Important Bugfixes: + * Add missing callvalue check to the creation code of a contract that does not define a constructor but has a base that does define a constructor. + + Language Features: diff --git a/docs/bugs.json b/docs/bugs.json index 56bae3aaf..c251fa114 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -1,4 +1,12 @@ [ + { + "name": "ImplicitConstructorCallvalueCheck", + "summary": "The creation code of a contract that does not define a constructor but has a base that does define a constructor did not revert for calls with non-zero value.", + "description": "Starting from Solidity 0.4.5 the creation code of contracts without explicit payable constructor is supposed to contain a callvalue check that results in contract creation reverting, if non-zero value is passed. However, this check was missing in case no explicit constructor was defined in a contract at all, but the contract has a base that does define a constructor. In these cases it is possible to send value in a contract creation transaction or using inline assembly without revert, even though the creation code is supposed to be non-payable.", + "introduced": "0.4.5", + "fixed": "0.6.8", + "severity": "very low" + }, { "name": "TupleAssignmentMultiStackSlotComponents", "summary": "Tuple assignments with components that occupy several stack slots, i.e. nested tuples, pointers to external functions or references to dynamically sized calldata arrays, can result in invalid values.", diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index 4c27e90d9..0398e4cd7 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -415,6 +415,7 @@ }, "0.4.10": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -433,6 +434,7 @@ }, "0.4.11": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -450,6 +452,7 @@ }, "0.4.12": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -466,6 +469,7 @@ }, "0.4.13": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -482,6 +486,7 @@ }, "0.4.14": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -497,6 +502,7 @@ }, "0.4.15": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -511,6 +517,7 @@ }, "0.4.16": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -527,6 +534,7 @@ }, "0.4.17": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -544,6 +552,7 @@ }, "0.4.18": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -560,6 +569,7 @@ }, "0.4.19": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -596,6 +606,7 @@ }, "0.4.20": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -613,6 +624,7 @@ }, "0.4.21": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -630,6 +642,7 @@ }, "0.4.22": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -647,6 +660,7 @@ }, "0.4.23": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -663,6 +677,7 @@ }, "0.4.24": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -679,6 +694,7 @@ }, "0.4.25": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -693,6 +709,7 @@ }, "0.4.26": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -739,6 +756,7 @@ }, "0.4.5": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -758,6 +776,7 @@ }, "0.4.6": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -776,6 +795,7 @@ }, "0.4.7": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -794,6 +814,7 @@ }, "0.4.8": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -812,6 +833,7 @@ }, "0.4.9": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -830,6 +852,7 @@ }, "0.5.0": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -844,6 +867,7 @@ }, "0.5.1": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -858,6 +882,7 @@ }, "0.5.10": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -868,6 +893,7 @@ }, "0.5.11": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -877,6 +903,7 @@ }, "0.5.12": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -886,6 +913,7 @@ }, "0.5.13": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -895,6 +923,7 @@ }, "0.5.14": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -905,6 +934,7 @@ }, "0.5.15": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -914,6 +944,7 @@ }, "0.5.16": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden" @@ -922,6 +953,7 @@ }, "0.5.17": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow" ], @@ -929,6 +961,7 @@ }, "0.5.2": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -943,6 +976,7 @@ }, "0.5.3": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -957,6 +991,7 @@ }, "0.5.4": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -971,6 +1006,7 @@ }, "0.5.5": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -987,6 +1023,7 @@ }, "0.5.6": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -1003,6 +1040,7 @@ }, "0.5.7": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -1017,6 +1055,7 @@ }, "0.5.8": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -1030,6 +1069,7 @@ }, "0.5.9": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", @@ -1042,6 +1082,7 @@ }, "0.6.0": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "YulOptimizerRedundantAssignmentBreakContinue" @@ -1050,6 +1091,7 @@ }, "0.6.1": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow" ], @@ -1057,6 +1099,7 @@ }, "0.6.2": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow" ], @@ -1064,6 +1107,7 @@ }, "0.6.3": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow" ], @@ -1071,6 +1115,7 @@ }, "0.6.4": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow" ], @@ -1078,16 +1123,21 @@ }, "0.6.5": { "bugs": [ + "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents" ], "released": "2020-04-06" }, "0.6.6": { - "bugs": [], + "bugs": [ + "ImplicitConstructorCallvalueCheck" + ], "released": "2020-04-09" }, "0.6.7": { - "bugs": [], + "bugs": [ + "ImplicitConstructorCallvalueCheck" + ], "released": "2020-05-04" } } \ No newline at end of file diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 319d7a7ad..7d07841f8 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -157,10 +157,13 @@ void ContractCompiler::appendInitAndConstructorCode(ContractDefinition const& _c if (FunctionDefinition const* constructor = _contract.constructor()) appendConstructor(*constructor); - else if (auto c = _contract.nextConstructor(m_context.mostDerivedContract())) - appendBaseConstructor(*c); else + { + // Implicit constructors are always non-payable. appendCallValueCheck(); + if (auto c = _contract.nextConstructor(m_context.mostDerivedContract())) + appendBaseConstructor(*c); + } } size_t ContractCompiler::packIntoContractCreator(ContractDefinition const& _contract) diff --git a/test/libsolidity/semanticTests/constructor/callvalue_check.sol b/test/libsolidity/semanticTests/constructor/callvalue_check.sol new file mode 100644 index 000000000..7a327e695 --- /dev/null +++ b/test/libsolidity/semanticTests/constructor/callvalue_check.sol @@ -0,0 +1,40 @@ +contract A1 { constructor() public {} } +contract B1 is A1 {} + +contract A2 { constructor() public payable {} } +contract B2 is A2 {} + +contract B3 {} + +contract B4 { constructor() public {} } + +contract C { + function createWithValue(bytes memory c, uint256 value) public payable returns (bool) { + uint256 y = 0; + assembly { y := create(value, add(c, 0x20), mload(c)) } + return y != 0; + } + function f(uint256 value) public payable returns (bool) { + return createWithValue(type(B1).creationCode, value); + } + function g(uint256 value) public payable returns (bool) { + return createWithValue(type(B2).creationCode, value); + } + function h(uint256 value) public payable returns (bool) { + return createWithValue(type(B3).creationCode, value); + } + function i(uint256 value) public payable returns (bool) { + return createWithValue(type(B4).creationCode, value); + } +} +// ==== +// EVMVersion: >homestead +// ---- +// f(uint256), 2000 ether: 0 -> true +// f(uint256), 2000 ether: 100 -> false +// g(uint256), 2000 ether: 0 -> true +// g(uint256), 2000 ether: 100 -> false +// h(uint256), 2000 ether: 0 -> true +// h(uint256), 2000 ether: 100 -> false +// i(uint256), 2000 ether: 0 -> true +// i(uint256), 2000 ether: 100 -> false diff --git a/test/libsolidity/semanticTests/constructor/no_callvalue_check.sol b/test/libsolidity/semanticTests/constructor/no_callvalue_check.sol new file mode 100644 index 000000000..9744aa3ce --- /dev/null +++ b/test/libsolidity/semanticTests/constructor/no_callvalue_check.sol @@ -0,0 +1,21 @@ +contract A1 {} +contract B1 is A1 { constructor() public payable {} } + +contract A2 { constructor() public {} } +contract B2 is A2 { constructor() public payable {} } + +contract B3 { constructor() public payable {} } + +contract C { + function f() public payable returns (bool) { + // Make sure none of these revert. + new B1{value: 10}(); + new B2{value: 10}(); + new B3{value: 10}(); + return true; + } +} +// ==== +// compileViaYul: also +// ---- +// f(), 2000 ether -> true diff --git a/test/libsolidity/syntaxTests/constructor/nonpayable_new.sol b/test/libsolidity/syntaxTests/constructor/nonpayable_new.sol new file mode 100644 index 000000000..c89508743 --- /dev/null +++ b/test/libsolidity/syntaxTests/constructor/nonpayable_new.sol @@ -0,0 +1,23 @@ +contract A1 { constructor() public {} } +contract B1 is A1 {} + +contract A2 { constructor() public payable {} } +contract B2 is A2 {} + +contract B3 {} + +contract B4 { constructor() public {} } + +contract C { + function f() public payable { + new B1{value: 10}(); + new B2{value: 10}(); + new B3{value: 10}(); + new B4{value: 10}(); + } +} +// ---- +// TypeError: (235-252): Cannot set option "value", since the constructor of contract B1 is not payable. +// TypeError: (258-275): Cannot set option "value", since the constructor of contract B2 is not payable. +// TypeError: (281-298): Cannot set option "value", since the constructor of contract B3 is not payable. +// TypeError: (304-321): Cannot set option "value", since the constructor of contract B4 is not payable. diff --git a/test/libsolidity/syntaxTests/constructor/payable_new.sol b/test/libsolidity/syntaxTests/constructor/payable_new.sol new file mode 100644 index 000000000..fb8e9ef53 --- /dev/null +++ b/test/libsolidity/syntaxTests/constructor/payable_new.sol @@ -0,0 +1,16 @@ +contract A1 {} +contract B1 is A1 { constructor() public payable {} } + +contract A2 { constructor() public {} } +contract B2 is A2 { constructor() public payable {} } + +contract B3 { constructor() public payable {} } + +contract C { + function f() public payable { + new B1{value: 10}(); + new B2{value: 10}(); + new B3{value: 10}(); + } +} +// ---- From c1ed5bbb0ff078ff5cfe7287a603b1385e6d6ee9 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Mon, 11 May 2020 16:53:45 +0200 Subject: [PATCH 63/89] Update Dockerfiles and CI scripts to Ubuntu 20.04 and simplify them. --- .circleci/README.md | 10 +- .circleci/config.yml | 78 ++++++------ .circleci/docker/Dockerfile.ubuntu1904.clang | 113 ------------------ ...rfile.ubuntu1904 => Dockerfile.ubuntu2004} | 44 +------ .circleci/docker/Dockerfile.ubuntu2004.clang | 61 ++++++++++ libsolidity/analysis/ViewPureChecker.cpp | 2 +- libyul/AsmAnalysis.cpp | 2 +- libyul/backends/evm/EVMCodeTransform.cpp | 10 +- libyul/backends/wasm/EVMToEwasmTranslator.cpp | 2 +- .../optimiser/RedundantAssignEliminator.cpp | 2 +- libyul/optimiser/UnusedPruner.cpp | 2 +- scripts/docs.sh | 2 +- 12 files changed, 121 insertions(+), 207 deletions(-) delete mode 100644 .circleci/docker/Dockerfile.ubuntu1904.clang rename .circleci/docker/{Dockerfile.ubuntu1904 => Dockerfile.ubuntu2004} (52%) create mode 100644 .circleci/docker/Dockerfile.ubuntu2004.clang diff --git a/.circleci/README.md b/.circleci/README.md index b48adba24..338e858d9 100644 --- a/.circleci/README.md +++ b/.circleci/README.md @@ -7,15 +7,15 @@ The docker images are build locally on the developer machine: ```sh cd .circleci/docker/ -docker build -t ethereum/solidity-buildpack-deps:ubuntu1904- -f Dockerfile.ubuntu1904 . -docker push ethereum/solidity-buildpack-deps:ubuntu1904- +docker build -t ethereum/solidity-buildpack-deps:ubuntu2004- -f Dockerfile.ubuntu2004 . +docker push ethereum/solidity-buildpack-deps:ubuntu2004- ``` -The current revisions per docker image are stored in [circle ci pipeline parameters](https://github.com/CircleCI-Public/api-preview-docs/blob/master/docs/pipeline-parameters.md#pipeline-parameters) called `-docker-image-rev` (e.g., `ubuntu-1904-docker-image-rev`). Please update the value assigned to the parameter(s) corresponding to the docker image(s) being updated at the time of the update. Please verify that the value assigned to the parameter matches the revision part of the docker image tag (`` in the docker build/push snippet shown above). Otherwise, the docker image used by circle ci and the one actually pushed to docker hub will differ. +The current revisions per docker image are stored in [circle ci pipeline parameters](https://github.com/CircleCI-Public/api-preview-docs/blob/master/docs/pipeline-parameters.md#pipeline-parameters) called `-docker-image-rev` (e.g., `ubuntu-2004-docker-image-rev`). Please update the value assigned to the parameter(s) corresponding to the docker image(s) being updated at the time of the update. Please verify that the value assigned to the parameter matches the revision part of the docker image tag (`` in the docker build/push snippet shown above). Otherwise, the docker image used by circle ci and the one actually pushed to docker hub will differ. Once the docker image has been built and pushed to Dockerhub, you can find it at: - https://hub.docker.com/r/ethereum/solidity-buildpack-deps:ubuntu1904- + https://hub.docker.com/r/ethereum/solidity-buildpack-deps:ubuntu2004- where the image tag reflects the target OS and revision to build Solidity and run its tests on. @@ -24,7 +24,7 @@ where the image tag reflects the target OS and revision to build Solidity and ru ```sh cd solidity # Mounts your local solidity directory in docker container for testing -docker run -v `pwd`:/src/solidity -ti ethereum/solidity-buildpack-deps:ubuntu1904- /bin/bash +docker run -v `pwd`:/src/solidity -ti ethereum/solidity-buildpack-deps:ubuntu2004- /bin/bash cd /src/solidity ``` diff --git a/.circleci/config.yml b/.circleci/config.yml index e1161e432..5ef9ea07e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,12 +10,12 @@ parameters: ubuntu-1804-docker-image-rev: type: string default: "4" - ubuntu-1904-docker-image-rev: + ubuntu-2004-docker-image-rev: type: string - default: "4" - ubuntu-1904-clang-docker-image-rev: + default: "1" + ubuntu-2004-clang-docker-image-rev: type: string - default: "5" + default: "1" ubuntu-1604-clang-ossfuzz-docker-image-rev: type: string default: "2" @@ -137,9 +137,9 @@ defaults: - store_test_results: *store_test_results - store_artifacts: *artifacts_test_results - - test_ubuntu1904_clang: &test_ubuntu1904_clang + - test_ubuntu2004_clang: &test_ubuntu2004_clang docker: - - image: ethereum/solidity-buildpack-deps:ubuntu1904-clang-<< pipeline.parameters.ubuntu-1904-clang-docker-image-rev >> + - image: ethereum/solidity-buildpack-deps:ubuntu2004-clang-<< pipeline.parameters.ubuntu-2004-clang-docker-image-rev >> steps: - checkout - attach_workspace: @@ -148,9 +148,9 @@ defaults: - store_test_results: *store_test_results - store_artifacts: *artifacts_test_results - - test_ubuntu1904: &test_ubuntu1904 + - test_ubuntu2004: &test_ubuntu2004 docker: - - image: ethereum/solidity-buildpack-deps:ubuntu1904-<< pipeline.parameters.ubuntu-1904-docker-image-rev >> + - image: ethereum/solidity-buildpack-deps:ubuntu2004-<< pipeline.parameters.ubuntu-2004-docker-image-rev >> steps: - checkout - attach_workspace: @@ -160,7 +160,7 @@ defaults: - store_artifacts: *artifacts_test_results - test_asan: &test_asan - <<: *test_ubuntu1904 + <<: *test_ubuntu2004 steps: - checkout - attach_workspace: @@ -179,7 +179,7 @@ defaults: tags: only: /.*/ - - workflow_ubuntu1904: &workflow_ubuntu1904 + - workflow_ubuntu2004: &workflow_ubuntu2004 <<: *workflow_trigger_on_tags requires: - b_ubu @@ -189,17 +189,17 @@ defaults: requires: - b_ubu_ossfuzz - - workflow_ubuntu1904_clang: &workflow_ubuntu1904_clang + - workflow_ubuntu2004_clang: &workflow_ubuntu2004_clang <<: *workflow_trigger_on_tags requires: - b_ubu_clang - - workflow_ubuntu1904_release: &workflow_ubuntu1904_release + - workflow_ubuntu2004_release: &workflow_ubuntu2004_release <<: *workflow_trigger_on_tags requires: - b_ubu_release - - workflow_ubuntu1904_codecov: &workflow_ubuntu1904_codecov + - workflow_ubuntu2004_codecov: &workflow_ubuntu2004_codecov <<: *workflow_trigger_on_tags requires: - b_ubu_codecov @@ -209,7 +209,7 @@ defaults: requires: - b_osx - - workflow_ubuntu1904_asan: &workflow_ubuntu1904_asan + - workflow_ubuntu2004_asan: &workflow_ubuntu2004_asan <<: *workflow_trigger_on_tags requires: - b_ubu_asan @@ -359,16 +359,16 @@ jobs: chk_docs_pragma_min_version: docker: - - image: ethereum/solidity-buildpack-deps:ubuntu1904-<< pipeline.parameters.ubuntu-1904-docker-image-rev >> + - image: ethereum/solidity-buildpack-deps:ubuntu2004-<< pipeline.parameters.ubuntu-2004-docker-image-rev >> environment: TERM: xterm steps: - checkout - run: *run_docs_pragma_min_version - b_ubu_clang: &build_ubuntu1904_clang + b_ubu_clang: &build_ubuntu2004_clang docker: - - image: ethereum/solidity-buildpack-deps:ubuntu1904-clang-<< pipeline.parameters.ubuntu-1904-clang-docker-image-rev >> + - image: ethereum/solidity-buildpack-deps:ubuntu2004-clang-<< pipeline.parameters.ubuntu-2004-clang-docker-image-rev >> environment: CC: clang CXX: clang++ @@ -378,9 +378,9 @@ jobs: - store_artifacts: *artifacts_solc - persist_to_workspace: *artifacts_executables - b_ubu: &build_ubuntu1904 + b_ubu: &build_ubuntu2004 docker: - - image: ethereum/solidity-buildpack-deps:ubuntu1904-<< pipeline.parameters.ubuntu-1904-docker-image-rev >> + - image: ethereum/solidity-buildpack-deps:ubuntu2004-<< pipeline.parameters.ubuntu-2004-docker-image-rev >> steps: - checkout - run: *run_build @@ -388,8 +388,8 @@ jobs: - store_artifacts: *artifacts_tools - persist_to_workspace: *artifacts_executables - b_ubu_release: &build_ubuntu1904_release - <<: *build_ubuntu1904 + b_ubu_release: &build_ubuntu2004_release + <<: *build_ubuntu2004 environment: FORCE_RELEASE: ON @@ -406,7 +406,7 @@ jobs: - persist_to_workspace: *artifacts_executables b_ubu_codecov: - <<: *build_ubuntu1904 + <<: *build_ubuntu2004 environment: COVERAGE: ON CMAKE_BUILD_TYPE: Debug @@ -416,7 +416,7 @@ jobs: - persist_to_workspace: *artifacts_build_dir t_ubu_codecov: - <<: *test_ubuntu1904 + <<: *test_ubuntu2004 environment: EVM: constantinople OPTIMIZE: 1 @@ -439,7 +439,7 @@ jobs: # Builds in C++20 mode and uses debug build in order to speed up. # Do *NOT* store any artifacts or workspace as we don't run tests on this build. b_ubu_cxx20: - <<: *build_ubuntu1904 + <<: *build_ubuntu2004 environment: CMAKE_BUILD_TYPE: Debug CMAKE_OPTIONS: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/cxx20.cmake -DUSE_CVC4=OFF @@ -591,7 +591,7 @@ jobs: # x64 ASAN build, for testing for memory related bugs b_ubu_asan: &b_ubu_asan - <<: *build_ubuntu1904 + <<: *build_ubuntu2004 environment: CMAKE_OPTIONS: -DSANITIZE=address CMAKE_BUILD_TYPE: Release @@ -603,7 +603,7 @@ jobs: b_docs: docker: - - image: ethereum/solidity-buildpack-deps:ubuntu1904-<< pipeline.parameters.ubuntu-1904-docker-image-rev >> + - image: ethereum/solidity-buildpack-deps:ubuntu2004-<< pipeline.parameters.ubuntu-2004-docker-image-rev >> steps: - checkout - run: *setup_prerelease_commit_hash @@ -615,11 +615,11 @@ jobs: destination: docs-html t_ubu_soltest: &t_ubu_soltest - <<: *test_ubuntu1904 + <<: *test_ubuntu2004 t_ubu_soltest_enforce_yul: &t_ubu_soltest_enforce_yul docker: - - image: ethereum/solidity-buildpack-deps:ubuntu1904-<< pipeline.parameters.ubuntu-1904-docker-image-rev >> + - image: ethereum/solidity-buildpack-deps:ubuntu2004-<< pipeline.parameters.ubuntu-2004-docker-image-rev >> environment: EVM: constantinople SOLTEST_FLAGS: --enforce-via-yul @@ -635,7 +635,7 @@ jobs: t_ubu_clang_soltest: &t_ubu_clang_soltest - <<: *test_ubuntu1904_clang + <<: *test_ubuntu2004_clang environment: EVM: constantinople OPTIMIZE: 0 @@ -645,7 +645,7 @@ jobs: t_ubu_cli: &t_ubu_cli docker: - - image: ethereum/solidity-buildpack-deps:ubuntu1904-<< pipeline.parameters.ubuntu-1904-docker-image-rev >> + - image: ethereum/solidity-buildpack-deps:ubuntu2004-<< pipeline.parameters.ubuntu-2004-docker-image-rev >> environment: TERM: xterm steps: @@ -833,21 +833,21 @@ workflows: # Ubuntu build and tests - b_ubu: *workflow_trigger_on_tags - b_ubu18: *workflow_trigger_on_tags - - t_ubu_cli: *workflow_ubuntu1904 - - t_ubu_soltest: *workflow_ubuntu1904 - - t_ubu_soltest_enforce_yul: *workflow_ubuntu1904 + - t_ubu_cli: *workflow_ubuntu2004 + - t_ubu_soltest: *workflow_ubuntu2004 + - t_ubu_soltest_enforce_yul: *workflow_ubuntu2004 - b_ubu_clang: *workflow_trigger_on_tags - - t_ubu_clang_soltest: *workflow_ubuntu1904_clang + - t_ubu_clang_soltest: *workflow_ubuntu2004_clang # Ubuntu fake release build and tests - b_ubu_release: *workflow_trigger_on_tags - - t_ubu_release_cli: *workflow_ubuntu1904_release - - t_ubu_release_soltest: *workflow_ubuntu1904_release + - t_ubu_release_cli: *workflow_ubuntu2004_release + - t_ubu_release_soltest: *workflow_ubuntu2004_release # ASan build and tests - b_ubu_asan: *workflow_trigger_on_tags - - t_ubu_asan_constantinople: *workflow_ubuntu1904_asan - - t_ubu_asan_cli: *workflow_ubuntu1904_asan + - t_ubu_asan_constantinople: *workflow_ubuntu2004_asan + - t_ubu_asan_cli: *workflow_ubuntu2004_asan # Emscripten build and selected tests - b_ems: *workflow_trigger_on_tags @@ -874,4 +874,4 @@ workflows: # Code Coverage enabled build and tests - b_ubu_codecov: *workflow_trigger_on_tags - - t_ubu_codecov: *workflow_ubuntu1904_codecov + - t_ubu_codecov: *workflow_ubuntu2004_codecov diff --git a/.circleci/docker/Dockerfile.ubuntu1904.clang b/.circleci/docker/Dockerfile.ubuntu1904.clang deleted file mode 100644 index cf790c84e..000000000 --- a/.circleci/docker/Dockerfile.ubuntu1904.clang +++ /dev/null @@ -1,113 +0,0 @@ -# vim:syntax=dockerfile -#------------------------------------------------------------------------------ -# Dockerfile for building and testing Solidity Compiler on CI -# Target: Ubuntu 19.04 (Disco Dingo) Clang variant -# URL: https://hub.docker.com/r/ethereum/solidity-buildpack-deps -# -# 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 -# -# (c) 2016-2019 solidity contributors. -#------------------------------------------------------------------------------ -FROM buildpack-deps:disco AS base - -ARG DEBIAN_FRONTEND=noninteractive - -RUN set -ex; \ - dist=$(grep DISTRIB_CODENAME /etc/lsb-release | cut -d= -f2); \ - echo "deb http://ppa.launchpad.net/ethereum/cpp-build-deps/ubuntu $dist main" >> /etc/apt/sources.list ; \ - apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 1c52189c923f6ca9 ; \ - apt-get update; \ - apt-get install -qqy --no-install-recommends \ - build-essential \ - software-properties-common \ - cmake ninja-build \ - clang++-8 llvm-8-dev \ - libjsoncpp-dev \ - libleveldb1d \ - ; \ - apt-get install -qy python-pip python-sphinx; \ - update-alternatives --install /usr/bin/llvm-symbolizer llvm-symbolizer /usr/bin/llvm-symbolizer-8 1; \ - update-alternatives --install /usr/bin/clang clang /usr/bin/clang-8 1; \ - update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-8 1; \ - pip install codecov; \ - rm -rf /var/lib/apt/lists/* - -FROM base AS libraries - -ENV CC clang -ENV CXX clang++ - -# Boost -RUN git clone -b boost-1.69.0 https://github.com/boostorg/boost.git \ - /usr/src/boost; \ - cd /usr/src/boost; \ - git submodule update --init --recursive; \ - ./bootstrap.sh --with-toolset=clang --prefix=/usr; \ - ./b2 toolset=clang headers; \ - ./b2 toolset=clang variant=release \ - system filesystem unit_test_framework program_options \ - install -j $(($(nproc)/2)); \ - rm -rf /usr/src/boost - -# Z3 -RUN git clone --depth 1 -b z3-4.8.7 https://github.com/Z3Prover/z3.git \ - /usr/src/z3; \ - cd /usr/src/z3; \ - python scripts/mk_make.py --prefix=/usr ; \ - cd build; \ - make -j; \ - make install; \ - rm -rf /usr/src/z3; - -# OSSFUZZ: libprotobuf-mutator -RUN set -ex; \ - git clone https://github.com/google/libprotobuf-mutator.git \ - /usr/src/libprotobuf-mutator; \ - cd /usr/src/libprotobuf-mutator; \ - git checkout 3521f47a2828da9ace403e4ecc4aece1a84feb36; \ - mkdir build; \ - cd build; \ - cmake .. -GNinja -DLIB_PROTO_MUTATOR_DOWNLOAD_PROTOBUF=ON \ - -DLIB_PROTO_MUTATOR_TESTING=OFF -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX="/usr"; \ - ninja; \ - cp -vpr external.protobuf/bin/* /usr/bin/; \ - cp -vpr external.protobuf/include/* /usr/include/; \ - cp -vpr external.protobuf/lib/* /usr/lib/; \ - ninja install/strip; \ - rm -rf /usr/src/libprotobuf-mutator - -# EVMONE -RUN set -ex; \ - cd /usr/src; \ - git clone --branch="v0.4.0" --recurse-submodules https://github.com/ethereum/evmone.git; \ - cd evmone; \ - mkdir build; \ - cd build; \ - # isoltest links against the evmone shared library - cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX="/usr" ..; \ - ninja; \ - ninja install/strip; \ - # abiv2_proto_ossfuzz links against the evmone standalone static library - cmake -G Ninja -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX="/usr" ..; \ - ninja; \ - ninja install/strip; \ - rm -rf /usr/src/evmone - -FROM base -COPY --from=libraries /usr/lib /usr/lib -COPY --from=libraries /usr/bin /usr/bin -COPY --from=libraries /usr/include /usr/include diff --git a/.circleci/docker/Dockerfile.ubuntu1904 b/.circleci/docker/Dockerfile.ubuntu2004 similarity index 52% rename from .circleci/docker/Dockerfile.ubuntu1904 rename to .circleci/docker/Dockerfile.ubuntu2004 index 903b6945b..d39025809 100644 --- a/.circleci/docker/Dockerfile.ubuntu1904 +++ b/.circleci/docker/Dockerfile.ubuntu2004 @@ -21,59 +21,26 @@ # # (c) 2016-2019 solidity contributors. #------------------------------------------------------------------------------ -FROM buildpack-deps:disco AS base +FROM buildpack-deps:focal AS base ARG DEBIAN_FRONTEND=noninteractive RUN set -ex; \ - dist=$(grep DISTRIB_CODENAME /etc/lsb-release | cut -d= -f2); \ - echo "deb http://ppa.launchpad.net/ethereum/cpp-build-deps/ubuntu $dist main" >> /etc/apt/sources.list ; \ - apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 1c52189c923f6ca9 ; \ apt-get update; \ apt-get install -qqy --no-install-recommends \ build-essential \ software-properties-common \ - cmake ninja-build clang++-8 libc++-8-dev libc++abi-8-dev \ + cmake ninja-build \ libboost-filesystem-dev libboost-test-dev libboost-system-dev \ libboost-program-options-dev \ - libjsoncpp-dev \ - llvm-8-dev libcvc4-dev libz3-static-dev libleveldb1d \ + libcvc4-dev z3 libz3-dev \ ; \ - apt-get install -qy python-pip python-sphinx; \ - update-alternatives --install /usr/bin/llvm-symbolizer llvm-symbolizer /usr/bin/llvm-symbolizer-8 1; \ - pip install codecov; \ + apt-get install -qy python3-pip python3-sphinx; \ + pip3 install codecov; \ rm -rf /var/lib/apt/lists/* FROM base AS libraries -# OSSFUZZ: libprotobuf-mutator -RUN set -ex; \ - git clone https://github.com/google/libprotobuf-mutator.git \ - /usr/src/libprotobuf-mutator; \ - cd /usr/src/libprotobuf-mutator; \ - git checkout d1fe8a7d8ae18f3d454f055eba5213c291986f21; \ - mkdir build; \ - cd build; \ - cmake .. -GNinja -DLIB_PROTO_MUTATOR_DOWNLOAD_PROTOBUF=ON \ - -DLIB_PROTO_MUTATOR_TESTING=OFF -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX="/usr"; \ - ninja; \ - cp -vpr external.protobuf/bin/* /usr/bin/; \ - cp -vpr external.protobuf/include/* /usr/include/; \ - cp -vpr external.protobuf/lib/* /usr/lib/; \ - ninja install/strip; \ - rm -rf /usr/src/libprotobuf-mutator - -# OSSFUZZ: libfuzzer -RUN set -ex; \ - cd /var/tmp; \ - svn co https://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/fuzzer libfuzzer; \ - mkdir -p build-libfuzzer; \ - cd build-libfuzzer; \ - clang++-8 -O1 -stdlib=libstdc++ -std=c++11 -O2 -fPIC -c ../libfuzzer/*.cpp -I../libfuzzer; \ - ar r /usr/lib/libFuzzingEngine.a *.o; \ - rm -rf /var/lib/libfuzzer - # EVMONE RUN set -ex; \ cd /usr/src; \ @@ -81,7 +48,6 @@ RUN set -ex; \ cd evmone; \ mkdir build; \ cd build; \ - # isoltest links against the evmone shared library cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX="/usr" ..; \ ninja; \ ninja install/strip; \ diff --git a/.circleci/docker/Dockerfile.ubuntu2004.clang b/.circleci/docker/Dockerfile.ubuntu2004.clang new file mode 100644 index 000000000..f436c34b7 --- /dev/null +++ b/.circleci/docker/Dockerfile.ubuntu2004.clang @@ -0,0 +1,61 @@ +# vim:syntax=dockerfile +#------------------------------------------------------------------------------ +# Dockerfile for building and testing Solidity Compiler on CI +# Target: Ubuntu 19.04 (Disco Dingo) Clang variant +# URL: https://hub.docker.com/r/ethereum/solidity-buildpack-deps +# +# 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 +# +# (c) 2016-2019 solidity contributors. +#------------------------------------------------------------------------------ +FROM buildpack-deps:focal AS base + +ARG DEBIAN_FRONTEND=noninteractive + +RUN set -ex; \ + apt-get update; \ + apt-get install -qqy --no-install-recommends \ + build-essential \ + software-properties-common \ + cmake ninja-build \ + libboost-filesystem-dev libboost-test-dev libboost-system-dev \ + libboost-program-options-dev \ + clang llvm-dev \ + z3 libz3-dev \ + ; \ + rm -rf /var/lib/apt/lists/* + +FROM base AS libraries + +ENV CC clang +ENV CXX clang++ + +# EVMONE +RUN set -ex; \ + cd /usr/src; \ + git clone --branch="v0.4.0" --recurse-submodules https://github.com/ethereum/evmone.git; \ + cd evmone; \ + mkdir build; \ + cd build; \ + cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX="/usr" ..; \ + ninja; \ + ninja install/strip; \ + rm -rf /usr/src/evmone + +FROM base +COPY --from=libraries /usr/lib /usr/lib +COPY --from=libraries /usr/bin /usr/bin +COPY --from=libraries /usr/include /usr/include diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp index dcd6f6a9c..230e0a8ba 100644 --- a/libsolidity/analysis/ViewPureChecker.cpp +++ b/libsolidity/analysis/ViewPureChecker.cpp @@ -230,7 +230,7 @@ void ViewPureChecker::endVisit(InlineAssembly const& _inlineAssembly) { AssemblyViewPureChecker{ _inlineAssembly.dialect(), - [=](StateMutability _mutability, SourceLocation const& _location) { reportMutability(_mutability, _location); } + [&](StateMutability _mutability, SourceLocation const& _location) { reportMutability(_mutability, _location); } }(_inlineAssembly.operations()); } diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index 5c6b7c927..2edd4dc38 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -527,7 +527,7 @@ bool AsmAnalyzer::warnOnInstructions(evmasm::Instruction _instr, SourceLocation // Similarly we assume bitwise shifting and create2 go together. yulAssert(m_evmVersion.hasBitwiseShifting() == m_evmVersion.hasCreate2(), ""); - auto errorForVM = [=](string const& vmKindMessage) { + auto errorForVM = [&](string const& vmKindMessage) { typeError( _location, "The \"" + diff --git a/libyul/backends/evm/EVMCodeTransform.cpp b/libyul/backends/evm/EVMCodeTransform.cpp index b9c5cb0ee..9e8d4d662 100644 --- a/libyul/backends/evm/EVMCodeTransform.cpp +++ b/libyul/backends/evm/EVMCodeTransform.cpp @@ -85,11 +85,11 @@ void VariableReferenceCounter::operator()(Block const& _block) void VariableReferenceCounter::increaseRefIfFound(YulString _variableName) { m_scope->lookup(_variableName, GenericVisitor{ - [=](Scope::Variable const& _var) + [&](Scope::Variable const& _var) { ++m_context.variableReferences[&_var]; }, - [=](Scope::Function const&) { } + [](Scope::Function const&) { } }); } @@ -272,7 +272,7 @@ void CodeTransform::operator()(FunctionCall const& _call) Scope::Function* function = nullptr; yulAssert(m_scope->lookup(_call.functionName.name, GenericVisitor{ - [=](Scope::Variable&) { yulAssert(false, "Expected function name."); }, + [](Scope::Variable&) { yulAssert(false, "Expected function name."); }, [&](Scope::Function& _function) { function = &_function; } }), "Function name not found."); yulAssert(function, ""); @@ -296,7 +296,7 @@ void CodeTransform::operator()(Identifier const& _identifier) // First search internals, then externals. yulAssert(m_scope, ""); if (m_scope->lookup(_identifier.name, GenericVisitor{ - [=](Scope::Variable& _var) + [&](Scope::Variable& _var) { // TODO: opportunity for optimization: Do not DUP if this is the last reference // to the top most element of the stack @@ -307,7 +307,7 @@ void CodeTransform::operator()(Identifier const& _identifier) m_assembly.appendConstant(u256(0)); decreaseReference(_identifier.name, _var); }, - [=](Scope::Function&) + [](Scope::Function&) { yulAssert(false, "Function not removed during desugaring."); } diff --git a/libyul/backends/wasm/EVMToEwasmTranslator.cpp b/libyul/backends/wasm/EVMToEwasmTranslator.cpp index dc69d913a..ebcdd961b 100644 --- a/libyul/backends/wasm/EVMToEwasmTranslator.cpp +++ b/libyul/backends/wasm/EVMToEwasmTranslator.cpp @@ -1232,7 +1232,7 @@ Object EVMToEwasmTranslator::run(Object const& _object) FunctionHoister::run(context, ast); FunctionGrouper::run(context, ast); - MainFunction{}(ast); + MainFunction::run(context, ast); ForLoopConditionIntoBody::run(context, ast); ExpressionSplitter::run(context, ast); WordSizeTransform::run(m_dialect, WasmDialect::instance(), ast, nameDispenser); diff --git a/libyul/optimiser/RedundantAssignEliminator.cpp b/libyul/optimiser/RedundantAssignEliminator.cpp index 236a27fb0..5d1d0557b 100644 --- a/libyul/optimiser/RedundantAssignEliminator.cpp +++ b/libyul/optimiser/RedundantAssignEliminator.cpp @@ -306,7 +306,7 @@ void RedundantAssignEliminator::finalize(YulString _variable, RedundantAssignEli void AssignmentRemover::operator()(Block& _block) { - boost::range::remove_erase_if(_block.statements, [=](Statement const& _statement) -> bool { + boost::range::remove_erase_if(_block.statements, [&](Statement const& _statement) -> bool { return holds_alternative(_statement) && m_toRemove.count(&std::get(_statement)); }); diff --git a/libyul/optimiser/UnusedPruner.cpp b/libyul/optimiser/UnusedPruner.cpp index 6ed8df47c..a0e0f535d 100644 --- a/libyul/optimiser/UnusedPruner.cpp +++ b/libyul/optimiser/UnusedPruner.cpp @@ -86,7 +86,7 @@ void UnusedPruner::operator()(Block& _block) if (std::none_of( varDecl.variables.begin(), varDecl.variables.end(), - [=](TypedName const& _typedName) { return used(_typedName.name); } + [&](TypedName const& _typedName) { return used(_typedName.name); } )) { if (!varDecl.value) diff --git a/scripts/docs.sh b/scripts/docs.sh index 2c08a82bc..91f619d89 100755 --- a/scripts/docs.sh +++ b/scripts/docs.sh @@ -28,6 +28,6 @@ set -e cd docs -pip install -r requirements.txt +pip3 install -r requirements.txt sphinx-build -nW -b html -d _build/doctrees . _build/html cd .. From c2f5a66a79def58aa56e38d25122a92f1d782a6d Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 6 May 2020 17:40:06 +0200 Subject: [PATCH 64/89] Implement .creationCode for Sol->Yul. --- .../codegen/ir/IRGeneratorForStatements.cpp | 15 ++++++++++- .../constructor/callvalue_check.sol | 1 + .../various/code_access_create.sol | 2 ++ .../various/code_access_runtime.sol | 27 +++++++++++++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 test/libsolidity/semanticTests/various/code_access_runtime.sol diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 7faf0d43c..553f618cd 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -1304,7 +1304,20 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) solAssert(false, "Blockhash has been removed."); else if (member == "creationCode" || member == "runtimeCode") { - solUnimplementedAssert(false, ""); + solUnimplementedAssert(member != "runtimeCode", ""); + TypePointer arg = dynamic_cast(*_memberAccess.expression().annotation().type).typeArgument(); + ContractDefinition const& contract = dynamic_cast(*arg).contractDefinition(); + m_context.subObjectsCreated().insert(&contract); + m_code << Whiskers(R"( + let := datasize("") + let := (add(, 32)) + mstore(, ) + datacopy(add(, 32), dataoffset(""), ) + )") + ("allocationFunction", m_utils.allocationFunction()) + ("size", m_context.newYulVariable()) + ("objectName", m_context.creationObjectName(contract)) + ("result", IRVariable(_memberAccess).commaSeparatedList()).render(); } else if (member == "name") { diff --git a/test/libsolidity/semanticTests/constructor/callvalue_check.sol b/test/libsolidity/semanticTests/constructor/callvalue_check.sol index 7a327e695..c096382d0 100644 --- a/test/libsolidity/semanticTests/constructor/callvalue_check.sol +++ b/test/libsolidity/semanticTests/constructor/callvalue_check.sol @@ -29,6 +29,7 @@ contract C { } // ==== // EVMVersion: >homestead +// compileViaYul: also // ---- // f(uint256), 2000 ether: 0 -> true // f(uint256), 2000 ether: 100 -> false diff --git a/test/libsolidity/semanticTests/various/code_access_create.sol b/test/libsolidity/semanticTests/various/code_access_create.sol index 3fbcf6132..9029e59ec 100644 --- a/test/libsolidity/semanticTests/various/code_access_create.sol +++ b/test/libsolidity/semanticTests/various/code_access_create.sol @@ -22,5 +22,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // test() -> 7 diff --git a/test/libsolidity/semanticTests/various/code_access_runtime.sol b/test/libsolidity/semanticTests/various/code_access_runtime.sol new file mode 100644 index 000000000..cc1401c6f --- /dev/null +++ b/test/libsolidity/semanticTests/various/code_access_runtime.sol @@ -0,0 +1,27 @@ +contract D { + uint256 x; + + constructor() public { + x = 7; + } + + function f() public view returns (uint256) { + return x; + } +} + + +contract C { + function test() public returns (uint256) { + D d = new D(); + bytes32 hash; + assembly { hash := extcodehash(d) } + assert(hash == keccak256(type(D).runtimeCode)); + return 42; + } +} + +// ==== +// EVMVersion: >=constantinople +// ---- +// test() -> 42 From 00946f3ea09321c2db7799897b183ba48a7cc597 Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Mon, 20 Apr 2020 14:06:16 +0200 Subject: [PATCH 65/89] ossfuzz: Add sol proto fuzzer skeleton Co-Authored-By: Leonardo --- test/tools/ossfuzz/protoToSol.cpp | 227 ++++++++++++++++++++++++++++++ test/tools/ossfuzz/protoToSol.h | 185 ++++++++++++++++++++++++ test/tools/ossfuzz/solProto.proto | 111 +++++++++++++++ 3 files changed, 523 insertions(+) create mode 100644 test/tools/ossfuzz/protoToSol.cpp create mode 100644 test/tools/ossfuzz/protoToSol.h create mode 100644 test/tools/ossfuzz/solProto.proto diff --git a/test/tools/ossfuzz/protoToSol.cpp b/test/tools/ossfuzz/protoToSol.cpp new file mode 100644 index 000000000..9551ee3ec --- /dev/null +++ b/test/tools/ossfuzz/protoToSol.cpp @@ -0,0 +1,227 @@ +/* + 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 . +*/ + +#include + +#include + +#include + +#include + +using namespace solidity::test::solprotofuzzer; +using namespace solidity::util; +using namespace std; + +string ProtoConverter::protoToSolidity(Program const& _p) +{ + // Create random number generator with fuzzer supplied + // seed. + m_randomGen = make_shared(_p.seed()); + return visit(_p); +} + +pair ProtoConverter::generateTestCase(TestContract const& _testContract) +{ + ostringstream testCode; + string usingLibDecl; + switch (_testContract.type()) + { + case TestContract::LIBRARY: + { + m_libraryTest = true; + auto testTuple = pseudoRandomLibraryTest(); + m_libraryName = get<0>(testTuple); + usingLibDecl = Whiskers(R"( + using for uint;)") + ("libraryName", get<0>(testTuple)) + .render(); + testCode << Whiskers(R"( + uint x; + if (x.() != ) + return 1;)") + ("testFunction", get<1>(testTuple)) + ("expectedOutput", get<2>(testTuple)) + .render(); + break; + } + case TestContract::CONTRACT: + { + unsigned errorCode = 1; + unsigned contractVarIndex = 0; + for (auto const& testTuple: m_contractTests) + { + // Do this to avoid stack too deep errors + // We require uint as a return var, so we + // cannot have more than 16 variables without + // running into stack too deep errors + if (contractVarIndex >= s_maxVars) + break; + string contractName = testTuple.first; + string contractVarName = "tc" + to_string(contractVarIndex); + testCode << Whiskers(R"( + = new ();)") + ("contractName", contractName) + ("contractVarName", contractVarName) + .render(); + for (auto const& t: testTuple.second) + { + testCode << Whiskers(R"( + if (.() != ) + return ;)") + ("contractVarName", contractVarName) + ("testFunction", t.first) + ("expectedOutput", t.second) + ("errorCode", to_string(errorCode)) + .render(); + errorCode++; + } + contractVarIndex++; + } + break; + } + } + // Expected return value when all tests pass + testCode << Whiskers(R"( + return 0;)") + .render(); + return pair(usingLibDecl, testCode.str()); +} + +string ProtoConverter::visit(TestContract const& _testContract) +{ + string testCode; + string usingLibDecl; + m_libraryTest = false; + + // Simply return valid uint (zero) if there are + // no tests. + if (emptyLibraryTests() || emptyContractTests()) + testCode = Whiskers(R"( + return 0;)") + .render(); + else + tie(usingLibDecl, testCode) = generateTestCase(_testContract); + + return Whiskers(R"( +contract C { + function test() public returns (uint) + { + } +} +)") + ("isLibrary", m_libraryTest) + ("usingDecl", usingLibDecl) + ("testCode", testCode) + .render(); +} + +bool ProtoConverter::libraryTest() const +{ + return m_libraryTest; +} + +string ProtoConverter::libraryName() const +{ + return m_libraryName; +} + +string ProtoConverter::visit(Program const& _p) +{ + ostringstream program; + ostringstream contracts; + + for (auto &contract: _p.contracts()) + contracts << visit(contract); + + program << Whiskers(R"( +pragma solidity >=0.0; + + + + +)") + ("contracts", contracts.str()) + ("testContract", visit(_p.test())) + .render(); + return program.str(); +} + +string ProtoConverter::visit(ContractType const& _contractType) +{ + switch (_contractType.contract_type_oneof_case()) + { + case ContractType::kC: + return visit(_contractType.c()); + case ContractType::kL: + return visit(_contractType.l()); + case ContractType::kI: + return visit(_contractType.i()); + case ContractType::CONTRACT_TYPE_ONEOF_NOT_SET: + return ""; + } +} + +string ProtoConverter::visit(Contract const& _contract) +{ + openProgramScope(&_contract); + return ""; +} + +string ProtoConverter::visit(Interface const& _interface) +{ + openProgramScope(&_interface); + return ""; +} + +string ProtoConverter::visit(Library const& _library) +{ + openProgramScope(&_library); + return ""; +} + +tuple ProtoConverter::pseudoRandomLibraryTest() +{ + solAssert(m_libraryTests.size() > 0, "Sol proto fuzzer: No library tests found"); + unsigned index = randomNumber() % m_libraryTests.size(); + return m_libraryTests[index]; +} + +void ProtoConverter::openProgramScope(CIL _program) +{ + string programNamePrefix; + if (holds_alternative(_program)) + programNamePrefix = "C"; + else if (holds_alternative(_program)) + programNamePrefix = "I"; + else + programNamePrefix = "L"; + string programName = programNamePrefix + to_string(m_programNumericSuffix++); + m_programNameMap.emplace(_program, programName); +} + +string ProtoConverter::programName(CIL _program) +{ + solAssert(m_programNameMap.count(_program), "Sol proto fuzzer: Unregistered program"); + return m_programNameMap[_program]; +} + +unsigned ProtoConverter::randomNumber() +{ + solAssert(m_randomGen, "Sol proto fuzzer: Uninitialized random number generator"); + return m_randomGen->operator()(); +} diff --git a/test/tools/ossfuzz/protoToSol.h b/test/tools/ossfuzz/protoToSol.h new file mode 100644 index 000000000..6a534d71c --- /dev/null +++ b/test/tools/ossfuzz/protoToSol.h @@ -0,0 +1,185 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +#pragma once + +#include + +#include +#include +#include +#include + +namespace solidity::test::solprotofuzzer +{ +/// Random number generator that is seeded with a fuzzer +/// supplied unsigned integer. +struct SolRandomNumGenerator +{ + using RandomEngine = std::minstd_rand; + + explicit SolRandomNumGenerator(unsigned _seed): m_random(RandomEngine(_seed)) {} + + /// @returns a pseudo random unsigned integer + unsigned operator()() + { + return m_random(); + } + + RandomEngine m_random; +}; + +/* There are two types of tests created by the converter: + * - library test + * - contract test + * + * The template for library test is the following: + * + * // Library generated from fuzzer protobuf specification + * library L0 { + * function f0(uint) public view returns (uint) { + * return 31337; + * } + * function f1(uint) public pure returns (uint) { + * return 455; + * } + * } + * library L1 { + * function f0(uint) external view returns (uint) { + * return 607; + * } + * } + * + * // Test entry point + * contract C { + * // Uses a single pseudo randomly chosen library + * // and calls a pseudo randomly chosen function + * // returning a non-zero error code on failure or + * // a zero uint when test passes. + * using L0 for uint; + * function test() public pure returns (uint) { + * uint x; + * if (x.f1() != 455) + * return 1; + * return 0; + * } + * } + * + * The template for contract test is the following + * // Contracts generated from fuzzer protobuf specification + * contract C0B { + * function f0() public pure virtual returns (uint) + * { + * return 42; + * } + * } + * contract C0 is C0B { + * function f0() public pure override returns (uint) + * { + * return 1337; + * } + * } + * + * // Test entry point + * contract C { + * // Invokes one or more contract functions returning + * // a non-zero error code for failure, a zero uint + * // when all tests pass + * function test() public pure returns (uint) + * { + * C0 tc0 = new C0(); + * if (tc0.f0() != 1337) + * return 1; + * C0B tc1 = new C0B(); + * if (tc1.f0() != 42) + * return 2; + * // Expected return value if all tests pass + * return 0; + * } + * } + */ +class ProtoConverter +{ +public: + ProtoConverter() {} + ProtoConverter(ProtoConverter const&) = delete; + ProtoConverter(ProtoConverter&&) = delete; + std::string protoToSolidity(Program const&); + /// @returns true if test calls a library function, false + /// otherwise + bool libraryTest() const; + /// @returns name of the library under test + std::string libraryName() const; +private: + /// Variant type that points to one of contract, interface, library protobuf messages + using CIL = std::variant; + /// Protobuf message visitors that accept a const reference to a protobuf message + /// type and return its solidity translation. + std::string visit(Program const&); + std::string visit(TestContract const&); + std::string visit(ContractType const&); + std::string visit(Interface const& _interface); + std::string visit(Library const& _library); + std::string visit(Contract const& _contract); + /// @returns a string pair containing a library declaration (relevant for library + /// tests only) and a solidity test case + std::pair generateTestCase(TestContract const& _testContract); + /// @returns name of a program i.e., contract, library or interface + std::string programName(CIL _program); + /// @returns a tuple containing the names of the library and function under + /// test, and its expected output. + std::tuple pseudoRandomLibraryTest(); + /// Performs bookkeeping for a fuzzer-supplied program + void openProgramScope(CIL _program); + /// @returns a deterministic pseudo random unsigned integer + unsigned randomNumber(); + /// @returns true if fuzzer supplied Library protobuf message + /// contains zero functions, false otherwise. + static bool emptyLibrary(Library const& _library) + { + return _library.funcdef_size() == 0; + } + /// @returns true if there are no valid library test cases, false + /// otherwise. + bool emptyLibraryTests() + { + return m_libraryTests.size() == 0; + } + /// @returns true if there are no valid contract test cases, false + /// otherwise. + bool emptyContractTests() + { + return m_contractTests.size() == 0; + } + /// Numeric suffix that is part of program names e.g., "0" in "C0" + unsigned m_programNumericSuffix = 0; + /// Flag that states whether library call is tested (true) or not (false). + bool m_libraryTest = false; + /// A smart pointer to fuzzer driven random number generator + std::shared_ptr m_randomGen; + /// Maps protobuf program to its string name + std::map m_programNameMap; + /// List of tuples containing library name, function and its expected output + std::vector> m_libraryTests; + /// Maps contract name to a map of function names and their expected output + std::map> m_contractTests; + /// Name of the library under test, relevant if m_libraryTest is set + std::string m_libraryName; + /// Maximum number of local variables in test function to avoid stack too deep + /// errors + static unsigned constexpr s_maxVars = 15; +}; +} diff --git a/test/tools/ossfuzz/solProto.proto b/test/tools/ossfuzz/solProto.proto new file mode 100644 index 000000000..f0444e0d7 --- /dev/null +++ b/test/tools/ossfuzz/solProto.proto @@ -0,0 +1,111 @@ +/* + 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 . +*/ + +syntax = "proto2"; + +message InterfaceFunction { + enum StateMutability { + PURE = 0; + VIEW = 1; + PAYABLE = 2; + NONPAYABLE = 3; + } + required StateMutability mut = 1; +} + +message LibraryFunction { + // Library functions cannot be payable + enum StateMutability { + PURE = 0; + VIEW = 1; + NONPAYABLE = 2; + } + enum Visibility { + PUBLIC = 0; + EXTERNAL = 1; + INTERNAL = 2; + PRIVATE = 3; + } + required Visibility vis = 1; + required StateMutability mut = 2; +} + +message ContractFunction { + enum StateMutability { + PURE = 0; + VIEW = 1; + PAYABLE = 2; + NONPAYABLE = 3; + } + enum Visibility { + PUBLIC = 0; + EXTERNAL = 1; + INTERNAL = 2; + PRIVATE = 3; + } + required Visibility vis = 1; + required StateMutability mut = 2; + required bool virtualfunc = 3; +} + +message Library { + repeated LibraryFunction funcdef = 1; +} + +message Interface { + repeated InterfaceFunction funcdef = 1; + repeated Interface bases = 2; +} + +message Contract { + repeated ContractFunction funcdef = 1; + required bool abstract = 2; + repeated ContractOrInterface bases = 3; +} + +message ContractOrInterface { + oneof contract_or_interface_oneof { + Contract c = 1; + Interface i = 2; + } +} + +message ContractType { + oneof contract_type_oneof { + Contract c = 1; + Library l = 2; + Interface i = 3; + } +} + +message TestContract { + enum Type { + LIBRARY = 0; + CONTRACT = 1; + } + required Type type = 1; +} + +message Program { + repeated ContractType contracts = 1; + required TestContract test = 2; + // Seed is an unsigned integer that initializes + // a pseudo random number generator. + required uint64 seed = 3; +} + +package solidity.test.solprotofuzzer; \ No newline at end of file From 596ac018f53c287f55c6bbd5f5af41156dd1da6f Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Mon, 20 Apr 2020 16:08:31 +0200 Subject: [PATCH 66/89] Fuzzer: Add test harness for solidity inheritance protobuf fuzzer Co-Authored-By: Leonardo --- .circleci/config.yml | 2 + test/tools/ossfuzz/CMakeLists.txt | 21 ++- test/tools/ossfuzz/protoToSol.cpp | 107 ++++++------ test/tools/ossfuzz/protoToSol.h | 4 +- test/tools/ossfuzz/solProto.proto | 2 +- test/tools/ossfuzz/solProtoFuzzer.cpp | 234 ++++++++++++++++++++++++++ 6 files changed, 313 insertions(+), 57 deletions(-) create mode 100644 test/tools/ossfuzz/solProtoFuzzer.cpp diff --git a/.circleci/config.yml b/.circleci/config.yml index e1161e432..f2b58bf47 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -50,6 +50,7 @@ defaults: cd build protoc --proto_path=../test/tools/ossfuzz yulProto.proto --cpp_out=../test/tools/ossfuzz protoc --proto_path=../test/tools/ossfuzz abiV2Proto.proto --cpp_out=../test/tools/ossfuzz + protoc --proto_path=../test/tools/ossfuzz solProto.proto --cpp_out=../test/tools/ossfuzz cmake .. -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE:-Release} $CMAKE_OPTIONS make ossfuzz ossfuzz_proto ossfuzz_abiv2 -j4 @@ -97,6 +98,7 @@ defaults: - test/tools/ossfuzz/strictasm_opt_ossfuzz - test/tools/ossfuzz/yul_proto_diff_ossfuzz - test/tools/ossfuzz/yul_proto_ossfuzz + - test/tools/ossfuzz/sol_proto_ossfuzz # test result output directory - artifacts_test_results: &artifacts_test_results diff --git a/test/tools/ossfuzz/CMakeLists.txt b/test/tools/ossfuzz/CMakeLists.txt index 83543b9f0..ccd71a983 100644 --- a/test/tools/ossfuzz/CMakeLists.txt +++ b/test/tools/ossfuzz/CMakeLists.txt @@ -10,7 +10,7 @@ add_dependencies(ossfuzz if (OSSFUZZ) add_custom_target(ossfuzz_proto) - add_dependencies(ossfuzz_proto yul_proto_ossfuzz yul_proto_diff_ossfuzz) + add_dependencies(ossfuzz_proto yul_proto_ossfuzz yul_proto_diff_ossfuzz sol_proto_ossfuzz) add_custom_target(ossfuzz_abiv2) add_dependencies(ossfuzz_abiv2 abiv2_proto_ossfuzz) @@ -78,6 +78,25 @@ if (OSSFUZZ) protobuf.a ) set_target_properties(abiv2_proto_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE}) + + add_executable(sol_proto_ossfuzz + solProtoFuzzer.cpp + protoToSol.cpp + solProto.pb.cc + abiV2FuzzerCommon.cpp + ../../EVMHost.cpp + ) + target_include_directories(sol_proto_ossfuzz PRIVATE + /usr/include/libprotobuf-mutator + ) + target_link_libraries(sol_proto_ossfuzz PRIVATE solidity libsolc + evmc + evmone-standalone + protobuf-mutator-libfuzzer.a + protobuf-mutator.a + protobuf.a + ) + set_target_properties(sol_proto_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE}) else() add_library(solc_opt_ossfuzz solc_opt_ossfuzz.cpp diff --git a/test/tools/ossfuzz/protoToSol.cpp b/test/tools/ossfuzz/protoToSol.cpp index 9551ee3ec..aefbb41b9 100644 --- a/test/tools/ossfuzz/protoToSol.cpp +++ b/test/tools/ossfuzz/protoToSol.cpp @@ -46,17 +46,22 @@ pair ProtoConverter::generateTestCase(TestContract const& _testC m_libraryTest = true; auto testTuple = pseudoRandomLibraryTest(); m_libraryName = get<0>(testTuple); - usingLibDecl = Whiskers(R"( - using for uint;)") - ("libraryName", get<0>(testTuple)) - .render(); - testCode << Whiskers(R"( - uint x; - if (x.() != ) - return 1;)") - ("testFunction", get<1>(testTuple)) - ("expectedOutput", get<2>(testTuple)) - .render(); + Whiskers u(R"(using for uint;)"); + u("ind", "\t"); + u("libraryName", get<0>(testTuple)); + usingLibDecl = u.render(); + Whiskers test(R"()"); + test("endl", "\n"); + test("ind", "\t\t"); + test("varDecl", "uint x;"); + Whiskers ifStmt(R"(if ()return 1;)"); + Whiskers ifCond(R"(x.() != )"); + ifCond("testFunction", get<1>(testTuple)); + ifCond("expectedOutput", get<2>(testTuple)); + ifStmt("cond", ifCond.render()); + ifStmt("endl", "\n"); + ifStmt("ind", "\t\t\t"); + test("ifStmt", ifStmt.render()); break; } case TestContract::CONTRACT: @@ -73,21 +78,28 @@ pair ProtoConverter::generateTestCase(TestContract const& _testC break; string contractName = testTuple.first; string contractVarName = "tc" + to_string(contractVarIndex); - testCode << Whiskers(R"( - = new ();)") - ("contractName", contractName) - ("contractVarName", contractVarName) - .render(); + Whiskers init(R"( = new ();)"); + init("endl", "\n"); + init("ind", "\t\t"); + init("contractName", contractName); + init("contractVarName", contractVarName); + testCode << init.render(); for (auto const& t: testTuple.second) { - testCode << Whiskers(R"( - if (.() != ) - return ;)") - ("contractVarName", contractVarName) - ("testFunction", t.first) - ("expectedOutput", t.second) - ("errorCode", to_string(errorCode)) - .render(); + Whiskers tc(R"()"); + tc("endl", "\n"); + tc("ind", "\t\t"); + Whiskers ifStmt(R"(if ()return ;)"); + Whiskers ifCond(R"(.() != )"); + ifCond("contractVarName", contractVarName); + ifCond("testFunction", t.first); + ifCond("expectedOutput", t.second); + ifStmt("endl", "\n"); + ifStmt("cond", ifCond.render()); + ifStmt("ind", "\t\t\t"); + ifStmt("errorCode", to_string(errorCode)); + tc("ifStmt", ifStmt.render()); + testCode << tc.render(); errorCode++; } contractVarIndex++; @@ -96,10 +108,8 @@ pair ProtoConverter::generateTestCase(TestContract const& _testC } } // Expected return value when all tests pass - testCode << Whiskers(R"( - return 0;)") - .render(); - return pair(usingLibDecl, testCode.str()); + testCode << Whiskers(R"(return 0;)")("endl", "\n")("ind", "\t\t").render(); + return {usingLibDecl, testCode.str()}; } string ProtoConverter::visit(TestContract const& _testContract) @@ -111,23 +121,20 @@ string ProtoConverter::visit(TestContract const& _testContract) // Simply return valid uint (zero) if there are // no tests. if (emptyLibraryTests() || emptyContractTests()) - testCode = Whiskers(R"( - return 0;)") - .render(); + testCode = Whiskers(R"(return 0;)")("endl", "\n")("ind", "\t\t").render(); else tie(usingLibDecl, testCode) = generateTestCase(_testContract); - return Whiskers(R"( -contract C { - function test() public returns (uint) - { - } -} -)") - ("isLibrary", m_libraryTest) - ("usingDecl", usingLibDecl) - ("testCode", testCode) - .render(); + Whiskers c(R"(contract C {})"); + c("endl", "\n"); + c("isLibrary", m_libraryTest); + c("usingDecl", usingLibDecl); + Whiskers f("function test() public returns (uint){}"); + f("ind", "\t"); + f("endl", "\n"); + f("testCode", testCode); + c("function", f.render()); + return c.render(); } bool ProtoConverter::libraryTest() const @@ -148,17 +155,11 @@ string ProtoConverter::visit(Program const& _p) for (auto &contract: _p.contracts()) contracts << visit(contract); - program << Whiskers(R"( -pragma solidity >=0.0; - - - - -)") - ("contracts", contracts.str()) - ("testContract", visit(_p.test())) - .render(); - return program.str(); + Whiskers p(R"(pragma solidity >=0.0;)"); + p("endl", "\n"); + p("contracts", contracts.str()); + p("test", visit(_p.test())); + return p.render(); } string ProtoConverter::visit(ContractType const& _contractType) diff --git a/test/tools/ossfuzz/protoToSol.h b/test/tools/ossfuzz/protoToSol.h index 6a534d71c..de2220752 100644 --- a/test/tools/ossfuzz/protoToSol.h +++ b/test/tools/ossfuzz/protoToSol.h @@ -156,13 +156,13 @@ private: /// otherwise. bool emptyLibraryTests() { - return m_libraryTests.size() == 0; + return m_libraryTests.empty(); } /// @returns true if there are no valid contract test cases, false /// otherwise. bool emptyContractTests() { - return m_contractTests.size() == 0; + return m_contractTests.empty(); } /// Numeric suffix that is part of program names e.g., "0" in "C0" unsigned m_programNumericSuffix = 0; diff --git a/test/tools/ossfuzz/solProto.proto b/test/tools/ossfuzz/solProto.proto index f0444e0d7..86e938c7c 100644 --- a/test/tools/ossfuzz/solProto.proto +++ b/test/tools/ossfuzz/solProto.proto @@ -108,4 +108,4 @@ message Program { required uint64 seed = 3; } -package solidity.test.solprotofuzzer; \ No newline at end of file +package solidity.test.solprotofuzzer; diff --git a/test/tools/ossfuzz/solProtoFuzzer.cpp b/test/tools/ossfuzz/solProtoFuzzer.cpp new file mode 100644 index 000000000..80facb3e1 --- /dev/null +++ b/test/tools/ossfuzz/solProtoFuzzer.cpp @@ -0,0 +1,234 @@ +/* + 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 . +*/ + +#include +#include +#include +#include + +#include +#include + +#include + +static evmc::VM evmone = evmc::VM{evmc_create_evmone()}; + +using namespace solidity::test::abiv2fuzzer; +using namespace solidity::test::solprotofuzzer; +using namespace solidity; +using namespace solidity::test; +using namespace solidity::util; +using namespace std; + +namespace +{ +/// Test function returns a uint256 value +static size_t const expectedOutputLength = 32; +/// Expected output value is decimal 0 +static uint8_t const expectedOutput[expectedOutputLength] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/// Compares the contents of the memory address pointed to +/// by `_result` of `_length` bytes to the expected output. +/// Returns true if `_result` matches expected output, false +/// otherwise. +bool isOutputExpected(evmc::result const& _run) +{ + if (_run.output_size != expectedOutputLength) + return false; + + return memcmp(_run.output_data, expectedOutput, expectedOutputLength) == 0; +} + +/// Accepts a reference to a user-specified input and returns an +/// evmc_message with all of its fields zero initialized except +/// gas and input fields. +/// The gas field is set to the maximum permissible value so that we +/// don't run into out of gas errors. The input field is copied from +/// user input. +evmc_message initializeMessage(bytes const& _input) +{ + // Zero initialize all message fields + evmc_message msg = {}; + // Gas available (value of type int64_t) is set to its maximum + // value. + msg.gas = std::numeric_limits::max(); + msg.input_data = _input.data(); + msg.input_size = _input.size(); + return msg; +} + +/// Accepts host context implementation, and keccak256 hash of the function +/// to be called at a specified address in the simulated blockchain as +/// input and returns the result of the execution of the called function. +evmc::result executeContract( + EVMHost& _hostContext, + bytes const& _functionHash, + evmc_address _deployedAddress +) +{ + evmc_message message = initializeMessage(_functionHash); + message.destination = _deployedAddress; + message.kind = EVMC_CALL; + return _hostContext.call(message); +} + +/// Accepts a reference to host context implementation and byte code +/// as input and deploys it on the simulated blockchain. Returns the +/// result of deployment. +evmc::result deployContract(EVMHost& _hostContext, bytes const& _code) +{ + evmc_message message = initializeMessage(_code); + message.kind = EVMC_CREATE; + return _hostContext.call(message); +} + +std::pair compileContract( + std::string _sourceCode, + std::string _contractName, + std::map const& _libraryAddresses = {}, + frontend::OptimiserSettings _optimization = frontend::OptimiserSettings::minimal() +) +{ + try + { + // Compile contract generated by the proto fuzzer + SolidityCompilationFramework solCompilationFramework; + return std::make_pair( + solCompilationFramework.compileContract(_sourceCode, _contractName, _libraryAddresses, _optimization), + solCompilationFramework.getMethodIdentifiers() + ); + } + // Ignore stack too deep errors during compilation + catch (evmasm::StackTooDeepException const&) + { + return std::make_pair(bytes{}, Json::Value(0)); + } +} + +evmc::result deployAndExecute(EVMHost& _hostContext, bytes _byteCode, std::string _hexEncodedInput) +{ + // Deploy contract and signal failure if deploy failed + evmc::result createResult = deployContract(_hostContext, _byteCode); + solAssert( + createResult.status_code == EVMC_SUCCESS, + "Proto solc fuzzer: Contract creation failed" + ); + + // Execute test function and signal failure if EVM reverted or + // did not return expected output on successful execution. + evmc::result callResult = executeContract( + _hostContext, + fromHex(_hexEncodedInput), + createResult.create_address + ); + + // We don't care about EVM One failures other than EVMC_REVERT + solAssert(callResult.status_code != EVMC_REVERT, "Proto solc fuzzer: EVM One reverted"); + return callResult; +} + +evmc::result compileDeployAndExecute( + std::string _sourceCode, + std::string _contractName, + std::string _methodName, + frontend::OptimiserSettings _optimization, + std::string _libraryName = {} +) +{ + bytes libraryBytecode; + Json::Value libIds; + // We target the default EVM which is the latest + langutil::EVMVersion version = {}; + EVMHost hostContext(version, evmone); + std::map _libraryAddressMap; + + // First deploy library + if (!_libraryName.empty()) + { + tie(libraryBytecode, libIds) = compileContract( + _sourceCode, + _libraryName, + {}, + _optimization + ); + // Deploy contract and signal failure if deploy failed + evmc::result createResult = deployContract(hostContext, libraryBytecode); + solAssert( + createResult.status_code == EVMC_SUCCESS, + "Proto solc fuzzer: Library deployment failed" + ); + _libraryAddressMap[_libraryName] = EVMHost::convertFromEVMC(createResult.create_address); + } + + auto [bytecode, ids] = compileContract( + _sourceCode, + _contractName, + _libraryAddressMap, + _optimization + ); + + return deployAndExecute( + hostContext, + bytecode, + ids[_methodName].asString() + ); +} +} + +DEFINE_PROTO_FUZZER(Program const& _input) +{ + ProtoConverter converter; + string sol_source = converter.protoToSolidity(_input); + + if (char const* dump_path = getenv("PROTO_FUZZER_DUMP_PATH")) + { + // With libFuzzer binary run this to generate a YUL source file x.yul: + // PROTO_FUZZER_DUMP_PATH=x.yul ./a.out proto-input + ofstream of(dump_path); + of.write(sol_source.data(), sol_source.size()); + } + + if (char const* dump_path = getenv("SOL_DEBUG_FILE")) + { + sol_source.clear(); + // With libFuzzer binary run this to generate a YUL source file x.yul: + // PROTO_FUZZER_LOAD_PATH=x.yul ./a.out proto-input + ifstream ifstr(dump_path); + sol_source = { + std::istreambuf_iterator(ifstr), + std::istreambuf_iterator() + }; + std::cout << sol_source << std::endl; + } + + auto minimalResult = compileDeployAndExecute( + sol_source, + ":C", + "test()", + frontend::OptimiserSettings::minimal(), + converter.libraryTest() ? converter.libraryName() : "" + ); + bool successState = minimalResult.status_code == EVMC_SUCCESS; + if (successState) + solAssert( + isOutputExpected(minimalResult), + "Proto solc fuzzer: Output incorrect" + ); +} From 1d5350e32f04e991dbfc8fca402cbc8c7930e85d Mon Sep 17 00:00:00 2001 From: a3d4 Date: Tue, 12 May 2020 02:26:02 +0200 Subject: [PATCH 67/89] Add error IDs to OverrideChecker --- libsolidity/analysis/OverrideChecker.cpp | 35 ++++++++++++++---------- libsolidity/analysis/OverrideChecker.h | 4 +++ 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/libsolidity/analysis/OverrideChecker.cpp b/libsolidity/analysis/OverrideChecker.cpp index 1f4fa10a2..4cf2ff8f4 100644 --- a/libsolidity/analysis/OverrideChecker.cpp +++ b/libsolidity/analysis/OverrideChecker.cpp @@ -506,12 +506,13 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr ); if (!_overriding.overrides()) - overrideError(_overriding, _super, "Overriding " + _overriding.astNodeName() + " is missing \"override\" specifier."); + overrideError(_overriding, _super, 9456_error, "Overriding " + _overriding.astNodeName() + " is missing \"override\" specifier."); if (_super.isVariable()) overrideError( _super, _overriding, + 1452_error, "Cannot override public state variable.", "Overriding " + _overriding.astNodeName() + " is here:" ); @@ -519,6 +520,7 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr overrideError( _super, _overriding, + 4334_error, "Trying to override non-virtual " + _super.astNodeName() + ". Did you forget to add \"virtual\"?", "Overriding " + _overriding.astNodeName() + " is here:" ); @@ -526,7 +528,7 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr if (_overriding.isVariable()) { if (_super.visibility() != Visibility::External) - overrideError(_overriding, _super, "Public state variables can only override functions with external visibility."); + overrideError(_overriding, _super, 5225_error, "Public state variables can only override functions with external visibility."); solAssert(_overriding.visibility() == Visibility::External, ""); } else if (_overriding.visibility() != _super.visibility()) @@ -537,7 +539,7 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr _super.visibility() == Visibility::External && _overriding.visibility() == Visibility::Public )) - overrideError(_overriding, _super, "Overriding " + _overriding.astNodeName() + " visibility differs."); + overrideError(_overriding, _super, 9098_error, "Overriding " + _overriding.astNodeName() + " visibility differs."); } if (_super.isFunction()) @@ -548,7 +550,7 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr solAssert(functionType->hasEqualParameterTypes(*superType), "Override doesn't have equal parameters!"); if (!functionType->hasEqualReturnTypes(*superType)) - overrideError(_overriding, _super, "Overriding " + _overriding.astNodeName() + " return types differ."); + overrideError(_overriding, _super, 4822_error, "Overriding " + _overriding.astNodeName() + " return types differ."); // This is only relevant for a function overriding a function. if (_overriding.isFunction()) @@ -557,6 +559,7 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr overrideError( _overriding, _super, + 2837_error, "Overriding function changes state mutability from \"" + stateMutabilityToString(_super.stateMutability()) + "\" to \"" + @@ -568,6 +571,7 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr overrideError( _overriding, _super, + 4593_error, "Overriding an implemented function with an unimplemented function is not allowed." ); } @@ -577,6 +581,7 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr void OverrideChecker::overrideListError( OverrideProxy const& _item, set _secondary, + ErrorId _error, string const& _message1, string const& _message2 ) @@ -594,7 +599,7 @@ void OverrideChecker::overrideListError( contractSingularPlural = "contracts "; m_errorReporter.typeError( - 5883_error, + _error, _item.overrides() ? _item.overrides()->location() : _item.location(), ssl, _message1 + @@ -605,10 +610,10 @@ void OverrideChecker::overrideListError( ); } -void OverrideChecker::overrideError(Declaration const& _overriding, Declaration const& _super, string const& _message, string const& _secondaryMsg) +void OverrideChecker::overrideError(Declaration const& _overriding, Declaration const& _super, ErrorId _error, string const& _message, string const& _secondaryMsg) { m_errorReporter.typeError( - 9456_error, + _error, _overriding.location(), SecondarySourceLocation().append(_secondaryMsg, _super.location()), _message @@ -616,10 +621,10 @@ void OverrideChecker::overrideError(Declaration const& _overriding, Declaration } -void OverrideChecker::overrideError(OverrideProxy const& _overriding, OverrideProxy const& _super, string const& _message, string const& _secondaryMsg) +void OverrideChecker::overrideError(OverrideProxy const& _overriding, OverrideProxy const& _super, ErrorId _error, string const& _message, string const& _secondaryMsg) { m_errorReporter.typeError( - 1452_error, + _error, _overriding.location(), SecondarySourceLocation().append(_secondaryMsg, _super.location()), _message @@ -773,11 +778,11 @@ void OverrideChecker::checkOverrideList(OverrideProxy _item, OverrideProxyBySign 4520_error, list[i]->location(), ssl, - "Duplicate contract \"" + - joinHumanReadable(list[i]->namePath(), ".") + - "\" found in override list of \"" + - _item.name() + - "\"." + "Duplicate contract \"" + + joinHumanReadable(list[i]->namePath(), ".") + + "\" found in override list of \"" + + _item.name() + + "\"." ); } } @@ -810,6 +815,7 @@ void OverrideChecker::checkOverrideList(OverrideProxy _item, OverrideProxyBySign overrideListError( _item, missingContracts, + 4327_error, _item.astNodeNameCapitalized() + " needs to specify overridden ", "" ); @@ -819,6 +825,7 @@ void OverrideChecker::checkOverrideList(OverrideProxy _item, OverrideProxyBySign overrideListError( _item, surplusContracts, + 2353_error, "Invalid ", "specified in override list: " ); diff --git a/libsolidity/analysis/OverrideChecker.h b/libsolidity/analysis/OverrideChecker.h index 9d7776028..d47b89f3d 100644 --- a/libsolidity/analysis/OverrideChecker.h +++ b/libsolidity/analysis/OverrideChecker.h @@ -32,6 +32,7 @@ namespace solidity::langutil { class ErrorReporter; +struct ErrorId; struct SourceLocation; } @@ -160,18 +161,21 @@ private: void overrideListError( OverrideProxy const& _item, std::set _secondary, + langutil::ErrorId _error, std::string const& _message1, std::string const& _message2 ); void overrideError( Declaration const& _overriding, Declaration const& _super, + langutil::ErrorId _error, std::string const& _message, std::string const& _secondaryMsg = "Overridden function is here:" ); void overrideError( OverrideProxy const& _overriding, OverrideProxy const& _super, + langutil::ErrorId _error, std::string const& _message, std::string const& _secondaryMsg = "Overridden function is here:" ); From bf7ab8d27731a497884a9b9e6477d1a958ff25c7 Mon Sep 17 00:00:00 2001 From: Harikrishnan Mulackal Date: Tue, 12 May 2020 13:00:29 +0530 Subject: [PATCH 68/89] Error ids only walk into a given set of directories --- scripts/correct_error_ids.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/scripts/correct_error_ids.py b/scripts/correct_error_ids.py index 8717dbf23..9fd3547f0 100644 --- a/scripts/correct_error_ids.py +++ b/scripts/correct_error_ids.py @@ -104,16 +104,14 @@ def find_source_files(top_dir): """Builds the list of .h and .cpp files in top_dir directory""" source_file_names = [] - black_set = { ".circleci", ".git", ".github", "build", "cmake", "CMakeFiles", "deps", "docs" } + dirs = ['libevmasm', 'liblangutil', 'libsolc', 'libsolidity', 'libsolutil', 'libyul', 'solc'] - for root, _, file_names in os.walk(top_dir, onerror=lambda e: exit(f"Walk error: {e}")): - path_elements = set(root.split(os.sep)) - if not black_set.isdisjoint(path_elements): - continue - for file_name in file_names: - _, ext = path.splitext(file_name) - if ext in [".h", ".cpp"]: - source_file_names.append(path.join(root, file_name)) + for dir in dirs: + for root, _, file_names in os.walk(os.path.join(top_dir, dir), onerror=lambda e: exit(f"Walk error: {e}")): + for file_name in file_names: + _, ext = path.splitext(file_name) + if ext in [".h", ".cpp"]: + source_file_names.append(path.join(root, file_name)) return source_file_names From 7cae074b8aa8a4098e51047d4d88a83224b10818 Mon Sep 17 00:00:00 2001 From: a3d4 Date: Tue, 12 May 2020 02:29:54 +0200 Subject: [PATCH 69/89] Add error IDs to BMC --- libsolidity/formal/BMC.cpp | 40 +++++++++++++++++++++++--------------- libsolidity/formal/BMC.h | 9 +++++---- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/libsolidity/formal/BMC.cpp b/libsolidity/formal/BMC.cpp index e8fc331fa..952eb1c50 100644 --- a/libsolidity/formal/BMC.cpp +++ b/libsolidity/formal/BMC.cpp @@ -21,8 +21,6 @@ #include #include -#include - using namespace std; using namespace solidity; using namespace solidity::util; @@ -594,8 +592,7 @@ void BMC::checkConstantCondition(BMCVerificationTarget& _target) *_target.expression, _target.constraints, _target.value, - _target.callStack, - "Condition is always $VALUE." + _target.callStack ); } @@ -613,6 +610,8 @@ void BMC::checkUnderflow(BMCVerificationTarget& _target, smt::Expression const& _target.callStack, _target.modelExpressions, _target.expression->location(), + 4144_error, + 8312_error, "Underflow (resulting value less than " + formatNumberReadable(intType->minValue()) + ")", "", &_target.value @@ -633,6 +632,8 @@ void BMC::checkOverflow(BMCVerificationTarget& _target, smt::Expression const& _ _target.callStack, _target.modelExpressions, _target.expression->location(), + 2661_error, + 8065_error, "Overflow (resulting value larger than " + formatNumberReadable(intType->maxValue()) + ")", "", &_target.value @@ -647,6 +648,8 @@ void BMC::checkDivByZero(BMCVerificationTarget& _target) _target.callStack, _target.modelExpressions, _target.expression->location(), + 3046_error, + 5272_error, "Division by zero", "", &_target.value @@ -661,6 +664,8 @@ void BMC::checkBalance(BMCVerificationTarget& _target) _target.callStack, _target.modelExpressions, _target.expression->location(), + 1236_error, + 4010_error, "Insufficient funds", "address(this).balance" ); @@ -675,6 +680,8 @@ void BMC::checkAssert(BMCVerificationTarget& _target) _target.callStack, _target.modelExpressions, _target.expression->location(), + 4661_error, + 7812_error, "Assertion violation" ); } @@ -705,9 +712,11 @@ void BMC::addVerificationTarget( void BMC::checkCondition( smt::Expression _condition, - vector const& callStack, + vector const& _callStack, pair, vector> const& _modelExpressions, SourceLocation const& _location, + ErrorId _errorHappens, + ErrorId _errorMightHappen, string const& _description, string const& _additionalValueName, smt::Expression const* _additionalValue @@ -719,7 +728,7 @@ void BMC::checkCondition( vector expressionsToEvaluate; vector expressionNames; tie(expressionsToEvaluate, expressionNames) = _modelExpressions; - if (callStack.size()) + if (_callStack.size()) if (_additionalValue) { expressionsToEvaluate.emplace_back(*_additionalValue); @@ -750,7 +759,7 @@ void BMC::checkCondition( { std::ostringstream message; message << _description << " happens here"; - if (callStack.size()) + if (_callStack.size()) { std::ostringstream modelMessage; modelMessage << " for:\n"; @@ -763,11 +772,11 @@ void BMC::checkCondition( for (auto const& eval: sortedModel) modelMessage << " " << eval.first << " = " << eval.second << "\n"; m_errorReporter.warning( - 4334_error, + _errorHappens, _location, message.str(), SecondarySourceLocation().append(modelMessage.str(), SourceLocation{}) - .append(SMTEncoder::callStackMessage(callStack)) + .append(SMTEncoder::callStackMessage(_callStack)) .append(move(secondaryLocation)) ); } @@ -781,7 +790,7 @@ void BMC::checkCondition( case smt::CheckResult::UNSATISFIABLE: break; case smt::CheckResult::UNKNOWN: - m_errorReporter.warning(5225_error, _location, _description + " might happen here.", secondaryLocation); + m_errorReporter.warning(_errorMightHappen, _location, _description + " might happen here.", secondaryLocation); break; case smt::CheckResult::CONFLICTING: m_errorReporter.warning(1584_error, _location, "At least two SMT solvers provided conflicting answers. Results might not be sound."); @@ -798,8 +807,7 @@ void BMC::checkBooleanNotConstant( Expression const& _condition, smt::Expression const& _constraints, smt::Expression const& _value, - vector const& _callStack, - string const& _description + vector const& _callStack ) { // Do not check for const-ness if this is a constant. @@ -832,22 +840,22 @@ void BMC::checkBooleanNotConstant( m_errorReporter.warning(2512_error, _condition.location(), "Condition unreachable.", SMTEncoder::callStackMessage(_callStack)); else { - string value; + string description; if (positiveResult == smt::CheckResult::SATISFIABLE) { solAssert(negatedResult == smt::CheckResult::UNSATISFIABLE, ""); - value = "true"; + description = "Condition is always true."; } else { solAssert(positiveResult == smt::CheckResult::UNSATISFIABLE, ""); solAssert(negatedResult == smt::CheckResult::SATISFIABLE, ""); - value = "false"; + description = "Condition is always false."; } m_errorReporter.warning( 6838_error, _condition.location(), - boost::algorithm::replace_all_copy(_description, "$VALUE", value), + description, SMTEncoder::callStackMessage(_callStack) ); } diff --git a/libsolidity/formal/BMC.h b/libsolidity/formal/BMC.h index f4b427ede..8b30f073d 100644 --- a/libsolidity/formal/BMC.h +++ b/libsolidity/formal/BMC.h @@ -44,6 +44,7 @@ using solidity::util::h256; namespace solidity::langutil { class ErrorReporter; +struct ErrorId; struct SourceLocation; } @@ -144,22 +145,22 @@ private: /// Check that a condition can be satisfied. void checkCondition( smt::Expression _condition, - std::vector const& callStack, + std::vector const& _callStack, std::pair, std::vector> const& _modelExpressions, langutil::SourceLocation const& _location, + langutil::ErrorId _errorHappens, + langutil::ErrorId _errorMightHappen, std::string const& _description, std::string const& _additionalValueName = "", smt::Expression const* _additionalValue = nullptr ); /// Checks that a boolean condition is not constant. Do not warn if the expression /// is a literal constant. - /// @param _description the warning string, $VALUE will be replaced by the constant value. void checkBooleanNotConstant( Expression const& _condition, smt::Expression const& _constraints, smt::Expression const& _value, - std::vector const& _callStack, - std::string const& _description + std::vector const& _callStack ); std::pair> checkSatisfiableAndGenerateModel(std::vector const& _expressionsToEvaluate); From 02eee54f38e0abafc7b86df7ba9c626398ba1914 Mon Sep 17 00:00:00 2001 From: a3d4 Date: Tue, 12 May 2020 11:42:29 +0200 Subject: [PATCH 70/89] Add error IDs to ContractLevelChecker --- libsolidity/analysis/ContractLevelChecker.cpp | 31 +++++++++++++------ libsolidity/analysis/ContractLevelChecker.h | 2 +- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/libsolidity/analysis/ContractLevelChecker.cpp b/libsolidity/analysis/ContractLevelChecker.cpp index 1cff26c26..cb8694537 100644 --- a/libsolidity/analysis/ContractLevelChecker.cpp +++ b/libsolidity/analysis/ContractLevelChecker.cpp @@ -112,7 +112,7 @@ void ContractLevelChecker::checkDuplicateFunctions(ContractDefinition const& _co functions[function->name()].push_back(function); } - findDuplicateDefinitions(functions, "Function with same name and arguments defined twice."); + findDuplicateDefinitions(functions); } void ContractLevelChecker::checkDuplicateEvents(ContractDefinition const& _contract) @@ -123,11 +123,11 @@ void ContractLevelChecker::checkDuplicateEvents(ContractDefinition const& _contr for (EventDefinition const* event: _contract.events()) events[event->name()].push_back(event); - findDuplicateDefinitions(events, "Event with same name and arguments defined twice."); + findDuplicateDefinitions(events); } template -void ContractLevelChecker::findDuplicateDefinitions(map> const& _definitions, string _message) +void ContractLevelChecker::findDuplicateDefinitions(map> const& _definitions) { for (auto const& it: _definitions) { @@ -146,13 +146,27 @@ void ContractLevelChecker::findDuplicateDefinitions(map> const if (ssl.infos.size() > 0) { - ssl.limitSize(_message); + ErrorId error; + string message; + if constexpr (is_same_v) + { + error = 1686_error; + message = "Function with same name and arguments defined twice."; + } + else + { + static_assert(is_same_v, "Expected \"FunctionDefinition const*\" or \"EventDefinition const*\""); + error = 5883_error; + message = "Event with same name and arguments defined twice."; + } + + ssl.limitSize(message); m_errorReporter.declarationError( - 1686_error, + error, overloads[i]->location(), ssl, - _message + message ); } } @@ -222,9 +236,8 @@ void ContractLevelChecker::checkAbstractDefinitions(ContractDefinition const& _c 3656_error, _contract.location(), ssl, - "Contract \"" + _contract.annotation().canonicalName - + "\" should be marked as abstract."); - + "Contract \"" + _contract.annotation().canonicalName + "\" should be marked as abstract." + ); } } diff --git a/libsolidity/analysis/ContractLevelChecker.h b/libsolidity/analysis/ContractLevelChecker.h index 736b3d3d7..e40cb8b0d 100644 --- a/libsolidity/analysis/ContractLevelChecker.h +++ b/libsolidity/analysis/ContractLevelChecker.h @@ -60,7 +60,7 @@ private: void checkDuplicateFunctions(ContractDefinition const& _contract); void checkDuplicateEvents(ContractDefinition const& _contract); template - void findDuplicateDefinitions(std::map> const& _definitions, std::string _message); + void findDuplicateDefinitions(std::map> const& _definitions); /// Checks for unimplemented functions and modifiers. void checkAbstractDefinitions(ContractDefinition const& _contract); /// Checks that the base constructor arguments are properly provided. From c29d76f8f22cc36808bf986d497b48589726020e Mon Sep 17 00:00:00 2001 From: Harikrishnan Mulackal Date: Tue, 12 May 2020 15:21:13 +0530 Subject: [PATCH 71/89] Test for function with value setting --- .../syntaxTests/conversion/function_cast_value_set.sol | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 test/libsolidity/syntaxTests/conversion/function_cast_value_set.sol diff --git a/test/libsolidity/syntaxTests/conversion/function_cast_value_set.sol b/test/libsolidity/syntaxTests/conversion/function_cast_value_set.sol new file mode 100644 index 000000000..163724d35 --- /dev/null +++ b/test/libsolidity/syntaxTests/conversion/function_cast_value_set.sol @@ -0,0 +1,7 @@ +contract C { + function f() public payable { + function() external payable x = this.f{value: 7}; + } +} +// ---- +// TypeError: (46-94): Type function () payable external is not implicitly convertible to expected type function () payable external. From 095e17f7f922e2b029884ab5584cbdfe7bfdd952 Mon Sep 17 00:00:00 2001 From: Harikrishnan Mulackal Date: Tue, 12 May 2020 19:00:42 +0530 Subject: [PATCH 72/89] Bug that ignored return tag when no other devdoc tags were present --- Changelog.md | 2 +- libsolidity/interface/Natspec.cpp | 14 ++++++-------- test/libsolidity/SolidityNatspecJSON.cpp | 21 +++++++++++++++++++++ 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/Changelog.md b/Changelog.md index 7c613ff1f..338eb5631 100644 --- a/Changelog.md +++ b/Changelog.md @@ -17,7 +17,7 @@ Bugfixes: * ABI: Skip ``private`` or ``internal`` constructors. * Type Checker: Disallow accessing ``runtimeCode`` for contract types that contain immutable state variables. * Fixed an "Assembly Exception in Bytecode" error where requested functions were generated twice. - + * Natspec: Fixed a bug that ignored ``@return`` tag when no other developer-documentation tags were present. ### 0.6.7 (2020-05-04) diff --git a/libsolidity/interface/Natspec.cpp b/libsolidity/interface/Natspec.cpp index b78e46081..5e51696ec 100644 --- a/libsolidity/interface/Natspec.cpp +++ b/libsolidity/interface/Natspec.cpp @@ -99,16 +99,14 @@ Json::Value Natspec::devDocumentation(ContractDefinition const& _contractDef) if (auto fun = dynamic_cast(&it.second->declaration())) { Json::Value method(devDocumentation(fun->annotation().docTags)); + // add the function, only if we have any documentation to add + Json::Value jsonReturn = extractReturnParameterDocs(fun->annotation().docTags, *fun); + + if (!jsonReturn.empty()) + method["returns"] = jsonReturn; + if (!method.empty()) - { - // add the function, only if we have any documentation to add - Json::Value jsonReturn = extractReturnParameterDocs(fun->annotation().docTags, *fun); - - if (!jsonReturn.empty()) - method["returns"] = jsonReturn; - methods[it.second->externalSignature()] = method; - } } } diff --git a/test/libsolidity/SolidityNatspecJSON.cpp b/test/libsolidity/SolidityNatspecJSON.cpp index 13bd1f3b0..69ae832ad 100644 --- a/test/libsolidity/SolidityNatspecJSON.cpp +++ b/test/libsolidity/SolidityNatspecJSON.cpp @@ -355,6 +355,27 @@ BOOST_AUTO_TEST_CASE(dev_multiple_functions) checkNatspec(sourceCode, "test", natspec, false); } +BOOST_AUTO_TEST_CASE(dev_return_no_params) +{ + char const* sourceCode = R"( + contract test { + /// @return d The result of the multiplication + function mul(uint a, uint second) public returns (uint d) { return a * 7 + second; } + } + )"; + + char const* natspec = R"ABCDEF( + { + "methods": { + "mul(uint256,uint256)": { + "returns": { "d": "The result of the multiplication" + } + } + })ABCDEF"; + + checkNatspec(sourceCode, "test", natspec, false); +} + BOOST_AUTO_TEST_CASE(dev_return) { char const* sourceCode = R"( From 7da453014dd3c0ae14abd9ba89a974e20a9f17c9 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 5 May 2020 01:03:41 +0200 Subject: [PATCH 73/89] Fix source location of yul variable declarations without value. --- Changelog.md | 1 + libyul/backends/evm/EVMCodeTransform.cpp | 4 ++-- test/cmdlineTests/optimizer_user_yul/output | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Changelog.md b/Changelog.md index 338eb5631..996904b27 100644 --- a/Changelog.md +++ b/Changelog.md @@ -18,6 +18,7 @@ Bugfixes: * Type Checker: Disallow accessing ``runtimeCode`` for contract types that contain immutable state variables. * Fixed an "Assembly Exception in Bytecode" error where requested functions were generated twice. * Natspec: Fixed a bug that ignored ``@return`` tag when no other developer-documentation tags were present. + * Yul assembler: Fix source location of variable declarations without value. ### 0.6.7 (2020-05-04) diff --git a/libyul/backends/evm/EVMCodeTransform.cpp b/libyul/backends/evm/EVMCodeTransform.cpp index 9e8d4d662..a4e19998f 100644 --- a/libyul/backends/evm/EVMCodeTransform.cpp +++ b/libyul/backends/evm/EVMCodeTransform.cpp @@ -184,11 +184,13 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl) } else { + m_assembly.setSourceLocation(_varDecl.location); int variablesLeft = numVariables; while (variablesLeft--) m_assembly.appendConstant(u256(0)); } + m_assembly.setSourceLocation(_varDecl.location); bool atTopOfStack = true; for (int varIndex = numVariables - 1; varIndex >= 0; --varIndex) { @@ -203,7 +205,6 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl) if (atTopOfStack) { m_context->variableStackHeights.erase(&var); - m_assembly.setSourceLocation(_varDecl.location); m_assembly.appendInstruction(evmasm::Instruction::POP); } else @@ -216,7 +217,6 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl) int slot = *m_unusedStackSlots.begin(); m_unusedStackSlots.erase(m_unusedStackSlots.begin()); m_context->variableStackHeights[&var] = slot; - m_assembly.setSourceLocation(_varDecl.location); if (int heightDiff = variableHeightDiff(var, varName, true)) m_assembly.appendInstruction(evmasm::swapInstruction(heightDiff - 1)); m_assembly.appendInstruction(evmasm::Instruction::POP); diff --git a/test/cmdlineTests/optimizer_user_yul/output b/test/cmdlineTests/optimizer_user_yul/output index b95f2e0fa..8eef7b4f6 100644 --- a/test/cmdlineTests/optimizer_user_yul/output +++ b/test/cmdlineTests/optimizer_user_yul/output @@ -5,7 +5,7 @@ EVM assembly: mstore(0x40, 0x80) /* "optimizer_user_yul/input.sol":72:77 int a */ 0x00 - /* "optimizer_user_yul/input.sol":38:487 constructor() public payable... */ + /* "optimizer_user_yul/input.sol":152:161 let x,y,z */ dup1 0x00 dup1 From 02d1f8c41aa4d9d36a002d12f3ced24ac21bdb85 Mon Sep 17 00:00:00 2001 From: a3d4 Date: Tue, 12 May 2020 18:13:17 +0200 Subject: [PATCH 74/89] Remove a dedicated error flag from DeclarationTypeChecker --- liblangutil/ErrorReporter.h | 6 ++++++ libsolidity/analysis/DeclarationTypeChecker.cpp | 6 ++---- libsolidity/analysis/DeclarationTypeChecker.h | 1 - .../nameAndTypeResolution/105_constant_input_parameter.sol | 2 -- .../syntaxTests/parsing/location_specifiers_for_params.sol | 2 -- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/liblangutil/ErrorReporter.h b/liblangutil/ErrorReporter.h index 466bb66cb..a52e978af 100644 --- a/liblangutil/ErrorReporter.h +++ b/liblangutil/ErrorReporter.h @@ -134,6 +134,12 @@ public: return m_errorCount > 0; } + /// @returns the number of errors (ignores warnings). + unsigned errorCount() const + { + return m_errorCount; + } + // @returns true if the maximum error count has been reached. bool hasExcessiveErrors() const; diff --git a/libsolidity/analysis/DeclarationTypeChecker.cpp b/libsolidity/analysis/DeclarationTypeChecker.cpp index 4e55151e9..a06679b97 100644 --- a/libsolidity/analysis/DeclarationTypeChecker.cpp +++ b/libsolidity/analysis/DeclarationTypeChecker.cpp @@ -361,24 +361,22 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable) void DeclarationTypeChecker::typeError(SourceLocation const& _location, string const& _description) { - m_errorOccurred = true; m_errorReporter.typeError(2311_error, _location, _description); } void DeclarationTypeChecker::fatalTypeError(SourceLocation const& _location, string const& _description) { - m_errorOccurred = true; m_errorReporter.fatalTypeError(5651_error, _location, _description); } void DeclarationTypeChecker::fatalDeclarationError(SourceLocation const& _location, string const& _description) { - m_errorOccurred = true; m_errorReporter.fatalDeclarationError(2046_error, _location, _description); } bool DeclarationTypeChecker::check(ASTNode const& _node) { + unsigned errorCount = m_errorReporter.errorCount(); _node.accept(*this); - return !m_errorOccurred; + return m_errorReporter.errorCount() == errorCount; } diff --git a/libsolidity/analysis/DeclarationTypeChecker.h b/libsolidity/analysis/DeclarationTypeChecker.h index b704c4fd2..e54075998 100644 --- a/libsolidity/analysis/DeclarationTypeChecker.h +++ b/libsolidity/analysis/DeclarationTypeChecker.h @@ -69,7 +69,6 @@ private: void fatalDeclarationError(langutil::SourceLocation const& _location, std::string const& _description); langutil::ErrorReporter& m_errorReporter; - bool m_errorOccurred = false; langutil::EVMVersion m_evmVersion; bool m_insideFunctionType = false; bool m_recursiveStructSeen = false; diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/105_constant_input_parameter.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/105_constant_input_parameter.sol index ba05fcb31..aab8a183a 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/105_constant_input_parameter.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/105_constant_input_parameter.sol @@ -3,5 +3,3 @@ contract test { } // ---- // DeclarationError: (31-55): The "constant" keyword can only be used for state variables. -// TypeError: (31-55): Constants of non-value type not yet implemented. -// TypeError: (31-55): Uninitialized "constant" variable. diff --git a/test/libsolidity/syntaxTests/parsing/location_specifiers_for_params.sol b/test/libsolidity/syntaxTests/parsing/location_specifiers_for_params.sol index bf78e59c6..b9b1f97cd 100644 --- a/test/libsolidity/syntaxTests/parsing/location_specifiers_for_params.sol +++ b/test/libsolidity/syntaxTests/parsing/location_specifiers_for_params.sol @@ -3,5 +3,3 @@ contract Foo { } // ---- // DeclarationError: (30-55): The "constant" keyword can only be used for state variables. -// TypeError: (30-55): Constants of non-value type not yet implemented. -// TypeError: (30-55): Uninitialized "constant" variable. From 47e9a13e8afc504d034119eac3edec6deb2f8a52 Mon Sep 17 00:00:00 2001 From: Harikrishnan Mulackal Date: Tue, 12 May 2020 12:36:21 +0530 Subject: [PATCH 75/89] Fix exponentiation bug --- Changelog.md | 1 + libsolidity/ast/Types.cpp | 7 +++++++ .../syntaxTests/literalOperations/exponent.sol | 10 ++++++++++ .../syntaxTests/literalOperations/exponent_fine.sol | 7 +++++++ 4 files changed, 25 insertions(+) create mode 100644 test/libsolidity/syntaxTests/literalOperations/exponent.sol create mode 100644 test/libsolidity/syntaxTests/literalOperations/exponent_fine.sol diff --git a/Changelog.md b/Changelog.md index 996904b27..8709aa947 100644 --- a/Changelog.md +++ b/Changelog.md @@ -19,6 +19,7 @@ Bugfixes: * Fixed an "Assembly Exception in Bytecode" error where requested functions were generated twice. * Natspec: Fixed a bug that ignored ``@return`` tag when no other developer-documentation tags were present. * Yul assembler: Fix source location of variable declarations without value. + * Type checker: Checks if a literal exponent in the ``**`` operation is too large or fractional. ### 0.6.7 (2020-05-04) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index aa888d26b..c9d40a1ce 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -613,6 +613,13 @@ TypeResult IntegerType::binaryOperatorResult(Token _operator, Type const* _other } else if (dynamic_cast(_other)) return nullptr; + else if (auto rationalNumberType = dynamic_cast(_other)) + { + if (rationalNumberType->isFractional()) + return TypeResult::err("Exponent is fractional."); + if (!rationalNumberType->integerType()) + return TypeResult::err("Exponent too large."); + } return this; } diff --git a/test/libsolidity/syntaxTests/literalOperations/exponent.sol b/test/libsolidity/syntaxTests/literalOperations/exponent.sol new file mode 100644 index 000000000..cee6263b7 --- /dev/null +++ b/test/libsolidity/syntaxTests/literalOperations/exponent.sol @@ -0,0 +1,10 @@ +contract C { + function g() public pure { + int a; + a ** 1E1233; + a ** (1/2); + } +} +// ---- +// TypeError: (67-78): Operator ** not compatible with types int256 and int_const 1000...(1226 digits omitted)...0000. Exponent too large. +// TypeError: (88-98): Operator ** not compatible with types int256 and rational_const 1 / 2. Exponent is fractional. diff --git a/test/libsolidity/syntaxTests/literalOperations/exponent_fine.sol b/test/libsolidity/syntaxTests/literalOperations/exponent_fine.sol new file mode 100644 index 000000000..56fed09ae --- /dev/null +++ b/test/libsolidity/syntaxTests/literalOperations/exponent_fine.sol @@ -0,0 +1,7 @@ +contract C { + function f() public pure { + uint a; + a = a ** 1E5; + a = 0 ** 1E1233; + } +} From 6f04664cfa1d64c00a30760b643e1c17fcc44514 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 13 May 2020 11:00:47 +0200 Subject: [PATCH 76/89] Disallow array slicing for arrays with dyanmically encoded base types. --- Changelog.md | 1 + docs/bugs.json | 11 +++++++++++ docs/bugs_by_version.json | 8 ++++++++ libsolidity/analysis/TypeChecker.cpp | 2 ++ libsolidity/codegen/CompilerUtils.cpp | 3 ++- libsolidity/codegen/ExpressionCompiler.cpp | 14 ++++++++++++-- libsolidity/codegen/YulUtilFunctions.cpp | 1 + .../syntaxTests/parsing/array_range_nested.sol | 5 ++--- .../parsing/array_range_nested_invalid.sol | 14 ++++++++++++++ 9 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 test/libsolidity/syntaxTests/parsing/array_range_nested_invalid.sol diff --git a/Changelog.md b/Changelog.md index 996904b27..25b457873 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,7 @@ Important Bugfixes: * Add missing callvalue check to the creation code of a contract that does not define a constructor but has a base that does define a constructor. + * Disallow index range accesses for arrays with dynamically encoded base types. Language Features: diff --git a/docs/bugs.json b/docs/bugs.json index c251fa114..a32b27fb4 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -1,4 +1,15 @@ [ + { + "name": "ArraySliceDynamicallyEncodedBaseType", + "summary": "Accessing array slices of arrays with dynamically encoded base types (e.g. multi-dimensional arrays) can result in invalid data being read.", + "description": "For arrays with dynamically sized base types, index range accesses that use a start expression that is non-zero will result in invalid array slices. Any index access to such array slices will result in data being read from incorrect calldata offsets. Array slices are only supported for dynamic calldata types and all problematic type require ABIEncoderV2 to be enabled.", + "introduced": "0.6.0", + "fixed": "0.6.8", + "severity": "very low", + "conditions": { + "ABIEncoderV2": true + } + }, { "name": "ImplicitConstructorCallvalueCheck", "summary": "The creation code of a contract that does not define a constructor but has a base that does define a constructor did not revert for calls with non-zero value.", diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index 0398e4cd7..ac0c4b9f1 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -1082,6 +1082,7 @@ }, "0.6.0": { "bugs": [ + "ArraySliceDynamicallyEncodedBaseType", "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", @@ -1091,6 +1092,7 @@ }, "0.6.1": { "bugs": [ + "ArraySliceDynamicallyEncodedBaseType", "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow" @@ -1099,6 +1101,7 @@ }, "0.6.2": { "bugs": [ + "ArraySliceDynamicallyEncodedBaseType", "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow" @@ -1107,6 +1110,7 @@ }, "0.6.3": { "bugs": [ + "ArraySliceDynamicallyEncodedBaseType", "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow" @@ -1115,6 +1119,7 @@ }, "0.6.4": { "bugs": [ + "ArraySliceDynamicallyEncodedBaseType", "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow" @@ -1123,6 +1128,7 @@ }, "0.6.5": { "bugs": [ + "ArraySliceDynamicallyEncodedBaseType", "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents" ], @@ -1130,12 +1136,14 @@ }, "0.6.6": { "bugs": [ + "ArraySliceDynamicallyEncodedBaseType", "ImplicitConstructorCallvalueCheck" ], "released": "2020-04-09" }, "0.6.7": { "bugs": [ + "ArraySliceDynamicallyEncodedBaseType", "ImplicitConstructorCallvalueCheck" ], "released": "2020-05-04" diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 380879c73..ebb7bf6e6 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -2864,6 +2864,8 @@ bool TypeChecker::visit(IndexRangeAccess const& _access) if (arrayType->location() != DataLocation::CallData || !arrayType->isDynamicallySized()) m_errorReporter.typeError(1227_error, _access.location(), "Index range access is only supported for dynamic calldata arrays."); + else if (arrayType->baseType()->isDynamicallyEncoded()) + m_errorReporter.typeError(1878_error, _access.location(), "Index range access is not supported for arrays with dynamically encoded base types."); _access.annotation().type = TypeProvider::arraySlice(*arrayType); _access.annotation().isLValue = isLValue; _access.annotation().isPure = isPure; diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 156cee565..feae52caa 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -990,7 +990,8 @@ void CompilerUtils::convertType( solAssert(_targetType == typeOnStack.arrayType(), ""); solUnimplementedAssert( typeOnStack.arrayType().location() == DataLocation::CallData && - typeOnStack.arrayType().isDynamicallySized(), + typeOnStack.arrayType().isDynamicallySized() && + !typeOnStack.arrayType().baseType()->isDynamicallyEncoded(), "" ); break; diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 7b07cc48a..f05ffda8f 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1769,7 +1769,12 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) case Type::Category::ArraySlice: { auto const& arrayType = dynamic_cast(baseType).arrayType(); - solAssert(arrayType.location() == DataLocation::CallData && arrayType.isDynamicallySized(), ""); + solAssert( + arrayType.location() == DataLocation::CallData && + arrayType.isDynamicallySized() && + !arrayType.baseType()->isDynamicallyEncoded(), + "" + ); solAssert(_indexAccess.indexExpression(), "Index expression expected."); acceptAndConvert(*_indexAccess.indexExpression(), *TypeProvider::uint256(), true); @@ -1852,7 +1857,12 @@ bool ExpressionCompiler::visit(IndexRangeAccess const& _indexAccess) arrayType = &sliceType->arrayType(); solAssert(arrayType, ""); - solUnimplementedAssert(arrayType->location() == DataLocation::CallData && arrayType->isDynamicallySized(), ""); + solUnimplementedAssert( + arrayType->location() == DataLocation::CallData && + arrayType->isDynamicallySized() && + !arrayType->baseType()->isDynamicallyEncoded(), + "" + ); if (_indexAccess.startExpression()) acceptAndConvert(*_indexAccess.startExpression(), *TypeProvider::uint256()); diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index f7bb31447..4fd681e1f 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -1599,6 +1599,7 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) ArraySliceType const& fromType = dynamic_cast(_from); ArrayType const& targetType = dynamic_cast(_to); + solAssert(!fromType.arrayType().baseType()->isDynamicallyEncoded(), ""); solAssert( *fromType.arrayType().baseType() == *targetType.baseType(), "Converting arrays of different type is not possible" diff --git a/test/libsolidity/syntaxTests/parsing/array_range_nested.sol b/test/libsolidity/syntaxTests/parsing/array_range_nested.sol index 847d7596d..16fde7999 100644 --- a/test/libsolidity/syntaxTests/parsing/array_range_nested.sol +++ b/test/libsolidity/syntaxTests/parsing/array_range_nested.sol @@ -2,9 +2,8 @@ pragma experimental ABIEncoderV2; contract C { function f(uint256[][] calldata x) external pure { x[0][1:2]; - x[1:2][1:2]; - uint256 a = x[1:2][1:2][1:][3:][0][2]; - uint256 b = x[1:][3:4][1][1:][2:3][0]; + uint256 a = x[0][1:2][1:2][1:][3:][0]; + uint256 b = x[1][1:][3:4][1:][2:3][0]; a; b; } } diff --git a/test/libsolidity/syntaxTests/parsing/array_range_nested_invalid.sol b/test/libsolidity/syntaxTests/parsing/array_range_nested_invalid.sol new file mode 100644 index 000000000..bc53d3faf --- /dev/null +++ b/test/libsolidity/syntaxTests/parsing/array_range_nested_invalid.sol @@ -0,0 +1,14 @@ +pragma experimental ABIEncoderV2; +contract C { + function f(uint256[][] calldata x) external pure { + x[1:2]; + x[:]; + x[1:]; + x[:2]; + } +} +// ---- +// TypeError: (110-116): Index range access is not supported for arrays with dynamically encoded base types. +// TypeError: (126-130): Index range access is not supported for arrays with dynamically encoded base types. +// TypeError: (140-145): Index range access is not supported for arrays with dynamically encoded base types. +// TypeError: (155-160): Index range access is not supported for arrays with dynamically encoded base types. From 820fdd9bf70a74af470d0f841d9fdfe8f3521a28 Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Thu, 7 May 2020 19:19:54 +0200 Subject: [PATCH 77/89] Escape backslashes when formatting --- Changelog.md | 1 + docs/bugs.json | 11 ++++++ docs/bugs_by_version.json | 12 +++++++ libsolutil/CommonData.cpp | 36 ++++++++++++++++++- libsolutil/CommonData.h | 4 +++ libyul/AsmPrinter.cpp | 28 +-------------- .../semanticTests/literals/escape.sol | 13 +++++++ 7 files changed, 77 insertions(+), 28 deletions(-) create mode 100644 test/libsolidity/semanticTests/literals/escape.sol diff --git a/Changelog.md b/Changelog.md index 8d7ff006a..10d6b3fc3 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,6 +3,7 @@ Important Bugfixes: * Add missing callvalue check to the creation code of a contract that does not define a constructor but has a base that does define a constructor. * Disallow index range accesses for arrays with dynamically encoded base types. + * Code Generator: Fixed that string literals containing backslash characters could cause incorrect code to be generated when passed directly to function calls or encoding functions when ABIEncoderV2 is active. Language Features: diff --git a/docs/bugs.json b/docs/bugs.json index a32b27fb4..90f211c1f 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -1,4 +1,15 @@ [ + { + "name": "MissingEscapingInFormatting", + "summary": "String literals containing double backslash characters passed directly to external or encoding function calls can lead to a different string being used when ABIEncoderV2 is enabled.", + "description": "When ABIEncoderV2 is enabled, string literals passed directly to encoding functions or external function calls are stored as strings in the intemediate code. Characters outside the printable range are handled correctly, but backslashes are not escaped in this procedure. This leads to double backslashes being reduced to single backslashes and consequently re-interpreted as escapes potentially resulting in a different string being encoded.", + "introduced": "0.5.14", + "fixed": "0.6.8", + "severity": "very low", + "conditions": { + "ABIEncoderV2": true + } + }, { "name": "ArraySliceDynamicallyEncodedBaseType", "summary": "Accessing array slices of arrays with dynamically encoded base types (e.g. multi-dimensional arrays) can result in invalid data being read.", diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index ac0c4b9f1..0f96fb509 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -923,6 +923,7 @@ }, "0.5.14": { "bugs": [ + "MissingEscapingInFormatting", "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", @@ -934,6 +935,7 @@ }, "0.5.15": { "bugs": [ + "MissingEscapingInFormatting", "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", @@ -944,6 +946,7 @@ }, "0.5.16": { "bugs": [ + "MissingEscapingInFormatting", "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", @@ -953,6 +956,7 @@ }, "0.5.17": { "bugs": [ + "MissingEscapingInFormatting", "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow" @@ -1082,6 +1086,7 @@ }, "0.6.0": { "bugs": [ + "MissingEscapingInFormatting", "ArraySliceDynamicallyEncodedBaseType", "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", @@ -1092,6 +1097,7 @@ }, "0.6.1": { "bugs": [ + "MissingEscapingInFormatting", "ArraySliceDynamicallyEncodedBaseType", "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", @@ -1101,6 +1107,7 @@ }, "0.6.2": { "bugs": [ + "MissingEscapingInFormatting", "ArraySliceDynamicallyEncodedBaseType", "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", @@ -1110,6 +1117,7 @@ }, "0.6.3": { "bugs": [ + "MissingEscapingInFormatting", "ArraySliceDynamicallyEncodedBaseType", "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", @@ -1119,6 +1127,7 @@ }, "0.6.4": { "bugs": [ + "MissingEscapingInFormatting", "ArraySliceDynamicallyEncodedBaseType", "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents", @@ -1128,6 +1137,7 @@ }, "0.6.5": { "bugs": [ + "MissingEscapingInFormatting", "ArraySliceDynamicallyEncodedBaseType", "ImplicitConstructorCallvalueCheck", "TupleAssignmentMultiStackSlotComponents" @@ -1136,6 +1146,7 @@ }, "0.6.6": { "bugs": [ + "MissingEscapingInFormatting", "ArraySliceDynamicallyEncodedBaseType", "ImplicitConstructorCallvalueCheck" ], @@ -1143,6 +1154,7 @@ }, "0.6.7": { "bugs": [ + "MissingEscapingInFormatting", "ArraySliceDynamicallyEncodedBaseType", "ImplicitConstructorCallvalueCheck" ], diff --git a/libsolutil/CommonData.cpp b/libsolutil/CommonData.cpp index 2024a1b1f..bb1a7696c 100644 --- a/libsolutil/CommonData.cpp +++ b/libsolutil/CommonData.cpp @@ -188,5 +188,39 @@ string solidity::util::formatAsStringOrNumber(string const& _value) if (c <= 0x1f || c >= 0x7f || c == '"') return "0x" + h256(_value, h256::AlignLeft).hex(); - return "\"" + _value + "\""; + return escapeAndQuoteString(_value); +} + + +string solidity::util::escapeAndQuoteString(string const& _input) +{ + string out; + + for (char c: _input) + if (c == '\\') + out += "\\\\"; + else if (c == '"') + out += "\\\""; + else if (c == '\b') + out += "\\b"; + else if (c == '\f') + out += "\\f"; + else if (c == '\n') + out += "\\n"; + else if (c == '\r') + out += "\\r"; + else if (c == '\t') + out += "\\t"; + else if (c == '\v') + out += "\\v"; + else if (!isprint(c, locale::classic())) + { + ostringstream o; + o << "\\x" << std::hex << setfill('0') << setw(2) << (unsigned)(unsigned char)(c); + out += o.str(); + } + else + out += c; + + return "\"" + std::move(out) + "\""; } diff --git a/libsolutil/CommonData.h b/libsolutil/CommonData.h index bd1133511..adac1fb05 100644 --- a/libsolutil/CommonData.h +++ b/libsolutil/CommonData.h @@ -460,6 +460,10 @@ bool isValidDecimal(std::string const& _string); /// _value cannot be longer than 32 bytes. std::string formatAsStringOrNumber(std::string const& _value); +/// @returns a string with the usual backslash-escapes for non-ASCII +/// characters and surrounded by '"'-characters. +std::string escapeAndQuoteString(std::string const& _input); + template bool containerEqual(Container const& _lhs, Container const& _rhs, Compare&& _compare) { diff --git a/libyul/AsmPrinter.cpp b/libyul/AsmPrinter.cpp index 93fb089ed..97a7dc3ad 100644 --- a/libyul/AsmPrinter.cpp +++ b/libyul/AsmPrinter.cpp @@ -55,33 +55,7 @@ string AsmPrinter::operator()(Literal const& _literal) const break; } - string out; - for (char c: _literal.value.str()) - if (c == '\\') - out += "\\\\"; - else if (c == '"') - out += "\\\""; - else if (c == '\b') - out += "\\b"; - else if (c == '\f') - out += "\\f"; - else if (c == '\n') - out += "\\n"; - else if (c == '\r') - out += "\\r"; - else if (c == '\t') - out += "\\t"; - else if (c == '\v') - out += "\\v"; - else if (!isprint(c, locale::classic())) - { - ostringstream o; - o << std::hex << setfill('0') << setw(2) << (unsigned)(unsigned char)(c); - out += "\\x" + o.str(); - } - else - out += c; - return "\"" + out + "\"" + appendTypeName(_literal.type); + return escapeAndQuoteString(_literal.value.str()) + appendTypeName(_literal.type); } string AsmPrinter::operator()(Identifier const& _identifier) const diff --git a/test/libsolidity/semanticTests/literals/escape.sol b/test/libsolidity/semanticTests/literals/escape.sol new file mode 100644 index 000000000..8f015297e --- /dev/null +++ b/test/libsolidity/semanticTests/literals/escape.sol @@ -0,0 +1,13 @@ +pragma experimental ABIEncoderV2; + +contract C +{ + function f() public pure returns (uint, byte, byte) { + bytes memory encoded = abi.encodePacked("\\\\"); + return (encoded.length, encoded[0], encoded[1]); + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> 2, 0x5c00000000000000000000000000000000000000000000000000000000000000, 0x5c00000000000000000000000000000000000000000000000000000000000000 From 3872a1f000f7aa19b05b003d99a82f17c73e98ff Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 12 May 2020 11:56:28 +0200 Subject: [PATCH 78/89] Add support for SPDX license identifiers. --- liblangutil/ParserBase.cpp | 5 ++ liblangutil/ParserBase.h | 1 + libsolidity/ast/AST.h | 11 +++- libsolidity/ast/ASTJsonConverter.cpp | 1 + libsolidity/ast/ASTJsonImporter.cpp | 7 ++- libsolidity/interface/CompilerStack.cpp | 2 + libsolidity/parsing/Parser.cpp | 60 ++++++++++++++++++- libsolidity/parsing/Parser.h | 2 + test/libsolidity/ABIJsonTest.cpp | 5 +- test/libsolidity/AnalysisFramework.cpp | 8 ++- test/libsolidity/AnalysisFramework.h | 2 +- test/libsolidity/GasMeter.cpp | 3 +- test/libsolidity/GasTest.cpp | 4 +- test/libsolidity/SMTChecker.cpp | 4 +- test/libsolidity/SMTCheckerJSONTest.cpp | 12 ++-- .../SolidityNameAndTypeResolution.cpp | 1 + test/libsolidity/SolidityTypes.cpp | 2 +- test/libsolidity/StandardCompiler.cpp | 2 +- test/libsolidity/SyntaxTest.cpp | 16 ++--- 19 files changed, 119 insertions(+), 29 deletions(-) diff --git a/liblangutil/ParserBase.cpp b/liblangutil/ParserBase.cpp index f0ebefd93..be8ec3eb9 100644 --- a/liblangutil/ParserBase.cpp +++ b/liblangutil/ParserBase.cpp @@ -148,6 +148,11 @@ void ParserBase::parserWarning(ErrorId _error, string const& _description) m_errorReporter.warning(_error, currentLocation(), _description); } +void ParserBase::parserWarning(ErrorId _error, SourceLocation const& _location, string const& _description) +{ + m_errorReporter.warning(_error, _location, _description); +} + void ParserBase::parserError(ErrorId _error, SourceLocation const& _location, string const& _description) { m_errorReporter.parserError(_error, _location, _description); diff --git a/liblangutil/ParserBase.h b/liblangutil/ParserBase.h index 8a8073696..bb4123b9f 100644 --- a/liblangutil/ParserBase.h +++ b/liblangutil/ParserBase.h @@ -95,6 +95,7 @@ protected: /// Creates a @ref ParserWarning and annotates it with the current position and the /// given @a _description. void parserWarning(ErrorId _error, std::string const& _description); + void parserWarning(ErrorId _error, SourceLocation const& _location, std::string const& _description); /// Creates a @ref ParserError and annotates it with the current position and the /// given @a _description. Throws the FatalError. diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 3c79912c2..0c4e181e8 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -156,19 +156,26 @@ std::vector ASTNode::filteredNodes(std::vector> co class SourceUnit: public ASTNode { public: - SourceUnit(int64_t _id, SourceLocation const& _location, std::vector> _nodes): - ASTNode(_id, _location), m_nodes(std::move(_nodes)) {} + SourceUnit( + int64_t _id, + SourceLocation const& _location, + std::optional _licenseString, + std::vector> _nodes + ): + ASTNode(_id, _location), m_licenseString(std::move(_licenseString)), m_nodes(std::move(_nodes)) {} void accept(ASTVisitor& _visitor) override; void accept(ASTConstVisitor& _visitor) const override; SourceUnitAnnotation& annotation() const override; + std::optional const& licenseString() const { return m_licenseString; } std::vector> nodes() const { return m_nodes; } /// @returns a set of referenced SourceUnits. Recursively if @a _recurse is true. std::set referencedSourceUnits(bool _recurse = false, std::set _skipList = std::set()) const; private: + std::optional m_licenseString; std::vector> m_nodes; }; diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index 9f61184be..603781b26 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -225,6 +225,7 @@ bool ASTJsonConverter::visit(SourceUnit const& _node) { make_pair("absolutePath", _node.annotation().path), make_pair("exportedSymbols", move(exportedSymbols)), + make_pair("license", _node.licenseString() ? Json::Value(*_node.licenseString()) : Json::nullValue), make_pair("nodes", toJson(_node.nodes())) } ); diff --git a/libsolidity/ast/ASTJsonImporter.cpp b/libsolidity/ast/ASTJsonImporter.cpp index e4538059d..c0bee4c60 100644 --- a/libsolidity/ast/ASTJsonImporter.cpp +++ b/libsolidity/ast/ASTJsonImporter.cpp @@ -218,10 +218,15 @@ ASTPointer ASTJsonImporter::convertJsonToASTNode(Json::Value const& _js ASTPointer ASTJsonImporter::createSourceUnit(Json::Value const& _node, string const& _srcName) { + optional license; + if (_node.isMember("license") && !_node["license"].isNull()) + license = _node["license"].asString(); + vector> nodes; for (auto& child: member(_node, "nodes")) nodes.emplace_back(convertJsonToASTNode(child)); - ASTPointer tmp = createASTNode(_node, nodes); + + ASTPointer tmp = createASTNode(_node, license, nodes); tmp->annotation().path = _srcName; return tmp; } diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index da561050b..e50d8990a 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -1236,6 +1236,8 @@ string CompilerStack::createMetadata(Contract const& _contract) const solAssert(s.second.scanner, "Scanner not available"); meta["sources"][s.first]["keccak256"] = "0x" + toHex(s.second.keccak256().asBytes()); + if (optional licenseString = s.second.ast->licenseString()) + meta["sources"][s.first]["license"] = *licenseString; if (m_metadataLiteralSources) meta["sources"][s.first]["content"] = s.second.scanner->source(); else diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 99b9a2cac..7ae22dc70 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -30,8 +30,11 @@ #include #include #include +#include +#include #include #include +#include using namespace std; using namespace solidity::langutil; @@ -79,6 +82,7 @@ ASTPointer Parser::parse(shared_ptr const& _scanner) m_recursionDepth = 0; m_scanner = _scanner; ASTNodeFactory nodeFactory(*this); + vector> nodes; while (m_scanner->currentToken() != Token::EOS) { @@ -107,7 +111,7 @@ ASTPointer Parser::parse(shared_ptr const& _scanner) } } solAssert(m_recursionDepth == 0, ""); - return nodeFactory.createNode(nodes); + return nodeFactory.createNode(findLicenseString(nodes), nodes); } catch (FatalError const&) { @@ -1981,6 +1985,60 @@ pair>, vector>> Parser::pars return ret; } +optional Parser::findLicenseString(std::vector> const& _nodes) +{ + // We circumvent the scanner here, because it skips non-docstring comments. + static regex const licenseRegex("SPDX-License-Identifier:\\s*([a-zA-Z0-9 ()+.-]+)"); + + // Search inside all parts of the source not covered by parsed nodes. + // This will leave e.g. "global comments". + string const& source = m_scanner->source(); + using iter = decltype(source.begin()); + vector> sequencesToSearch; + sequencesToSearch.emplace_back(source.begin(), source.end()); + for (ASTPointer const& node: _nodes) + if (node->location().hasText()) + { + sequencesToSearch.back().second = source.begin() + node->location().start; + sequencesToSearch.emplace_back(source.begin() + node->location().end, source.end()); + } + + vector matches; + for (auto const& [start, end]: sequencesToSearch) + { + smatch match; + if (regex_search(start, end, match, licenseRegex)) + { + string license{boost::trim_copy(string(match[1]))}; + if (!license.empty()) + matches.emplace_back(std::move(license)); + } + } + + if (matches.size() == 1) + return matches.front(); + else if (matches.empty()) + parserWarning( + 1878_error, + {-1, -1, m_scanner->charStream()}, + "SPDX license identifier not provided in source file. " + "Before publishing, consider adding a comment containing " + "\"SPDX-License-Identifier: \" to each source file. " + "Use \"SPDX-License-Identifier: UNLICENSED\" for non-open-source code. " + "Please see https://spdx.org for more information." + ); + else + parserError( + 3716_error, + {-1, -1, m_scanner->charStream()}, + "Multiple SPDX license identifiers found in source file. " + "Use \"AND\" or \"OR\" to combine multiple licenses. " + "Please see https://spdx.org for more information." + ); + + return {}; +} + Parser::LookAheadInfo Parser::peekStatementType() const { // Distinguish between variable declaration (and potentially assignment) and expression statement diff --git a/libsolidity/parsing/Parser.h b/libsolidity/parsing/Parser.h index 25bb2b93f..f66754045 100644 --- a/libsolidity/parsing/Parser.h +++ b/libsolidity/parsing/Parser.h @@ -175,6 +175,8 @@ private: bool empty() const; }; + std::optional findLicenseString(std::vector> const& _nodes); + /// Returns the next AST node ID int64_t nextID() { return ++m_currentNodeID; } diff --git a/test/libsolidity/ABIJsonTest.cpp b/test/libsolidity/ABIJsonTest.cpp index d144e2ee7..a46c1d470 100644 --- a/test/libsolidity/ABIJsonTest.cpp +++ b/test/libsolidity/ABIJsonTest.cpp @@ -45,7 +45,10 @@ TestCase::TestResult ABIJsonTest::run(ostream& _stream, string const& _linePrefi { CompilerStack compiler; - compiler.setSources({{"", "pragma solidity >=0.0;\n" + m_source}}); + compiler.setSources({{ + "", + "pragma solidity >=0.0;\n// SPDX-License-Identifier: GPL-3.0\n" + m_source + }}); compiler.setEVMVersion(solidity::test::CommonOptions::get().evmVersion()); compiler.setOptimiserSettings(solidity::test::CommonOptions::get().optimize); if (!compiler.parseAndAnalyze()) diff --git a/test/libsolidity/AnalysisFramework.cpp b/test/libsolidity/AnalysisFramework.cpp index be14d1cf1..80c20c760 100644 --- a/test/libsolidity/AnalysisFramework.cpp +++ b/test/libsolidity/AnalysisFramework.cpp @@ -44,13 +44,17 @@ pair AnalysisFramework::parseAnalyseAndReturnError( string const& _source, bool _reportWarnings, - bool _insertVersionPragma, + bool _insertLicenseAndVersionPragma, bool _allowMultipleErrors, bool _allowRecoveryErrors ) { compiler().reset(); - compiler().setSources({{"", _insertVersionPragma ? "pragma solidity >=0.0;\n" + _source : _source}}); + compiler().setSources({{"", + _insertLicenseAndVersionPragma ? + "pragma solidity >=0.0;\n// SPDX-License-Identifier: GPL-3.0\n" + _source : + _source + }}); compiler().setEVMVersion(solidity::test::CommonOptions::get().evmVersion()); compiler().setParserErrorRecovery(_allowRecoveryErrors); _allowMultipleErrors = _allowMultipleErrors || _allowRecoveryErrors; diff --git a/test/libsolidity/AnalysisFramework.h b/test/libsolidity/AnalysisFramework.h index 26ca9e916..db75ad301 100644 --- a/test/libsolidity/AnalysisFramework.h +++ b/test/libsolidity/AnalysisFramework.h @@ -47,7 +47,7 @@ protected: parseAnalyseAndReturnError( std::string const& _source, bool _reportWarnings = false, - bool _insertVersionPragma = true, + bool _insertLicenseAndVersionPragma = true, bool _allowMultipleErrors = false, bool _allowRecoveryErrors = false ); diff --git a/test/libsolidity/GasMeter.cpp b/test/libsolidity/GasMeter.cpp index 79394855a..09e257664 100644 --- a/test/libsolidity/GasMeter.cpp +++ b/test/libsolidity/GasMeter.cpp @@ -43,7 +43,8 @@ public: void compile(string const& _sourceCode) { m_compiler.reset(); - m_compiler.setSources({{"", "pragma solidity >=0.0;\n" + _sourceCode}}); + m_compiler.setSources({{"", "pragma solidity >=0.0;\n" + "// SPDX-License-Identifier: GPL-3.0\n" + _sourceCode}}); m_compiler.setOptimiserSettings(solidity::test::CommonOptions::get().optimize); m_compiler.setEVMVersion(m_evmVersion); BOOST_REQUIRE_MESSAGE(m_compiler.compile(), "Compiling contract failed"); diff --git a/test/libsolidity/GasTest.cpp b/test/libsolidity/GasTest.cpp index 694839b99..893a20715 100644 --- a/test/libsolidity/GasTest.cpp +++ b/test/libsolidity/GasTest.cpp @@ -100,7 +100,7 @@ void GasTest::printUpdatedExpectations(ostream& _stream, string const& _linePref TestCase::TestResult GasTest::run(ostream& _stream, string const& _linePrefix, bool _formatted) { - string const versionPragma = "pragma solidity >=0.0;\n"; + string const preamble = "pragma solidity >=0.0;\n// SPDX-License-Identifier: GPL-3.0\n"; compiler().reset(); // Prerelease CBOR metadata varies in size due to changing version numbers and build dates. // This leads to volatile creation cost estimates. Therefore we force the compiler to @@ -114,7 +114,7 @@ TestCase::TestResult GasTest::run(ostream& _stream, string const& _linePrefix, b } settings.expectedExecutionsPerDeployment = m_optimiseRuns; compiler().setOptimiserSettings(settings); - compiler().setSources({{"", versionPragma + m_source}}); + compiler().setSources({{"", preamble + m_source}}); if (!compiler().parseAndAnalyze() || !compiler().compile()) { diff --git a/test/libsolidity/SMTChecker.cpp b/test/libsolidity/SMTChecker.cpp index 6df19c1c7..66398381e 100644 --- a/test/libsolidity/SMTChecker.cpp +++ b/test/libsolidity/SMTChecker.cpp @@ -38,7 +38,7 @@ protected: parseAnalyseAndReturnError( std::string const& _source, bool _reportWarnings = false, - bool _insertVersionPragma = true, + bool _insertLicenseAndVersionPragma = true, bool _allowMultipleErrors = false, bool _allowRecoveryErrors = false ) override @@ -46,7 +46,7 @@ protected: return AnalysisFramework::parseAnalyseAndReturnError( "pragma experimental SMTChecker;\n" + _source, _reportWarnings, - _insertVersionPragma, + _insertLicenseAndVersionPragma, _allowMultipleErrors, _allowRecoveryErrors ); diff --git a/test/libsolidity/SMTCheckerJSONTest.cpp b/test/libsolidity/SMTCheckerJSONTest.cpp index a1c23662a..484db13ff 100644 --- a/test/libsolidity/SMTCheckerJSONTest.cpp +++ b/test/libsolidity/SMTCheckerJSONTest.cpp @@ -64,8 +64,8 @@ TestCase::TestResult SMTCheckerJSONTest::run(ostream& _stream, string const& _li StandardCompiler compiler; // Run the compiler and retrieve the smtlib2queries (1st run) - string versionPragma = "pragma solidity >=0.0;\n"; - Json::Value input = buildJson(versionPragma); + string preamble = "pragma solidity >=0.0;\n// SPDX-License-Identifier: GPL-3.0\n"; + Json::Value input = buildJson(preamble); Json::Value result = compiler.compile(input); // This is the list of query hashes requested by the 1st run @@ -121,10 +121,10 @@ TestCase::TestResult SMTCheckerJSONTest::run(ostream& _stream, string const& _li std::string sourceName; if (location.isMember("source") && location["source"].isString()) sourceName = location["source"].asString(); - if (start >= static_cast(versionPragma.size())) - start -= versionPragma.size(); - if (end >= static_cast(versionPragma.size())) - end -= versionPragma.size(); + if (start >= static_cast(preamble.size())) + start -= preamble.size(); + if (end >= static_cast(preamble.size())) + end -= preamble.size(); m_errorList.emplace_back(SyntaxTestError{ error["type"].asString(), error["message"].asString(), diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 26d9ca989..b97d7bd4d 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -370,6 +370,7 @@ BOOST_AUTO_TEST_CASE(dynamic_return_types_not_possible) BOOST_AUTO_TEST_CASE(warn_nonpresent_pragma) { char const* text = R"( + // SPDX-License-Identifier: GPL-3.0 contract C {} )"; auto sourceAndError = parseAnalyseAndReturnError(text, true, false); diff --git a/test/libsolidity/SolidityTypes.cpp b/test/libsolidity/SolidityTypes.cpp index b21c8f2e1..bc9f16904 100644 --- a/test/libsolidity/SolidityTypes.cpp +++ b/test/libsolidity/SolidityTypes.cpp @@ -209,7 +209,7 @@ BOOST_AUTO_TEST_CASE(type_identifiers) ModifierDefinition mod(++id, SourceLocation{}, make_shared("modif"), {}, emptyParams, {}, {}, {}); BOOST_CHECK_EQUAL(ModifierType(mod).identifier(), "t_modifier$__$"); - SourceUnit su(++id, {}, {}); + SourceUnit su(++id, {}, {}, {}); BOOST_CHECK_EQUAL(ModuleType(su).identifier(), "t_module_7"); BOOST_CHECK_EQUAL(MagicType(MagicType::Kind::Block).identifier(), "t_magic_block"); BOOST_CHECK_EQUAL(MagicType(MagicType::Kind::Message).identifier(), "t_magic_message"); diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index ce9a29268..288bba3fe 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -427,7 +427,7 @@ BOOST_AUTO_TEST_CASE(basic_compilation) BOOST_CHECK(result["sources"]["fileA"]["legacyAST"].isObject()); BOOST_CHECK_EQUAL( util::jsonCompactPrint(result["sources"]["fileA"]["legacyAST"]), - "{\"attributes\":{\"absolutePath\":\"fileA\",\"exportedSymbols\":{\"A\":[1]}},\"children\":" + "{\"attributes\":{\"absolutePath\":\"fileA\",\"exportedSymbols\":{\"A\":[1]},\"license\":null},\"children\":" "[{\"attributes\":{\"abstract\":false,\"baseContracts\":[null],\"contractDependencies\":[null],\"contractKind\":\"contract\"," "\"documentation\":null,\"fullyImplemented\":true,\"linearizedBaseContracts\":[1],\"name\":\"A\",\"nodes\":[null],\"scope\":2}," "\"id\":1,\"name\":\"ContractDefinition\",\"src\":\"0:14:0\"}],\"id\":2,\"name\":\"SourceUnit\",\"src\":\"0:14:0\"}" diff --git a/test/libsolidity/SyntaxTest.cpp b/test/libsolidity/SyntaxTest.cpp index 3ec506998..55a77ed30 100644 --- a/test/libsolidity/SyntaxTest.cpp +++ b/test/libsolidity/SyntaxTest.cpp @@ -52,11 +52,11 @@ TestCase::TestResult SyntaxTest::run(ostream& _stream, string const& _linePrefix void SyntaxTest::setupCompiler() { - string const versionPragma = "pragma solidity >=0.0;\n"; + string const preamble = "pragma solidity >=0.0;\n// SPDX-License-Identifier: GPL-3.0\n"; compiler().reset(); auto sourcesWithPragma = m_sources; for (auto& source: sourcesWithPragma) - source.second = versionPragma + source.second; + source.second = preamble + source.second; compiler().setSources(sourcesWithPragma); compiler().setEVMVersion(m_evmVersion); compiler().setParserErrorRecovery(m_parserErrorRecovery); @@ -89,18 +89,18 @@ void SyntaxTest::parseAndAnalyze() void SyntaxTest::filterObtainedErrors() { - string const versionPragma = "pragma solidity >=0.0;\n"; + string const preamble = "pragma solidity >=0.0;\n// SPDX-License-Identifier: GPL-3.0\n"; for (auto const& currentError: filterErrors(compiler().errors(), true)) { int locationStart = -1, locationEnd = -1; string sourceName; if (auto location = boost::get_error_info(*currentError)) { - // ignore the version pragma inserted by the testing tool when calculating locations. - if (location->start >= static_cast(versionPragma.size())) - locationStart = location->start - versionPragma.size(); - if (location->end >= static_cast(versionPragma.size())) - locationEnd = location->end - versionPragma.size(); + // ignore the version & license pragma inserted by the testing tool when calculating locations. + if (location->start >= static_cast(preamble.size())) + locationStart = location->start - (preamble.size()); + if (location->end >= static_cast(preamble.size())) + locationEnd = location->end - (preamble.size()); if (location->source) sourceName = location->source->name(); } From 52b9a92ff803f4b7cfcfee7d6e8559775e68c6c0 Mon Sep 17 00:00:00 2001 From: Alexander Arlt Date: Tue, 12 May 2020 20:52:11 -0500 Subject: [PATCH 79/89] Update existing tests. --- .../abiencoderv2_no_warning/input.sol | 2 + .../input.sol | 1 + test/cmdlineTests/ir_compiler_subobjects/err | 4 +- .../ir_compiler_subobjects/input.sol | 1 + test/cmdlineTests/message_format/input.sol | 2 +- .../cmdlineTests/optimizer_user_yul/input.sol | 1 + test/cmdlineTests/optimizer_user_yul/output | 50 +++++++++---------- .../output_selection_all_A1/input.json | 4 +- .../output_selection_all_A1/output.json | 4 +- .../output_selection_all_A2/input.json | 4 +- .../output_selection_all_A2/output.json | 4 +- .../output_selection_all_blank/input.json | 4 +- .../output_selection_all_blank/output.json | 4 +- .../output_selection_all_star/input.json | 4 +- .../output_selection_all_star/output.json | 4 +- .../output_selection_single_A1/input.json | 4 +- .../output_selection_single_B1/input.json | 4 +- .../output_selection_single_B1/output.json | 4 +- .../output_selection_single_all/input.json | 4 +- .../cmdlineTests/recovery_ast_constructor/err | 8 +-- .../recovery_ast_constructor/input.sol | 1 + .../recovery_ast_constructor/output | 33 ++++++------ .../recovery_ast_empty_contract/err | 4 +- .../recovery_ast_empty_contract/input.sol | 1 + .../recovery_standard_json/input.json | 2 +- .../recovery_standard_json/output.json | 6 +-- test/cmdlineTests/require_overload/err | 4 +- test/cmdlineTests/require_overload/input.sol | 1 + .../standard_default_success/input.json | 2 +- .../standard_eWasm_requested/input.json | 2 +- .../standard_empty_file_name/input.json | 2 +- .../standard_empty_file_name/output.json | 2 +- .../standard_immutable_references/input.json | 2 +- .../standard_immutable_references/output.json | 2 +- .../standard_irOptimized_requested/input.json | 2 +- .../standard_ir_requested/input.json | 2 +- .../input.json | 2 +- .../input.json | 2 +- .../standard_only_ast_requested/input.json | 2 +- .../standard_only_ast_requested/output.json | 2 +- .../input.json | 2 +- .../input.json | 2 +- .../standard_optimizer_no_yul/input.json | 2 +- .../standard_optimizer_yul/input.json | 2 +- .../standard_optimizer_yulDetails/input.json | 2 +- .../input.json | 2 +- .../input.json | 2 +- .../input.json | 2 +- .../input.json | 2 +- .../input.json | 2 +- .../input.json | 2 +- .../input.json | 2 +- .../input.json | 2 +- .../output.json | 8 +-- .../input.json | 2 +- .../standard_wrong_key_metadata/input.json | 2 +- .../standard_wrong_key_optimizer/input.json | 2 +- .../standard_wrong_key_root/input.json | 2 +- .../standard_wrong_key_settings/input.json | 2 +- .../standard_wrong_key_source/input.json | 2 +- .../input.json | 2 +- .../input.json | 2 +- .../input.json | 2 +- .../standard_wrong_type_metadata/input.json | 2 +- .../standard_wrong_type_optimizer/input.json | 2 +- .../input.json | 2 +- .../input.json | 2 +- .../input.json | 2 +- .../input.json | 2 +- .../standard_wrong_type_remappings/input.json | 2 +- .../input.json | 2 +- .../standard_wrong_type_settings/input.json | 2 +- .../standard_wrong_type_source/input.json | 2 +- .../input.json | 2 +- .../storage_layout_bytes/input.json | 2 +- .../storage_layout_dyn_array/input.json | 2 +- .../storage_layout_many/input.json | 2 +- .../storage_layout_mapping/input.json | 2 +- .../storage_layout_smoke/input.json | 2 +- .../input.json | 4 +- .../storage_layout_string/input.json | 2 +- .../storage_layout_struct/input.json | 2 +- .../storage_layout_struct_packed/input.json | 2 +- .../storage_layout_value_types/input.json | 2 +- .../input.json | 2 +- .../err | 8 +-- .../input.sol | 1 + test/cmdlineTests/too_long_line/err | 3 ++ .../too_long_line_both_sides_short/err | 3 ++ test/cmdlineTests/too_long_line_edge_in/err | 3 ++ test/cmdlineTests/too_long_line_edge_out/err | 3 ++ .../cmdlineTests/too_long_line_left_short/err | 3 ++ test/cmdlineTests/too_long_line_multiline/err | 3 ++ .../too_long_line_right_short/err | 3 ++ .../yul_optimizer_steps/input.sol | 1 + .../yul_optimizer_steps_disabled/input.sol | 1 + .../input.sol | 1 + .../input.sol | 1 + .../input.sol | 1 + .../yul_string_format_ascii/input.json | 2 +- .../input.json | 2 +- .../input.json | 2 +- .../yul_string_format_ascii_long/input.json | 2 +- .../yul_string_format_hex/input.json | 2 +- .../ASTJSON/abstract_contract.json | 1 + .../ASTJSON/abstract_contract_legacy.json | 3 +- test/libsolidity/ASTJSON/address_payable.json | 1 + .../ASTJSON/address_payable_legacy.json | 3 +- test/libsolidity/ASTJSON/array_type_name.json | 1 + .../ASTJSON/array_type_name_legacy.json | 3 +- test/libsolidity/ASTJSON/assembly/call.json | 1 + .../ASTJSON/assembly/call_legacy.json | 3 +- .../ASTJSON/assembly/empty_block.json | 1 + .../ASTJSON/assembly/empty_block_legacy.json | 3 +- .../ASTJSON/assembly/function.json | 1 + .../ASTJSON/assembly/function_legacy.json | 3 +- test/libsolidity/ASTJSON/assembly/leave.json | 1 + .../ASTJSON/assembly/leave_legacy.json | 3 +- test/libsolidity/ASTJSON/assembly/loop.json | 1 + .../ASTJSON/assembly/loop_legacy.json | 3 +- .../ASTJSON/assembly/nested_functions.json | 1 + .../assembly/nested_functions_legacy.json | 3 +- .../ASTJSON/assembly/slot_offset.json | 1 + .../ASTJSON/assembly/slot_offset_legacy.json | 3 +- .../ASTJSON/assembly/stringlit.json | 1 + .../ASTJSON/assembly/stringlit_legacy.json | 3 +- test/libsolidity/ASTJSON/assembly/switch.json | 1 + .../ASTJSON/assembly/switch_default.json | 1 + .../assembly/switch_default_legacy.json | 3 +- .../ASTJSON/assembly/switch_legacy.json | 3 +- .../ASTJSON/assembly/var_access.json | 1 + .../ASTJSON/assembly/var_access_legacy.json | 3 +- test/libsolidity/ASTJSON/constructor.json | 1 + .../ASTJSON/constructor_legacy.json | 3 +- .../ASTJSON/contract_dep_order.json | 1 + .../ASTJSON/contract_dep_order_legacy.json | 3 +- test/libsolidity/ASTJSON/documentation.json | 3 ++ .../ASTJSON/documentation_legacy.json | 3 +- test/libsolidity/ASTJSON/enum_value.json | 1 + .../ASTJSON/enum_value_legacy.json | 3 +- .../libsolidity/ASTJSON/event_definition.json | 1 + .../ASTJSON/event_definition_legacy.json | 3 +- test/libsolidity/ASTJSON/fallback.json | 1 + .../ASTJSON/fallback_and_reveice_ether.json | 1 + .../fallback_and_reveice_ether_legacy.json | 3 +- test/libsolidity/ASTJSON/fallback_legacy.json | 3 +- .../libsolidity/ASTJSON/fallback_payable.json | 1 + .../ASTJSON/fallback_payable_legacy.json | 3 +- test/libsolidity/ASTJSON/function_type.json | 1 + .../ASTJSON/function_type_legacy.json | 3 +- test/libsolidity/ASTJSON/global_enum.json | 1 + .../ASTJSON/global_enum_legacy.json | 3 +- test/libsolidity/ASTJSON/global_struct.json | 1 + .../ASTJSON/global_struct_legacy.json | 3 +- .../ASTJSON/inheritance_specifier.json | 1 + .../ASTJSON/inheritance_specifier_legacy.json | 3 +- .../long_type_name_binary_operation.json | 1 + ...ong_type_name_binary_operation_legacy.json | 3 +- .../ASTJSON/long_type_name_identifier.json | 1 + .../long_type_name_identifier_legacy.json | 3 +- test/libsolidity/ASTJSON/mappings.json | 1 + test/libsolidity/ASTJSON/mappings_legacy.json | 3 +- .../ASTJSON/modifier_definition.json | 1 + .../ASTJSON/modifier_definition_legacy.json | 3 +- .../ASTJSON/modifier_invocation.json | 1 + .../ASTJSON/modifier_invocation_legacy.json | 3 +- test/libsolidity/ASTJSON/mutability.json | 1 + .../ASTJSON/mutability_legacy.json | 3 +- test/libsolidity/ASTJSON/non_utf8.json | 1 + test/libsolidity/ASTJSON/non_utf8_legacy.json | 3 +- test/libsolidity/ASTJSON/override.json | 1 + test/libsolidity/ASTJSON/override_legacy.json | 3 +- .../ASTJSON/placeholder_statement.json | 1 + .../ASTJSON/placeholder_statement_legacy.json | 3 +- test/libsolidity/ASTJSON/receive_ether.json | 1 + .../ASTJSON/receive_ether_legacy.json | 3 +- test/libsolidity/ASTJSON/short_type_name.json | 1 + .../ASTJSON/short_type_name_legacy.json | 3 +- .../ASTJSON/short_type_name_ref.json | 1 + .../ASTJSON/short_type_name_ref_legacy.json | 3 +- test/libsolidity/ASTJSON/smoke.json | 1 + test/libsolidity/ASTJSON/smoke_legacy.json | 3 +- test/libsolidity/ASTJSON/source_location.json | 1 + .../ASTJSON/source_location_legacy.json | 3 +- .../ASTJSON/two_base_functions.json | 1 + .../ASTJSON/two_base_functions_legacy.json | 3 +- .../ASTJSON/using_for_directive.json | 1 + .../ASTJSON/using_for_directive_legacy.json | 3 +- 188 files changed, 314 insertions(+), 192 deletions(-) diff --git a/test/cmdlineTests/abiencoderv2_no_warning/input.sol b/test/cmdlineTests/abiencoderv2_no_warning/input.sol index fef512e55..c2eb120f8 100644 --- a/test/cmdlineTests/abiencoderv2_no_warning/input.sol +++ b/test/cmdlineTests/abiencoderv2_no_warning/input.sol @@ -1,5 +1,7 @@ +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.0; pragma experimental ABIEncoderV2; + contract C { struct S { uint x; } function f(S memory) public pure { diff --git a/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/input.sol b/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/input.sol index 69f553304..160c4cd1d 100644 --- a/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/input.sol +++ b/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/input.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0; contract C { diff --git a/test/cmdlineTests/ir_compiler_subobjects/err b/test/cmdlineTests/ir_compiler_subobjects/err index a28ad1966..d4394af57 100644 --- a/test/cmdlineTests/ir_compiler_subobjects/err +++ b/test/cmdlineTests/ir_compiler_subobjects/err @@ -1,5 +1,5 @@ Warning: Unused local variable. - --> ir_compiler_subobjects/input.sol:6:9: + --> ir_compiler_subobjects/input.sol:7:9: | -6 | C c = new C(); +7 | C c = new C(); | ^^^ diff --git a/test/cmdlineTests/ir_compiler_subobjects/input.sol b/test/cmdlineTests/ir_compiler_subobjects/input.sol index e0fdbbc13..13f9f3c60 100644 --- a/test/cmdlineTests/ir_compiler_subobjects/input.sol +++ b/test/cmdlineTests/ir_compiler_subobjects/input.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0; contract C {} diff --git a/test/cmdlineTests/message_format/input.sol b/test/cmdlineTests/message_format/input.sol index 6f854f96a..cbb51c9d6 100644 --- a/test/cmdlineTests/message_format/input.sol +++ b/test/cmdlineTests/message_format/input.sol @@ -1,5 +1,5 @@ // checks that error messages around power-or-10 lines are formatted correctly - +// SPDX-License-Identifier: GPL-3.0 diff --git a/test/cmdlineTests/optimizer_user_yul/input.sol b/test/cmdlineTests/optimizer_user_yul/input.sol index 74dc84cbd..e61b132e4 100644 --- a/test/cmdlineTests/optimizer_user_yul/input.sol +++ b/test/cmdlineTests/optimizer_user_yul/input.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.0; contract C diff --git a/test/cmdlineTests/optimizer_user_yul/output b/test/cmdlineTests/optimizer_user_yul/output index 8eef7b4f6..a160c37c4 100644 --- a/test/cmdlineTests/optimizer_user_yul/output +++ b/test/cmdlineTests/optimizer_user_yul/output @@ -1,69 +1,69 @@ ======= optimizer_user_yul/input.sol:C ======= EVM assembly: - /* "optimizer_user_yul/input.sol":24:489 contract C... */ + /* "optimizer_user_yul/input.sol":60:525 contract C... */ mstore(0x40, 0x80) - /* "optimizer_user_yul/input.sol":72:77 int a */ + /* "optimizer_user_yul/input.sol":108:113 int a */ 0x00 - /* "optimizer_user_yul/input.sol":152:161 let x,y,z */ + /* "optimizer_user_yul/input.sol":188:197 let x,y,z */ dup1 0x00 dup1 - /* "optimizer_user_yul/input.sol":176:177 1 */ + /* "optimizer_user_yul/input.sol":212:213 1 */ 0x01 - /* "optimizer_user_yul/input.sol":173:174 0 */ + /* "optimizer_user_yul/input.sol":209:210 0 */ 0x00 - /* "optimizer_user_yul/input.sol":166:178 sstore(0, 1) */ + /* "optimizer_user_yul/input.sol":202:214 sstore(0, 1) */ sstore - /* "optimizer_user_yul/input.sol":183:229 for { } sload(4) { } {... */ + /* "optimizer_user_yul/input.sol":219:265 for { } sload(4) { } {... */ tag_3: - /* "optimizer_user_yul/input.sol":197:198 4 */ + /* "optimizer_user_yul/input.sol":233:234 4 */ 0x04 - /* "optimizer_user_yul/input.sol":191:199 sload(4) */ + /* "optimizer_user_yul/input.sol":227:235 sload(4) */ sload - /* "optimizer_user_yul/input.sol":183:229 for { } sload(4) { } {... */ + /* "optimizer_user_yul/input.sol":219:265 for { } sload(4) { } {... */ iszero tag_5 jumpi pop - /* "optimizer_user_yul/input.sol":215:224 exp(x, y) */ + /* "optimizer_user_yul/input.sol":251:260 exp(x, y) */ dup1 dup3 exp - /* "optimizer_user_yul/input.sol":183:229 for { } sload(4) { } {... */ + /* "optimizer_user_yul/input.sol":219:265 for { } sload(4) { } {... */ jump(tag_3) tag_5: - /* "optimizer_user_yul/input.sol":187:190 { } */ + /* "optimizer_user_yul/input.sol":223:226 { } */ pop pop pop - /* "optimizer_user_yul/input.sol":239:240 2 */ + /* "optimizer_user_yul/input.sol":275:276 2 */ 0x02 - /* "optimizer_user_yul/input.sol":234:240 a := 2 */ + /* "optimizer_user_yul/input.sol":270:276 a := 2 */ swap1 pop - /* "optimizer_user_yul/input.sol":340:341 3 */ + /* "optimizer_user_yul/input.sol":376:377 3 */ 0x03 - /* "optimizer_user_yul/input.sol":337:338 2 */ + /* "optimizer_user_yul/input.sol":373:374 2 */ 0x02 - /* "optimizer_user_yul/input.sol":330:342 sstore(2, 3) */ + /* "optimizer_user_yul/input.sol":366:378 sstore(2, 3) */ sstore - /* "optimizer_user_yul/input.sol":347:480 for { } sload(5) { } {... */ + /* "optimizer_user_yul/input.sol":383:516 for { } sload(5) { } {... */ tag_6: - /* "optimizer_user_yul/input.sol":361:362 5 */ + /* "optimizer_user_yul/input.sol":397:398 5 */ 0x05 - /* "optimizer_user_yul/input.sol":355:363 sload(5) */ + /* "optimizer_user_yul/input.sol":391:399 sload(5) */ sload tag_9 jumpi jump(tag_8) tag_9: - /* "optimizer_user_yul/input.sol":347:480 for { } sload(5) { } {... */ + /* "optimizer_user_yul/input.sol":383:516 for { } sload(5) { } {... */ jump(tag_6) tag_8: - /* "optimizer_user_yul/input.sol":311:484 {... */ + /* "optimizer_user_yul/input.sol":347:520 {... */ pop - /* "optimizer_user_yul/input.sol":24:489 contract C... */ + /* "optimizer_user_yul/input.sol":60:525 contract C... */ dataSize(sub_0) dup1 dataOffset(sub_0) @@ -74,7 +74,7 @@ tag_8: stop sub_0: assembly { - /* "optimizer_user_yul/input.sol":24:489 contract C... */ + /* "optimizer_user_yul/input.sol":60:525 contract C... */ mstore(0x40, 0x80) /* "--CODEGEN--":12:13 */ 0x00 diff --git a/test/cmdlineTests/output_selection_all_A1/input.json b/test/cmdlineTests/output_selection_all_A1/input.json index 339077d0b..a7a84163d 100644 --- a/test/cmdlineTests/output_selection_all_A1/input.json +++ b/test/cmdlineTests/output_selection_all_A1/input.json @@ -2,10 +2,10 @@ "language": "Solidity", "sources": { "a.sol": { - "content": "contract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" }, "b.sol": { - "content": "contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" } }, "settings": { diff --git a/test/cmdlineTests/output_selection_all_A1/output.json b/test/cmdlineTests/output_selection_all_A1/output.json index e87df2995..074b2062b 100644 --- a/test/cmdlineTests/output_selection_all_A1/output.json +++ b/test/cmdlineTests/output_selection_all_A1/output.json @@ -1,6 +1,6 @@ {"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}},"b.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:1:15: Warning: Function state mutability can be restricted to pure +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } ^------------------------------------------^ -","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":58,"file":"b.sol","start":14},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} +","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/output_selection_all_A2/input.json b/test/cmdlineTests/output_selection_all_A2/input.json index 4a29266ad..3107a5e4c 100644 --- a/test/cmdlineTests/output_selection_all_A2/input.json +++ b/test/cmdlineTests/output_selection_all_A2/input.json @@ -2,10 +2,10 @@ "language": "Solidity", "sources": { "a.sol": { - "content": "contract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" }, "b.sol": { - "content": "contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" } }, "settings": { diff --git a/test/cmdlineTests/output_selection_all_A2/output.json b/test/cmdlineTests/output_selection_all_A2/output.json index 7601952b6..aa2ca9d0e 100644 --- a/test/cmdlineTests/output_selection_all_A2/output.json +++ b/test/cmdlineTests/output_selection_all_A2/output.json @@ -1,6 +1,6 @@ {"contracts":{"a.sol":{"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:1:15: Warning: Function state mutability can be restricted to pure +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } ^------------------------------------------^ -","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":58,"file":"b.sol","start":14},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} +","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/output_selection_all_blank/input.json b/test/cmdlineTests/output_selection_all_blank/input.json index 08c2946c6..85bc114b3 100644 --- a/test/cmdlineTests/output_selection_all_blank/input.json +++ b/test/cmdlineTests/output_selection_all_blank/input.json @@ -2,10 +2,10 @@ "language": "Solidity", "sources": { "a.sol": { - "content": "contract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" }, "b.sol": { - "content": "contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" } }, "settings": { diff --git a/test/cmdlineTests/output_selection_all_blank/output.json b/test/cmdlineTests/output_selection_all_blank/output.json index 81c98e790..e0872ca8c 100644 --- a/test/cmdlineTests/output_selection_all_blank/output.json +++ b/test/cmdlineTests/output_selection_all_blank/output.json @@ -1,6 +1,6 @@ {"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:1:15: Warning: Function state mutability can be restricted to pure +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } ^------------------------------------------^ -","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":58,"file":"b.sol","start":14},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} +","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/output_selection_all_star/input.json b/test/cmdlineTests/output_selection_all_star/input.json index 5d079abd3..450286311 100644 --- a/test/cmdlineTests/output_selection_all_star/input.json +++ b/test/cmdlineTests/output_selection_all_star/input.json @@ -2,10 +2,10 @@ "language": "Solidity", "sources": { "a.sol": { - "content": "contract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" }, "b.sol": { - "content": "contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" } }, "settings": { diff --git a/test/cmdlineTests/output_selection_all_star/output.json b/test/cmdlineTests/output_selection_all_star/output.json index 0a8071aaf..8997ed8e2 100644 --- a/test/cmdlineTests/output_selection_all_star/output.json +++ b/test/cmdlineTests/output_selection_all_star/output.json @@ -1,6 +1,6 @@ {"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}},"b.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"B2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:1:15: Warning: Function state mutability can be restricted to pure +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } ^------------------------------------------^ -","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":58,"file":"b.sol","start":14},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} +","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/output_selection_single_A1/input.json b/test/cmdlineTests/output_selection_single_A1/input.json index 5f11ce6da..2ea69a594 100644 --- a/test/cmdlineTests/output_selection_single_A1/input.json +++ b/test/cmdlineTests/output_selection_single_A1/input.json @@ -2,10 +2,10 @@ "language": "Solidity", "sources": { "a.sol": { - "content": "contract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" }, "b.sol": { - "content": "contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" } }, "settings": { diff --git a/test/cmdlineTests/output_selection_single_B1/input.json b/test/cmdlineTests/output_selection_single_B1/input.json index 6adcd139e..f25a1b57d 100644 --- a/test/cmdlineTests/output_selection_single_B1/input.json +++ b/test/cmdlineTests/output_selection_single_B1/input.json @@ -2,10 +2,10 @@ "language": "Solidity", "sources": { "a.sol": { - "content": "contract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" }, "b.sol": { - "content": "contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" } }, "settings": { diff --git a/test/cmdlineTests/output_selection_single_B1/output.json b/test/cmdlineTests/output_selection_single_B1/output.json index fafe87ebd..c9c929b97 100644 --- a/test/cmdlineTests/output_selection_single_B1/output.json +++ b/test/cmdlineTests/output_selection_single_B1/output.json @@ -1,5 +1,5 @@ {"contracts":{"b.sol":{"B2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:1:15: Warning: Function state mutability can be restricted to pure +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } ^------------------------------------------^ -","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":58,"file":"b.sol","start":14},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} +","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/output_selection_single_all/input.json b/test/cmdlineTests/output_selection_single_all/input.json index 1dddfe771..a4137b063 100644 --- a/test/cmdlineTests/output_selection_single_all/input.json +++ b/test/cmdlineTests/output_selection_single_all/input.json @@ -2,10 +2,10 @@ "language": "Solidity", "sources": { "a.sol": { - "content": "contract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function a(uint x) public pure { assert(x > 0); } } contract A2 { function a(uint x) public pure { assert(x > 0); } }" }, "b.sol": { - "content": "contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } }" } }, "settings": { diff --git a/test/cmdlineTests/recovery_ast_constructor/err b/test/cmdlineTests/recovery_ast_constructor/err index 81c911386..ecff59f7a 100644 --- a/test/cmdlineTests/recovery_ast_constructor/err +++ b/test/cmdlineTests/recovery_ast_constructor/err @@ -1,13 +1,13 @@ Error: Expected primary expression. - --> recovery_ast_constructor/input.sol:5:27: + --> recovery_ast_constructor/input.sol:6:27: | -5 | balances[tx.origin] = ; // missing RHS. +6 | balances[tx.origin] = ; // missing RHS. | ^ Warning: Recovered in Statement at ';'. - --> recovery_ast_constructor/input.sol:5:27: + --> recovery_ast_constructor/input.sol:6:27: | -5 | balances[tx.origin] = ; // missing RHS. +6 | balances[tx.origin] = ; // missing RHS. | ^ diff --git a/test/cmdlineTests/recovery_ast_constructor/input.sol b/test/cmdlineTests/recovery_ast_constructor/input.sol index a6b55ab7f..9035590d9 100644 --- a/test/cmdlineTests/recovery_ast_constructor/input.sol +++ b/test/cmdlineTests/recovery_ast_constructor/input.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.0.0; contract Error1 { diff --git a/test/cmdlineTests/recovery_ast_constructor/output b/test/cmdlineTests/recovery_ast_constructor/output index f2cc2ccf8..06d7bb95c 100644 --- a/test/cmdlineTests/recovery_ast_constructor/output +++ b/test/cmdlineTests/recovery_ast_constructor/output @@ -12,7 +12,8 @@ JSON AST: [ 18 ] - } + }, + "license": "GPL-3.0" }, "children": [ @@ -29,7 +30,7 @@ JSON AST: }, "id": 1, "name": "PragmaDirective", - "src": "0:24:0" + "src": "36:24:0" }, { "attributes": @@ -86,7 +87,7 @@ JSON AST: "children": [], "id": 2, "name": "ParameterList", - "src": "57:2:0" + "src": "93:2:0" }, { "attributes": @@ -99,7 +100,7 @@ JSON AST: "children": [], "id": 3, "name": "ParameterList", - "src": "67:0:0" + "src": "103:0:0" }, { "attributes": @@ -112,12 +113,12 @@ JSON AST: "children": [], "id": 8, "name": "Block", - "src": "67:49:0" + "src": "103:49:0" } ], "id": 9, "name": "FunctionDefinition", - "src": "46:70:0" + "src": "82:70:0" }, { "attributes": @@ -151,7 +152,7 @@ JSON AST: "children": [], "id": 10, "name": "ParameterList", - "src": "382:2:0" + "src": "418:2:0" }, { "children": @@ -180,17 +181,17 @@ JSON AST: }, "id": 11, "name": "ElementaryTypeName", - "src": "405:4:0" + "src": "441:4:0" } ], "id": 12, "name": "VariableDeclaration", - "src": "405:4:0" + "src": "441:4:0" } ], "id": 13, "name": "ParameterList", - "src": "404:6:0" + "src": "440:6:0" }, { "children": @@ -218,30 +219,30 @@ JSON AST: }, "id": 14, "name": "Literal", - "src": "424:1:0" + "src": "460:1:0" } ], "id": 15, "name": "Return", - "src": "417:8:0" + "src": "453:8:0" } ], "id": 16, "name": "Block", - "src": "411:19:0" + "src": "447:19:0" } ], "id": 17, "name": "FunctionDefinition", - "src": "369:61:0" + "src": "405:61:0" } ], "id": 18, "name": "ContractDefinition", - "src": "26:406:0" + "src": "62:406:0" } ], "id": 19, "name": "SourceUnit", - "src": "0:433:0" + "src": "36:433:0" } diff --git a/test/cmdlineTests/recovery_ast_empty_contract/err b/test/cmdlineTests/recovery_ast_empty_contract/err index 3de346d51..588067877 100644 --- a/test/cmdlineTests/recovery_ast_empty_contract/err +++ b/test/cmdlineTests/recovery_ast_empty_contract/err @@ -1,7 +1,7 @@ Error: Expected pragma, import directive or contract/interface/library/struct/enum definition. - --> recovery_ast_empty_contract/input.sol:2:1: + --> recovery_ast_empty_contract/input.sol:3:1: | -2 | c +3 | c | ^ diff --git a/test/cmdlineTests/recovery_ast_empty_contract/input.sol b/test/cmdlineTests/recovery_ast_empty_contract/input.sol index c54a818bf..bdc83a2c9 100644 --- a/test/cmdlineTests/recovery_ast_empty_contract/input.sol +++ b/test/cmdlineTests/recovery_ast_empty_contract/input.sol @@ -1,2 +1,3 @@ +// SPDX-License-Identifier: GPL-3.0 pragma 0.5.11; c \ No newline at end of file diff --git a/test/cmdlineTests/recovery_standard_json/input.json b/test/cmdlineTests/recovery_standard_json/input.json index bc0d019d2..9c8b15066 100644 --- a/test/cmdlineTests/recovery_standard_json/input.json +++ b/test/cmdlineTests/recovery_standard_json/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract Errort6 { using foo for ; /* missing type name */ }" + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract Errort6 { using foo for ; /* missing type name */ }" } }, "settings": diff --git a/test/cmdlineTests/recovery_standard_json/output.json b/test/cmdlineTests/recovery_standard_json/output.json index 1f2ab6eb6..18a3b97ce 100644 --- a/test/cmdlineTests/recovery_standard_json/output.json +++ b/test/cmdlineTests/recovery_standard_json/output.json @@ -1,7 +1,7 @@ -{"errors":[{"component":"general","formattedMessage":"A:1:58: ParserError: Expected type name +{"errors":[{"component":"general","formattedMessage":"A:2:58: ParserError: Expected type name pragma solidity >=0.0; contract Errort6 { using foo for ; /* missing type name */ } ^ -","message":"Expected type name","severity":"error","sourceLocation":{"end":58,"file":"A","start":57},"type":"ParserError"},{"component":"general","formattedMessage":"A:1:84: Warning: Recovered in ContractDefinition at '}'. +","message":"Expected type name","severity":"error","sourceLocation":{"end":94,"file":"A","start":93},"type":"ParserError"},{"component":"general","formattedMessage":"A:2:84: Warning: Recovered in ContractDefinition at '}'. pragma solidity >=0.0; contract Errort6 { using foo for ; /* missing type name */ } ^ -","message":"Recovered in ContractDefinition at '}'.","severity":"warning","sourceLocation":{"end":84,"file":"A","start":83},"type":"Warning"}],"sources":{"A":{"ast":{"absolutePath":"A","exportedSymbols":{"Errort6":[3]},"id":4,"nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"0:22:0"},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","documentation":null,"fullyImplemented":true,"id":3,"linearizedBaseContracts":[3],"name":"Errort6","nodeType":"ContractDefinition","nodes":[],"scope":4,"src":"23:35:0"}],"src":"0:84:0"},"id":0}}} +","message":"Recovered in ContractDefinition at '}'.","severity":"warning","sourceLocation":{"end":120,"file":"A","start":119},"type":"Warning"}],"sources":{"A":{"ast":{"absolutePath":"A","exportedSymbols":{"Errort6":[3]},"id":4,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:0"},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","documentation":null,"fullyImplemented":true,"id":3,"linearizedBaseContracts":[3],"name":"Errort6","nodeType":"ContractDefinition","nodes":[],"scope":4,"src":"59:35:0"}],"src":"36:84:0"},"id":0}}} diff --git a/test/cmdlineTests/require_overload/err b/test/cmdlineTests/require_overload/err index 83f027608..4c33672d4 100644 --- a/test/cmdlineTests/require_overload/err +++ b/test/cmdlineTests/require_overload/err @@ -1,7 +1,7 @@ Error: No matching declaration found after argument-dependent lookup. - --> require_overload/input.sol:4:9: + --> require_overload/input.sol:5:9: | -4 | require(this); +5 | require(this); | ^^^^^^^ Note: Candidate: function require(bool) Note: Candidate: function require(bool, string memory) diff --git a/test/cmdlineTests/require_overload/input.sol b/test/cmdlineTests/require_overload/input.sol index 6d48ac24a..b927c043c 100644 --- a/test/cmdlineTests/require_overload/input.sol +++ b/test/cmdlineTests/require_overload/input.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.0; contract C { function f() public pure { diff --git a/test/cmdlineTests/standard_default_success/input.json b/test/cmdlineTests/standard_default_success/input.json index 826253b85..47a367113 100644 --- a/test/cmdlineTests/standard_default_success/input.json +++ b/test/cmdlineTests/standard_default_success/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } } } diff --git a/test/cmdlineTests/standard_eWasm_requested/input.json b/test/cmdlineTests/standard_eWasm_requested/input.json index 9476629e1..25cc1705d 100644 --- a/test/cmdlineTests/standard_eWasm_requested/input.json +++ b/test/cmdlineTests/standard_eWasm_requested/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { }" + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { }" } }, "settings": diff --git a/test/cmdlineTests/standard_empty_file_name/input.json b/test/cmdlineTests/standard_empty_file_name/input.json index 95c2cdd30..209f994c5 100644 --- a/test/cmdlineTests/standard_empty_file_name/input.json +++ b/test/cmdlineTests/standard_empty_file_name/input.json @@ -4,7 +4,7 @@ { "": { - "content": "pragma solidity >=0.0; import {A} from \".\";" + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; import {A} from \".\";" } } } diff --git a/test/cmdlineTests/standard_empty_file_name/output.json b/test/cmdlineTests/standard_empty_file_name/output.json index b31ceb152..d1ab4c870 100644 --- a/test/cmdlineTests/standard_empty_file_name/output.json +++ b/test/cmdlineTests/standard_empty_file_name/output.json @@ -1,4 +1,4 @@ -{"errors":[{"component":"general","formattedMessage":":1:24: DeclarationError: Declaration \"A\" not found in \"\" (referenced as \".\"). +{"errors":[{"component":"general","formattedMessage":":2:24: DeclarationError: Declaration \"A\" not found in \"\" (referenced as \".\"). pragma solidity >=0.0; import {A} from \".\"; ^------------------^ ","message":"Declaration \"A\" not found in \"\" (referenced as \".\").","severity":"error","type":"DeclarationError"}],"sources":{}} diff --git a/test/cmdlineTests/standard_immutable_references/input.json b/test/cmdlineTests/standard_immutable_references/input.json index 15213be74..d81365c8a 100644 --- a/test/cmdlineTests/standard_immutable_references/input.json +++ b/test/cmdlineTests/standard_immutable_references/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "a.sol": { - "content": "contract A { uint256 immutable x = 1; function f() public view returns (uint256) { return x; } }" + "content": "// SPDX-License-Identifier: GPL-3.0\ncontract A { uint256 immutable x = 1; function f() public view returns (uint256) { return x; } }" } }, "settings": { diff --git a/test/cmdlineTests/standard_immutable_references/output.json b/test/cmdlineTests/standard_immutable_references/output.json index 2788a8e73..edb5d74d0 100644 --- a/test/cmdlineTests/standard_immutable_references/output.json +++ b/test/cmdlineTests/standard_immutable_references/output.json @@ -1,2 +1,2 @@ -{"contracts":{"a.sol":{"A":{"evm":{"deployedBytecode":{"immutableReferences":{"3":[{"length":32,"start":77}]},"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"0:96:0:-:0;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;0:96:0;;;;;;;;;;;;;;;;12:1:-1;9;2:12;38:56:0;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;72:7;90:1;83:8;;38:56;:::o"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! +{"contracts":{"a.sol":{"A":{"evm":{"deployedBytecode":{"immutableReferences":{"3":[{"length":32,"start":77}]},"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"36:96:0:-:0;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;36:96:0;;;;;;;;;;;;;;;;12:1:-1;9;2:12;74:56:0;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;108:7;126:1;119:8;;74:56;:::o"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"}],"sources":{"a.sol":{"id":0}}} diff --git a/test/cmdlineTests/standard_irOptimized_requested/input.json b/test/cmdlineTests/standard_irOptimized_requested/input.json index 96ea078bd..09aa37bae 100644 --- a/test/cmdlineTests/standard_irOptimized_requested/input.json +++ b/test/cmdlineTests/standard_irOptimized_requested/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_ir_requested/input.json b/test/cmdlineTests/standard_ir_requested/input.json index 37404ddba..cc0a91df9 100644 --- a/test/cmdlineTests/standard_ir_requested/input.json +++ b/test/cmdlineTests/standard_ir_requested/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_method_identifiers_requested/input.json b/test/cmdlineTests/standard_method_identifiers_requested/input.json index 79a3c75d2..c7a770fb4 100644 --- a/test/cmdlineTests/standard_method_identifiers_requested/input.json +++ b/test/cmdlineTests/standard_method_identifiers_requested/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_missing_key_useLiteralContent/input.json b/test/cmdlineTests/standard_missing_key_useLiteralContent/input.json index 8627a282a..459f991b4 100644 --- a/test/cmdlineTests/standard_missing_key_useLiteralContent/input.json +++ b/test/cmdlineTests/standard_missing_key_useLiteralContent/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_only_ast_requested/input.json b/test/cmdlineTests/standard_only_ast_requested/input.json index 7abd6da5f..56409a9a1 100644 --- a/test/cmdlineTests/standard_only_ast_requested/input.json +++ b/test/cmdlineTests/standard_only_ast_requested/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_only_ast_requested/output.json b/test/cmdlineTests/standard_only_ast_requested/output.json index 6ba921abf..c1ffe5892 100644 --- a/test/cmdlineTests/standard_only_ast_requested/output.json +++ b/test/cmdlineTests/standard_only_ast_requested/output.json @@ -1 +1 @@ -{"sources":{"A":{"ast":{"absolutePath":"A","exportedSymbols":{"C":[6]},"id":7,"nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"0:22:0"},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","documentation":null,"fullyImplemented":true,"id":6,"linearizedBaseContracts":[6],"name":"C","nodeType":"ContractDefinition","nodes":[{"body":{"id":4,"nodeType":"Block","src":"61:2:0","statements":[]},"documentation":null,"functionSelector":"26121ff0","id":5,"implemented":true,"kind":"function","modifiers":[],"name":"f","nodeType":"FunctionDefinition","overrides":null,"parameters":{"id":2,"nodeType":"ParameterList","parameters":[],"src":"46:2:0"},"returnParameters":{"id":3,"nodeType":"ParameterList","parameters":[],"src":"61:0:0"},"scope":6,"src":"36:27:0","stateMutability":"pure","virtual":false,"visibility":"public"}],"scope":7,"src":"23:42:0"}],"src":"0:65:0"},"id":0}}} +{"sources":{"A":{"ast":{"absolutePath":"A","exportedSymbols":{"C":[6]},"id":7,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:0"},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","documentation":null,"fullyImplemented":true,"id":6,"linearizedBaseContracts":[6],"name":"C","nodeType":"ContractDefinition","nodes":[{"body":{"id":4,"nodeType":"Block","src":"97:2:0","statements":[]},"documentation":null,"functionSelector":"26121ff0","id":5,"implemented":true,"kind":"function","modifiers":[],"name":"f","nodeType":"FunctionDefinition","overrides":null,"parameters":{"id":2,"nodeType":"ParameterList","parameters":[],"src":"82:2:0"},"returnParameters":{"id":3,"nodeType":"ParameterList","parameters":[],"src":"97:0:0"},"scope":6,"src":"72:27:0","stateMutability":"pure","virtual":false,"visibility":"public"}],"scope":7,"src":"59:42:0"}],"src":"36:65:0"},"id":0}}} diff --git a/test/cmdlineTests/standard_optimizer_invalid_detail_type/input.json b/test/cmdlineTests/standard_optimizer_invalid_detail_type/input.json index f0ce43e37..5e90f6d98 100644 --- a/test/cmdlineTests/standard_optimizer_invalid_detail_type/input.json +++ b/test/cmdlineTests/standard_optimizer_invalid_detail_type/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_optimizer_invalid_details/input.json b/test/cmdlineTests/standard_optimizer_invalid_details/input.json index 850f6f77c..eecfbd5e5 100644 --- a/test/cmdlineTests/standard_optimizer_invalid_details/input.json +++ b/test/cmdlineTests/standard_optimizer_invalid_details/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_optimizer_no_yul/input.json b/test/cmdlineTests/standard_optimizer_no_yul/input.json index 23f14b488..a42299fbe 100644 --- a/test/cmdlineTests/standard_optimizer_no_yul/input.json +++ b/test/cmdlineTests/standard_optimizer_no_yul/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_optimizer_yul/input.json b/test/cmdlineTests/standard_optimizer_yul/input.json index 3cafae03a..5e81a6091 100644 --- a/test/cmdlineTests/standard_optimizer_yul/input.json +++ b/test/cmdlineTests/standard_optimizer_yul/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_optimizer_yulDetails/input.json b/test/cmdlineTests/standard_optimizer_yulDetails/input.json index 5203e64bf..842468bca 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails/input.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_no_object/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_no_object/input.json index 18d3852db..2581aeb71 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_no_object/input.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_no_object/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps/input.json index 00919a864..0dcdab6c2 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps/input.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_abbreviation/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_abbreviation/input.json index 25b3c4bb4..427566764 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_abbreviation/input.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_abbreviation/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nesting/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nesting/input.json index c322913d9..851e132e8 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nesting/input.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_invalid_nesting/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_type/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_type/input.json index c02aa6bb3..11bc9ca62 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_type/input.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_type/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_bracket/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_bracket/input.json index d6e1e0dc7..79c52e6dd 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_bracket/input.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_optimiserSteps_unbalanced_bracket/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_optimizer_yulDetails_without_yul/input.json b/test/cmdlineTests/standard_optimizer_yulDetails_without_yul/input.json index 056aee91b..cac3c068b 100644 --- a/test/cmdlineTests/standard_optimizer_yulDetails_without_yul/input.json +++ b/test/cmdlineTests/standard_optimizer_yulDetails_without_yul/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_secondary_source_location/input.json b/test/cmdlineTests/standard_secondary_source_location/input.json index f08069d9f..0cd6a6126 100644 --- a/test/cmdlineTests/standard_secondary_source_location/input.json +++ b/test/cmdlineTests/standard_secondary_source_location/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract A { constructor(uint) public {} } contract B is A(2) { } contract C is A(3) {} contract D is B, C {}" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract A { constructor(uint) public {} } contract B is A(2) { } contract C is A(3) {} contract D is B, C {}" } } } diff --git a/test/cmdlineTests/standard_secondary_source_location/output.json b/test/cmdlineTests/standard_secondary_source_location/output.json index 0330135e2..d9f56b80d 100644 --- a/test/cmdlineTests/standard_secondary_source_location/output.json +++ b/test/cmdlineTests/standard_secondary_source_location/output.json @@ -1,10 +1,10 @@ -{"errors":[{"component":"general","formattedMessage":"A:1:112: DeclarationError: Base constructor arguments given twice. +{"errors":[{"component":"general","formattedMessage":"A:2:112: DeclarationError: Base constructor arguments given twice. pragma solidity >=0.0; contract A { constructor(uint) public {} } contract B is A(2) { } contract C is A(3) {} contract D is B, C {} ^-------------------^ -A:1:81: First constructor call is here: +A:2:81: First constructor call is here: pragma solidity >=0.0; contract A { constructor(uint) public {} } contract B is A(2) { } contract C is A(3) {} contract D is B, C {} ^--^ -A:1:104: Second constructor call is here: +A:2:104: Second constructor call is here: pragma solidity >=0.0; contract A { constructor(uint) public {} } contract B is A(2) { } contract C is A(3) {} contract D is B, C {} ^--^ -","message":"Base constructor arguments given twice.","secondarySourceLocations":[{"end":84,"file":"A","message":"First constructor call is here:","start":80},{"end":107,"file":"A","message":"Second constructor call is here:","start":103}],"severity":"error","sourceLocation":{"end":132,"file":"A","start":111},"type":"DeclarationError"}],"sources":{}} +","message":"Base constructor arguments given twice.","secondarySourceLocations":[{"end":119,"file":"A","message":"First constructor call is here:","start":115},{"end":142,"file":"A","message":"Second constructor call is here:","start":138}],"severity":"error","sourceLocation":{"end":167,"file":"A","start":146},"type":"DeclarationError"}],"sources":{}} diff --git a/test/cmdlineTests/standard_wrong_key_auxiliary_input/input.json b/test/cmdlineTests/standard_wrong_key_auxiliary_input/input.json index 51dbce41a..0843460ed 100644 --- a/test/cmdlineTests/standard_wrong_key_auxiliary_input/input.json +++ b/test/cmdlineTests/standard_wrong_key_auxiliary_input/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "auxiliaryInput": diff --git a/test/cmdlineTests/standard_wrong_key_metadata/input.json b/test/cmdlineTests/standard_wrong_key_metadata/input.json index 490e489a2..a52d45004 100644 --- a/test/cmdlineTests/standard_wrong_key_metadata/input.json +++ b/test/cmdlineTests/standard_wrong_key_metadata/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_wrong_key_optimizer/input.json b/test/cmdlineTests/standard_wrong_key_optimizer/input.json index c28c3a92d..945c1e346 100644 --- a/test/cmdlineTests/standard_wrong_key_optimizer/input.json +++ b/test/cmdlineTests/standard_wrong_key_optimizer/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_wrong_key_root/input.json b/test/cmdlineTests/standard_wrong_key_root/input.json index 4689c50c0..2fb1a656b 100644 --- a/test/cmdlineTests/standard_wrong_key_root/input.json +++ b/test/cmdlineTests/standard_wrong_key_root/input.json @@ -5,7 +5,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } } } diff --git a/test/cmdlineTests/standard_wrong_key_settings/input.json b/test/cmdlineTests/standard_wrong_key_settings/input.json index d7809b1c8..8f0e1d06b 100644 --- a/test/cmdlineTests/standard_wrong_key_settings/input.json +++ b/test/cmdlineTests/standard_wrong_key_settings/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_wrong_key_source/input.json b/test/cmdlineTests/standard_wrong_key_source/input.json index d8a8aa16f..f4b0f560a 100644 --- a/test/cmdlineTests/standard_wrong_key_source/input.json +++ b/test/cmdlineTests/standard_wrong_key_source/input.json @@ -5,7 +5,7 @@ "A": { "key1": "test", - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } } } diff --git a/test/cmdlineTests/standard_wrong_type_auxiliary_input/input.json b/test/cmdlineTests/standard_wrong_type_auxiliary_input/input.json index 8d2c75931..895aa80ee 100644 --- a/test/cmdlineTests/standard_wrong_type_auxiliary_input/input.json +++ b/test/cmdlineTests/standard_wrong_type_auxiliary_input/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "auxiliaryInput": [1, 2, 3] diff --git a/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses/input.json b/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses/input.json index 9175050fd..46090f7e3 100644 --- a/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses/input.json +++ b/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { }" } }, "settings": { diff --git a/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses_member/input.json b/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses_member/input.json index aa7d451b1..96ca950b1 100644 --- a/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses_member/input.json +++ b/test/cmdlineTests/standard_wrong_type_auxiliary_input_smtlib2responses_member/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { }" } }, "settings": { diff --git a/test/cmdlineTests/standard_wrong_type_metadata/input.json b/test/cmdlineTests/standard_wrong_type_metadata/input.json index d4dd06a1f..0d459ef37 100644 --- a/test/cmdlineTests/standard_wrong_type_metadata/input.json +++ b/test/cmdlineTests/standard_wrong_type_metadata/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_wrong_type_optimizer/input.json b/test/cmdlineTests/standard_wrong_type_optimizer/input.json index b42ca550a..f623628e9 100644 --- a/test/cmdlineTests/standard_wrong_type_optimizer/input.json +++ b/test/cmdlineTests/standard_wrong_type_optimizer/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_wrong_type_output_selection/input.json b/test/cmdlineTests/standard_wrong_type_output_selection/input.json index a7b615d1c..5f03fbf7b 100644 --- a/test/cmdlineTests/standard_wrong_type_output_selection/input.json +++ b/test/cmdlineTests/standard_wrong_type_output_selection/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { }" } }, "settings": { diff --git a/test/cmdlineTests/standard_wrong_type_output_selection_contract/input.json b/test/cmdlineTests/standard_wrong_type_output_selection_contract/input.json index 9840a97e5..4004b2285 100644 --- a/test/cmdlineTests/standard_wrong_type_output_selection_contract/input.json +++ b/test/cmdlineTests/standard_wrong_type_output_selection_contract/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { }" } }, "settings": { diff --git a/test/cmdlineTests/standard_wrong_type_output_selection_file/input.json b/test/cmdlineTests/standard_wrong_type_output_selection_file/input.json index 7ab12ba8b..9bfdb99ad 100644 --- a/test/cmdlineTests/standard_wrong_type_output_selection_file/input.json +++ b/test/cmdlineTests/standard_wrong_type_output_selection_file/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { }" } }, "settings": { diff --git a/test/cmdlineTests/standard_wrong_type_output_selection_output/input.json b/test/cmdlineTests/standard_wrong_type_output_selection_output/input.json index 3e5cd6618..d5c51fa93 100644 --- a/test/cmdlineTests/standard_wrong_type_output_selection_output/input.json +++ b/test/cmdlineTests/standard_wrong_type_output_selection_output/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { }" } }, "settings": { diff --git a/test/cmdlineTests/standard_wrong_type_remappings/input.json b/test/cmdlineTests/standard_wrong_type_remappings/input.json index 1436e0147..4d64b9e47 100644 --- a/test/cmdlineTests/standard_wrong_type_remappings/input.json +++ b/test/cmdlineTests/standard_wrong_type_remappings/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { }" } }, "settings": { diff --git a/test/cmdlineTests/standard_wrong_type_remappings_entry/input.json b/test/cmdlineTests/standard_wrong_type_remappings_entry/input.json index c96611f3e..ee7fb52fa 100644 --- a/test/cmdlineTests/standard_wrong_type_remappings_entry/input.json +++ b/test/cmdlineTests/standard_wrong_type_remappings_entry/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { }" } }, "settings": { diff --git a/test/cmdlineTests/standard_wrong_type_settings/input.json b/test/cmdlineTests/standard_wrong_type_settings/input.json index 7cdb0881c..638f57a76 100644 --- a/test/cmdlineTests/standard_wrong_type_settings/input.json +++ b/test/cmdlineTests/standard_wrong_type_settings/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/standard_wrong_type_source/input.json b/test/cmdlineTests/standard_wrong_type_source/input.json index d58504fe0..f8c72996b 100644 --- a/test/cmdlineTests/standard_wrong_type_source/input.json +++ b/test/cmdlineTests/standard_wrong_type_source/input.json @@ -6,7 +6,7 @@ "B": [1, 2, 3], "C": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } } } diff --git a/test/cmdlineTests/standard_wrong_type_useLiteralContent/input.json b/test/cmdlineTests/standard_wrong_type_useLiteralContent/input.json index be4272b6c..b96a17564 100644 --- a/test/cmdlineTests/standard_wrong_type_useLiteralContent/input.json +++ b/test/cmdlineTests/standard_wrong_type_useLiteralContent/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() public pure {} }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() public pure {} }" } }, "settings": diff --git a/test/cmdlineTests/storage_layout_bytes/input.json b/test/cmdlineTests/storage_layout_bytes/input.json index fe1468c53..cd69dd0ed 100644 --- a/test/cmdlineTests/storage_layout_bytes/input.json +++ b/test/cmdlineTests/storage_layout_bytes/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { bytes s1 = \"test\"; bytes s2; }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { bytes s1 = \"test\"; bytes s2; }" } }, "settings": { diff --git a/test/cmdlineTests/storage_layout_dyn_array/input.json b/test/cmdlineTests/storage_layout_dyn_array/input.json index 64ab3e20b..2904a9cef 100644 --- a/test/cmdlineTests/storage_layout_dyn_array/input.json +++ b/test/cmdlineTests/storage_layout_dyn_array/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { uint[] array1; bool[] array2; }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { uint[] array1; bool[] array2; }" } }, "settings": { diff --git a/test/cmdlineTests/storage_layout_many/input.json b/test/cmdlineTests/storage_layout_many/input.json index 7ea41f211..90b4e25dd 100644 --- a/test/cmdlineTests/storage_layout_many/input.json +++ b/test/cmdlineTests/storage_layout_many/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { struct S { uint128 a; uint128 b; uint[2] staticArray; uint[] dynArray; } uint x; uint y; S s; address addr; mapping (uint => mapping (address => bool)) map; uint[] array; string s1; bytes b1; }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { struct S { uint128 a; uint128 b; uint[2] staticArray; uint[] dynArray; } uint x; uint y; S s; address addr; mapping (uint => mapping (address => bool)) map; uint[] array; string s1; bytes b1; }" } }, "settings": { diff --git a/test/cmdlineTests/storage_layout_mapping/input.json b/test/cmdlineTests/storage_layout_mapping/input.json index 6292391d5..66ecff537 100644 --- a/test/cmdlineTests/storage_layout_mapping/input.json +++ b/test/cmdlineTests/storage_layout_mapping/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { uint x; uint y; mapping (uint => mapping (address => bool)) map; }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { uint x; uint y; mapping (uint => mapping (address => bool)) map; }" } }, "settings": { diff --git a/test/cmdlineTests/storage_layout_smoke/input.json b/test/cmdlineTests/storage_layout_smoke/input.json index 47722e759..90fd18101 100644 --- a/test/cmdlineTests/storage_layout_smoke/input.json +++ b/test/cmdlineTests/storage_layout_smoke/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { }" } }, "settings": { diff --git a/test/cmdlineTests/storage_layout_smoke_two_contracts/input.json b/test/cmdlineTests/storage_layout_smoke_two_contracts/input.json index b31f3dd9d..15cb774f5 100644 --- a/test/cmdlineTests/storage_layout_smoke_two_contracts/input.json +++ b/test/cmdlineTests/storage_layout_smoke_two_contracts/input.json @@ -2,10 +2,10 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { }" }, "fileB": { - "content": "contract A { uint x; uint y; }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { uint x; uint y; }" } }, "settings": { diff --git a/test/cmdlineTests/storage_layout_string/input.json b/test/cmdlineTests/storage_layout_string/input.json index 834617b3a..d069d3098 100644 --- a/test/cmdlineTests/storage_layout_string/input.json +++ b/test/cmdlineTests/storage_layout_string/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { string s1 = \"test\"; string s2; }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { string s1 = \"test\"; string s2; }" } }, "settings": { diff --git a/test/cmdlineTests/storage_layout_struct/input.json b/test/cmdlineTests/storage_layout_struct/input.json index 31ab020cf..7353386df 100644 --- a/test/cmdlineTests/storage_layout_struct/input.json +++ b/test/cmdlineTests/storage_layout_struct/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { struct S { uint a; uint b; uint[2] staticArray; uint[] dynArray; } uint x; uint y; S s; address addr; }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { struct S { uint a; uint b; uint[2] staticArray; uint[] dynArray; } uint x; uint y; S s; address addr; }" } }, "settings": { diff --git a/test/cmdlineTests/storage_layout_struct_packed/input.json b/test/cmdlineTests/storage_layout_struct_packed/input.json index 80c706c7b..e562a6a3a 100644 --- a/test/cmdlineTests/storage_layout_struct_packed/input.json +++ b/test/cmdlineTests/storage_layout_struct_packed/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { struct S { uint128 a; uint128 b; uint[2] staticArray; uint[] dynArray; } uint x; uint y; S s; address addr; }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { struct S { uint128 a; uint128 b; uint[2] staticArray; uint[] dynArray; } uint x; uint y; S s; address addr; }" } }, "settings": { diff --git a/test/cmdlineTests/storage_layout_value_types/input.json b/test/cmdlineTests/storage_layout_value_types/input.json index 1477dde08..3f0dd709c 100644 --- a/test/cmdlineTests/storage_layout_value_types/input.json +++ b/test/cmdlineTests/storage_layout_value_types/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { uint x; uint y; address addr; uint[2] array; }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { uint x; uint y; address addr; uint[2] array; }" } }, "settings": { diff --git a/test/cmdlineTests/storage_layout_value_types_packed/input.json b/test/cmdlineTests/storage_layout_value_types_packed/input.json index 04a7bd3bf..18af8f50f 100644 --- a/test/cmdlineTests/storage_layout_value_types_packed/input.json +++ b/test/cmdlineTests/storage_layout_value_types_packed/input.json @@ -2,7 +2,7 @@ "language": "Solidity", "sources": { "fileA": { - "content": "contract A { uint64 x; uint128 y; uint128 z; address addr; uint[2] array; }" + "content": "//SPDX-License-Identifier: GPL-3.0\ncontract A { uint64 x; uint128 y; uint128 z; address addr; uint[2] array; }" } }, "settings": { diff --git a/test/cmdlineTests/structured_documentation_source_location/err b/test/cmdlineTests/structured_documentation_source_location/err index 1081fdaa8..1f69adf4f 100644 --- a/test/cmdlineTests/structured_documentation_source_location/err +++ b/test/cmdlineTests/structured_documentation_source_location/err @@ -1,11 +1,11 @@ Error: Documentation tag "@return No value returned" does not contain the name of its return parameter. - --> structured_documentation_source_location/input.sol:3:5: + --> structured_documentation_source_location/input.sol:4:5: | -3 | /// @param id Some identifier +4 | /// @param id Some identifier | ^ (Relevant source part starts here and spans across multiple lines). Error: Documentation tag "@return No value returned" does not contain the name of its return parameter. - --> structured_documentation_source_location/input.sol:7:5: + --> structured_documentation_source_location/input.sol:8:5: | -7 | /// @return No value returned +8 | /// @return No value returned | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/test/cmdlineTests/structured_documentation_source_location/input.sol b/test/cmdlineTests/structured_documentation_source_location/input.sol index ceec13547..399c2b8b8 100644 --- a/test/cmdlineTests/structured_documentation_source_location/input.sol +++ b/test/cmdlineTests/structured_documentation_source_location/input.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 pragma solidity >= 0.0; abstract contract C { /// @param id Some identifier diff --git a/test/cmdlineTests/too_long_line/err b/test/cmdlineTests/too_long_line/err index 6e5119037..802cac3cb 100644 --- a/test/cmdlineTests/too_long_line/err +++ b/test/cmdlineTests/too_long_line/err @@ -1,3 +1,6 @@ +Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +--> too_long_line/input.sol + Warning: Source file does not specify required compiler version! --> too_long_line/input.sol diff --git a/test/cmdlineTests/too_long_line_both_sides_short/err b/test/cmdlineTests/too_long_line_both_sides_short/err index 34bd25d28..131fab209 100644 --- a/test/cmdlineTests/too_long_line_both_sides_short/err +++ b/test/cmdlineTests/too_long_line_both_sides_short/err @@ -1,3 +1,6 @@ +Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +--> too_long_line_both_sides_short/input.sol + Warning: Source file does not specify required compiler version! --> too_long_line_both_sides_short/input.sol diff --git a/test/cmdlineTests/too_long_line_edge_in/err b/test/cmdlineTests/too_long_line_edge_in/err index 2988bc44e..83cd670e1 100644 --- a/test/cmdlineTests/too_long_line_edge_in/err +++ b/test/cmdlineTests/too_long_line_edge_in/err @@ -1,3 +1,6 @@ +Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +--> too_long_line_edge_in/input.sol + Warning: Source file does not specify required compiler version! --> too_long_line_edge_in/input.sol diff --git a/test/cmdlineTests/too_long_line_edge_out/err b/test/cmdlineTests/too_long_line_edge_out/err index a85faa44f..7d3b54f21 100644 --- a/test/cmdlineTests/too_long_line_edge_out/err +++ b/test/cmdlineTests/too_long_line_edge_out/err @@ -1,3 +1,6 @@ +Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +--> too_long_line_edge_out/input.sol + Warning: Source file does not specify required compiler version! --> too_long_line_edge_out/input.sol diff --git a/test/cmdlineTests/too_long_line_left_short/err b/test/cmdlineTests/too_long_line_left_short/err index aa36b1068..0f8c70e5a 100644 --- a/test/cmdlineTests/too_long_line_left_short/err +++ b/test/cmdlineTests/too_long_line_left_short/err @@ -1,3 +1,6 @@ +Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +--> too_long_line_left_short/input.sol + Warning: Source file does not specify required compiler version! --> too_long_line_left_short/input.sol diff --git a/test/cmdlineTests/too_long_line_multiline/err b/test/cmdlineTests/too_long_line_multiline/err index 2aa801623..6d8114ca8 100644 --- a/test/cmdlineTests/too_long_line_multiline/err +++ b/test/cmdlineTests/too_long_line_multiline/err @@ -1,3 +1,6 @@ +Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +--> too_long_line_multiline/input.sol + Error: No visibility specified. Did you intend to add "public"? --> too_long_line_multiline/input.sol:2:5: | diff --git a/test/cmdlineTests/too_long_line_right_short/err b/test/cmdlineTests/too_long_line_right_short/err index d2d8f3980..6837dd8ab 100644 --- a/test/cmdlineTests/too_long_line_right_short/err +++ b/test/cmdlineTests/too_long_line_right_short/err @@ -1,3 +1,6 @@ +Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +--> too_long_line_right_short/input.sol + Warning: Source file does not specify required compiler version! --> too_long_line_right_short/input.sol diff --git a/test/cmdlineTests/yul_optimizer_steps/input.sol b/test/cmdlineTests/yul_optimizer_steps/input.sol index f787d2fcf..a75662b25 100644 --- a/test/cmdlineTests/yul_optimizer_steps/input.sol +++ b/test/cmdlineTests/yul_optimizer_steps/input.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.0; contract C diff --git a/test/cmdlineTests/yul_optimizer_steps_disabled/input.sol b/test/cmdlineTests/yul_optimizer_steps_disabled/input.sol index 363a4c721..6923ca702 100644 --- a/test/cmdlineTests/yul_optimizer_steps_disabled/input.sol +++ b/test/cmdlineTests/yul_optimizer_steps_disabled/input.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.0; contract C diff --git a/test/cmdlineTests/yul_optimizer_steps_invalid_abbreviation/input.sol b/test/cmdlineTests/yul_optimizer_steps_invalid_abbreviation/input.sol index 363a4c721..6923ca702 100644 --- a/test/cmdlineTests/yul_optimizer_steps_invalid_abbreviation/input.sol +++ b/test/cmdlineTests/yul_optimizer_steps_invalid_abbreviation/input.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.0; contract C diff --git a/test/cmdlineTests/yul_optimizer_steps_invalid_nesting/input.sol b/test/cmdlineTests/yul_optimizer_steps_invalid_nesting/input.sol index 363a4c721..6923ca702 100644 --- a/test/cmdlineTests/yul_optimizer_steps_invalid_nesting/input.sol +++ b/test/cmdlineTests/yul_optimizer_steps_invalid_nesting/input.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.0; contract C diff --git a/test/cmdlineTests/yul_optimizer_steps_unbalanced_bracket/input.sol b/test/cmdlineTests/yul_optimizer_steps_unbalanced_bracket/input.sol index 363a4c721..6923ca702 100644 --- a/test/cmdlineTests/yul_optimizer_steps_unbalanced_bracket/input.sol +++ b/test/cmdlineTests/yul_optimizer_steps_unbalanced_bracket/input.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.0; contract C diff --git a/test/cmdlineTests/yul_string_format_ascii/input.json b/test/cmdlineTests/yul_string_format_ascii/input.json index c23c65b5a..0eba555c9 100644 --- a/test/cmdlineTests/yul_string_format_ascii/input.json +++ b/test/cmdlineTests/yul_string_format_ascii/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() external pure returns (string memory) { return \"abcabc\"; } }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() external pure returns (string memory) { return \"abcabc\"; } }" } }, "settings": diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32/input.json b/test/cmdlineTests/yul_string_format_ascii_bytes32/input.json index 247f665cb..3dbcdb819 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32/input.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() external pure returns (bytes32) { return \"abcabc\"; } }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() external pure returns (bytes32) { return \"abcabc\"; } }" } }, "settings": diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/input.json b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/input.json index c7309f2af..003dddfa7 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/input.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() external pure returns (bytes4) { return 0x61626364; } }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() external pure returns (bytes4) { return 0x61626364; } }" } }, "settings": diff --git a/test/cmdlineTests/yul_string_format_ascii_long/input.json b/test/cmdlineTests/yul_string_format_ascii_long/input.json index cf3b2a854..5d91e402e 100644 --- a/test/cmdlineTests/yul_string_format_ascii_long/input.json +++ b/test/cmdlineTests/yul_string_format_ascii_long/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() external pure returns (string memory) { return \"abcdabcdcafecafeabcdabcdcafecafeffffzzzzoooo0123456789,.<,>.?:;'[{]}|`~!@#$%^&*()-_=+\"; } }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() external pure returns (string memory) { return \"abcdabcdcafecafeabcdabcdcafecafeffffzzzzoooo0123456789,.<,>.?:;'[{]}|`~!@#$%^&*()-_=+\"; } }" } }, "settings": diff --git a/test/cmdlineTests/yul_string_format_hex/input.json b/test/cmdlineTests/yul_string_format_hex/input.json index 5ba723f56..9bb3fd138 100644 --- a/test/cmdlineTests/yul_string_format_hex/input.json +++ b/test/cmdlineTests/yul_string_format_hex/input.json @@ -4,7 +4,7 @@ { "A": { - "content": "pragma solidity >=0.0; contract C { function f() external pure returns (bytes4) { return 0xaabbccdd; } }" + "content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { function f() external pure returns (bytes4) { return 0xaabbccdd; } }" } }, "settings": diff --git a/test/libsolidity/ASTJSON/abstract_contract.json b/test/libsolidity/ASTJSON/abstract_contract.json index da9fd1196..32b414e8a 100644 --- a/test/libsolidity/ASTJSON/abstract_contract.json +++ b/test/libsolidity/ASTJSON/abstract_contract.json @@ -8,6 +8,7 @@ ] }, "id": 6, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/abstract_contract_legacy.json b/test/libsolidity/ASTJSON/abstract_contract_legacy.json index 66d1c0e8b..13f046eec 100644 --- a/test/libsolidity/ASTJSON/abstract_contract_legacy.json +++ b/test/libsolidity/ASTJSON/abstract_contract_legacy.json @@ -8,7 +8,8 @@ [ 5 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/address_payable.json b/test/libsolidity/ASTJSON/address_payable.json index ef965ac79..a82fa0b82 100644 --- a/test/libsolidity/ASTJSON/address_payable.json +++ b/test/libsolidity/ASTJSON/address_payable.json @@ -8,6 +8,7 @@ ] }, "id": 40, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/address_payable_legacy.json b/test/libsolidity/ASTJSON/address_payable_legacy.json index dd33e6408..7fe404f3e 100644 --- a/test/libsolidity/ASTJSON/address_payable_legacy.json +++ b/test/libsolidity/ASTJSON/address_payable_legacy.json @@ -8,7 +8,8 @@ [ 39 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/array_type_name.json b/test/libsolidity/ASTJSON/array_type_name.json index e97518cb8..a09bc306a 100644 --- a/test/libsolidity/ASTJSON/array_type_name.json +++ b/test/libsolidity/ASTJSON/array_type_name.json @@ -8,6 +8,7 @@ ] }, "id": 5, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/array_type_name_legacy.json b/test/libsolidity/ASTJSON/array_type_name_legacy.json index 37175bb37..cc1c7a77a 100644 --- a/test/libsolidity/ASTJSON/array_type_name_legacy.json +++ b/test/libsolidity/ASTJSON/array_type_name_legacy.json @@ -8,7 +8,8 @@ [ 4 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/assembly/call.json b/test/libsolidity/ASTJSON/assembly/call.json index 1c2a4bf7e..ad81c1094 100644 --- a/test/libsolidity/ASTJSON/assembly/call.json +++ b/test/libsolidity/ASTJSON/assembly/call.json @@ -8,6 +8,7 @@ ] }, "id": 7, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/assembly/call_legacy.json b/test/libsolidity/ASTJSON/assembly/call_legacy.json index 619d132bc..93ad1b956 100644 --- a/test/libsolidity/ASTJSON/assembly/call_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/call_legacy.json @@ -8,7 +8,8 @@ [ 6 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/assembly/empty_block.json b/test/libsolidity/ASTJSON/assembly/empty_block.json index 575b1f7f4..847fd4085 100644 --- a/test/libsolidity/ASTJSON/assembly/empty_block.json +++ b/test/libsolidity/ASTJSON/assembly/empty_block.json @@ -8,6 +8,7 @@ ] }, "id": 7, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/assembly/empty_block_legacy.json b/test/libsolidity/ASTJSON/assembly/empty_block_legacy.json index 108a76a00..74d24d5e1 100644 --- a/test/libsolidity/ASTJSON/assembly/empty_block_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/empty_block_legacy.json @@ -8,7 +8,8 @@ [ 6 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/assembly/function.json b/test/libsolidity/ASTJSON/assembly/function.json index 7e9895261..6bd37162d 100644 --- a/test/libsolidity/ASTJSON/assembly/function.json +++ b/test/libsolidity/ASTJSON/assembly/function.json @@ -8,6 +8,7 @@ ] }, "id": 7, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/assembly/function_legacy.json b/test/libsolidity/ASTJSON/assembly/function_legacy.json index 163d8d05a..ee6918d25 100644 --- a/test/libsolidity/ASTJSON/assembly/function_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/function_legacy.json @@ -8,7 +8,8 @@ [ 6 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/assembly/leave.json b/test/libsolidity/ASTJSON/assembly/leave.json index c8ef5eaee..5868c1acb 100644 --- a/test/libsolidity/ASTJSON/assembly/leave.json +++ b/test/libsolidity/ASTJSON/assembly/leave.json @@ -8,6 +8,7 @@ ] }, "id": 7, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/assembly/leave_legacy.json b/test/libsolidity/ASTJSON/assembly/leave_legacy.json index 35ce02f55..2c39fba37 100644 --- a/test/libsolidity/ASTJSON/assembly/leave_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/leave_legacy.json @@ -8,7 +8,8 @@ [ 6 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/assembly/loop.json b/test/libsolidity/ASTJSON/assembly/loop.json index b815da447..263db400d 100644 --- a/test/libsolidity/ASTJSON/assembly/loop.json +++ b/test/libsolidity/ASTJSON/assembly/loop.json @@ -8,6 +8,7 @@ ] }, "id": 7, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/assembly/loop_legacy.json b/test/libsolidity/ASTJSON/assembly/loop_legacy.json index cf4095dd8..5085e4c50 100644 --- a/test/libsolidity/ASTJSON/assembly/loop_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/loop_legacy.json @@ -8,7 +8,8 @@ [ 6 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/assembly/nested_functions.json b/test/libsolidity/ASTJSON/assembly/nested_functions.json index f52cbfc08..5abb7fce4 100644 --- a/test/libsolidity/ASTJSON/assembly/nested_functions.json +++ b/test/libsolidity/ASTJSON/assembly/nested_functions.json @@ -8,6 +8,7 @@ ] }, "id": 9, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/assembly/nested_functions_legacy.json b/test/libsolidity/ASTJSON/assembly/nested_functions_legacy.json index c0164e3f7..0ccfcf85a 100644 --- a/test/libsolidity/ASTJSON/assembly/nested_functions_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/nested_functions_legacy.json @@ -8,7 +8,8 @@ [ 8 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/assembly/slot_offset.json b/test/libsolidity/ASTJSON/assembly/slot_offset.json index 75c22243c..7231747c4 100644 --- a/test/libsolidity/ASTJSON/assembly/slot_offset.json +++ b/test/libsolidity/ASTJSON/assembly/slot_offset.json @@ -8,6 +8,7 @@ ] }, "id": 12, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/assembly/slot_offset_legacy.json b/test/libsolidity/ASTJSON/assembly/slot_offset_legacy.json index 083f8dd52..574c7ad75 100644 --- a/test/libsolidity/ASTJSON/assembly/slot_offset_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/slot_offset_legacy.json @@ -8,7 +8,8 @@ [ 11 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/assembly/stringlit.json b/test/libsolidity/ASTJSON/assembly/stringlit.json index a7a596e0c..7fd0b9b84 100644 --- a/test/libsolidity/ASTJSON/assembly/stringlit.json +++ b/test/libsolidity/ASTJSON/assembly/stringlit.json @@ -8,6 +8,7 @@ ] }, "id": 7, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/assembly/stringlit_legacy.json b/test/libsolidity/ASTJSON/assembly/stringlit_legacy.json index bb7a5c5c3..76c503925 100644 --- a/test/libsolidity/ASTJSON/assembly/stringlit_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/stringlit_legacy.json @@ -8,7 +8,8 @@ [ 6 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/assembly/switch.json b/test/libsolidity/ASTJSON/assembly/switch.json index 854c5b6cd..61b462f1e 100644 --- a/test/libsolidity/ASTJSON/assembly/switch.json +++ b/test/libsolidity/ASTJSON/assembly/switch.json @@ -8,6 +8,7 @@ ] }, "id": 7, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/assembly/switch_default.json b/test/libsolidity/ASTJSON/assembly/switch_default.json index c0bf26438..2f15a82c5 100644 --- a/test/libsolidity/ASTJSON/assembly/switch_default.json +++ b/test/libsolidity/ASTJSON/assembly/switch_default.json @@ -8,6 +8,7 @@ ] }, "id": 7, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/assembly/switch_default_legacy.json b/test/libsolidity/ASTJSON/assembly/switch_default_legacy.json index 2d5caa0fa..18e7c860c 100644 --- a/test/libsolidity/ASTJSON/assembly/switch_default_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/switch_default_legacy.json @@ -8,7 +8,8 @@ [ 6 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/assembly/switch_legacy.json b/test/libsolidity/ASTJSON/assembly/switch_legacy.json index 5b9322f4c..dab33b305 100644 --- a/test/libsolidity/ASTJSON/assembly/switch_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/switch_legacy.json @@ -8,7 +8,8 @@ [ 6 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/assembly/var_access.json b/test/libsolidity/ASTJSON/assembly/var_access.json index 0ef180ced..c44940a28 100644 --- a/test/libsolidity/ASTJSON/assembly/var_access.json +++ b/test/libsolidity/ASTJSON/assembly/var_access.json @@ -8,6 +8,7 @@ ] }, "id": 10, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/assembly/var_access_legacy.json b/test/libsolidity/ASTJSON/assembly/var_access_legacy.json index 21cda71e8..a80a24613 100644 --- a/test/libsolidity/ASTJSON/assembly/var_access_legacy.json +++ b/test/libsolidity/ASTJSON/assembly/var_access_legacy.json @@ -8,7 +8,8 @@ [ 9 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/constructor.json b/test/libsolidity/ASTJSON/constructor.json index 5e6059b29..321d93471 100644 --- a/test/libsolidity/ASTJSON/constructor.json +++ b/test/libsolidity/ASTJSON/constructor.json @@ -8,6 +8,7 @@ ] }, "id": 6, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/constructor_legacy.json b/test/libsolidity/ASTJSON/constructor_legacy.json index 53265f711..9417561a7 100644 --- a/test/libsolidity/ASTJSON/constructor_legacy.json +++ b/test/libsolidity/ASTJSON/constructor_legacy.json @@ -8,7 +8,8 @@ [ 5 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/contract_dep_order.json b/test/libsolidity/ASTJSON/contract_dep_order.json index 6b269800f..b4a93ff75 100644 --- a/test/libsolidity/ASTJSON/contract_dep_order.json +++ b/test/libsolidity/ASTJSON/contract_dep_order.json @@ -24,6 +24,7 @@ ] }, "id": 14, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/contract_dep_order_legacy.json b/test/libsolidity/ASTJSON/contract_dep_order_legacy.json index 11ccbed7a..75ac151e8 100644 --- a/test/libsolidity/ASTJSON/contract_dep_order_legacy.json +++ b/test/libsolidity/ASTJSON/contract_dep_order_legacy.json @@ -24,7 +24,8 @@ [ 13 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/documentation.json b/test/libsolidity/ASTJSON/documentation.json index 8671978b0..782409abf 100644 --- a/test/libsolidity/ASTJSON/documentation.json +++ b/test/libsolidity/ASTJSON/documentation.json @@ -8,6 +8,7 @@ ] }, "id": 3, + "license": null, "nodeType": "SourceUnit", "nodes": [ @@ -48,6 +49,7 @@ ] }, "id": 6, + "license": null, "nodeType": "SourceUnit", "nodes": [ @@ -88,6 +90,7 @@ ] }, "id": 21, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/documentation_legacy.json b/test/libsolidity/ASTJSON/documentation_legacy.json index 90866e7fb..70a4d8cf4 100644 --- a/test/libsolidity/ASTJSON/documentation_legacy.json +++ b/test/libsolidity/ASTJSON/documentation_legacy.json @@ -8,7 +8,8 @@ [ 20 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/enum_value.json b/test/libsolidity/ASTJSON/enum_value.json index 981b54210..bb8e1289b 100644 --- a/test/libsolidity/ASTJSON/enum_value.json +++ b/test/libsolidity/ASTJSON/enum_value.json @@ -8,6 +8,7 @@ ] }, "id": 5, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/enum_value_legacy.json b/test/libsolidity/ASTJSON/enum_value_legacy.json index 0c1c0b8e2..eeff347d7 100644 --- a/test/libsolidity/ASTJSON/enum_value_legacy.json +++ b/test/libsolidity/ASTJSON/enum_value_legacy.json @@ -8,7 +8,8 @@ [ 4 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/event_definition.json b/test/libsolidity/ASTJSON/event_definition.json index e58a6b843..e5c574973 100644 --- a/test/libsolidity/ASTJSON/event_definition.json +++ b/test/libsolidity/ASTJSON/event_definition.json @@ -8,6 +8,7 @@ ] }, "id": 4, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/event_definition_legacy.json b/test/libsolidity/ASTJSON/event_definition_legacy.json index 30dfb7069..330f586ae 100644 --- a/test/libsolidity/ASTJSON/event_definition_legacy.json +++ b/test/libsolidity/ASTJSON/event_definition_legacy.json @@ -8,7 +8,8 @@ [ 3 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/fallback.json b/test/libsolidity/ASTJSON/fallback.json index 128888701..7c83f871f 100644 --- a/test/libsolidity/ASTJSON/fallback.json +++ b/test/libsolidity/ASTJSON/fallback.json @@ -8,6 +8,7 @@ ] }, "id": 6, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/fallback_and_reveice_ether.json b/test/libsolidity/ASTJSON/fallback_and_reveice_ether.json index 353d512f7..801a4e148 100644 --- a/test/libsolidity/ASTJSON/fallback_and_reveice_ether.json +++ b/test/libsolidity/ASTJSON/fallback_and_reveice_ether.json @@ -8,6 +8,7 @@ ] }, "id": 10, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/fallback_and_reveice_ether_legacy.json b/test/libsolidity/ASTJSON/fallback_and_reveice_ether_legacy.json index 7d1aa7ae4..44e02c42d 100644 --- a/test/libsolidity/ASTJSON/fallback_and_reveice_ether_legacy.json +++ b/test/libsolidity/ASTJSON/fallback_and_reveice_ether_legacy.json @@ -8,7 +8,8 @@ [ 9 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/fallback_legacy.json b/test/libsolidity/ASTJSON/fallback_legacy.json index 8c84c57fc..8c81e87d8 100644 --- a/test/libsolidity/ASTJSON/fallback_legacy.json +++ b/test/libsolidity/ASTJSON/fallback_legacy.json @@ -8,7 +8,8 @@ [ 5 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/fallback_payable.json b/test/libsolidity/ASTJSON/fallback_payable.json index 8facda351..fb55b6077 100644 --- a/test/libsolidity/ASTJSON/fallback_payable.json +++ b/test/libsolidity/ASTJSON/fallback_payable.json @@ -8,6 +8,7 @@ ] }, "id": 6, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/fallback_payable_legacy.json b/test/libsolidity/ASTJSON/fallback_payable_legacy.json index 74e4242fd..2bc5a9659 100644 --- a/test/libsolidity/ASTJSON/fallback_payable_legacy.json +++ b/test/libsolidity/ASTJSON/fallback_payable_legacy.json @@ -8,7 +8,8 @@ [ 5 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/function_type.json b/test/libsolidity/ASTJSON/function_type.json index e1e83a316..57f061b39 100644 --- a/test/libsolidity/ASTJSON/function_type.json +++ b/test/libsolidity/ASTJSON/function_type.json @@ -8,6 +8,7 @@ ] }, "id": 18, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/function_type_legacy.json b/test/libsolidity/ASTJSON/function_type_legacy.json index e86eb16a6..799e94bf9 100644 --- a/test/libsolidity/ASTJSON/function_type_legacy.json +++ b/test/libsolidity/ASTJSON/function_type_legacy.json @@ -8,7 +8,8 @@ [ 17 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/global_enum.json b/test/libsolidity/ASTJSON/global_enum.json index 1b0ffe377..876b55ddf 100644 --- a/test/libsolidity/ASTJSON/global_enum.json +++ b/test/libsolidity/ASTJSON/global_enum.json @@ -8,6 +8,7 @@ ] }, "id": 3, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/global_enum_legacy.json b/test/libsolidity/ASTJSON/global_enum_legacy.json index f29649018..aea058345 100644 --- a/test/libsolidity/ASTJSON/global_enum_legacy.json +++ b/test/libsolidity/ASTJSON/global_enum_legacy.json @@ -8,7 +8,8 @@ [ 2 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/global_struct.json b/test/libsolidity/ASTJSON/global_struct.json index 64cf62a53..e1802e03b 100644 --- a/test/libsolidity/ASTJSON/global_struct.json +++ b/test/libsolidity/ASTJSON/global_struct.json @@ -8,6 +8,7 @@ ] }, "id": 4, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/global_struct_legacy.json b/test/libsolidity/ASTJSON/global_struct_legacy.json index ef0f71c37..2670ea5ea 100644 --- a/test/libsolidity/ASTJSON/global_struct_legacy.json +++ b/test/libsolidity/ASTJSON/global_struct_legacy.json @@ -8,7 +8,8 @@ [ 3 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/inheritance_specifier.json b/test/libsolidity/ASTJSON/inheritance_specifier.json index 2a235d1ed..20da9e31c 100644 --- a/test/libsolidity/ASTJSON/inheritance_specifier.json +++ b/test/libsolidity/ASTJSON/inheritance_specifier.json @@ -12,6 +12,7 @@ ] }, "id": 5, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/inheritance_specifier_legacy.json b/test/libsolidity/ASTJSON/inheritance_specifier_legacy.json index a387355b4..b8de3a97b 100644 --- a/test/libsolidity/ASTJSON/inheritance_specifier_legacy.json +++ b/test/libsolidity/ASTJSON/inheritance_specifier_legacy.json @@ -12,7 +12,8 @@ [ 4 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/long_type_name_binary_operation.json b/test/libsolidity/ASTJSON/long_type_name_binary_operation.json index 6e025f5f9..5e13c2bfb 100644 --- a/test/libsolidity/ASTJSON/long_type_name_binary_operation.json +++ b/test/libsolidity/ASTJSON/long_type_name_binary_operation.json @@ -8,6 +8,7 @@ ] }, "id": 12, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/long_type_name_binary_operation_legacy.json b/test/libsolidity/ASTJSON/long_type_name_binary_operation_legacy.json index 6ad38d194..c6f7662ea 100644 --- a/test/libsolidity/ASTJSON/long_type_name_binary_operation_legacy.json +++ b/test/libsolidity/ASTJSON/long_type_name_binary_operation_legacy.json @@ -8,7 +8,8 @@ [ 11 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/long_type_name_identifier.json b/test/libsolidity/ASTJSON/long_type_name_identifier.json index eddeacd04..417972b45 100644 --- a/test/libsolidity/ASTJSON/long_type_name_identifier.json +++ b/test/libsolidity/ASTJSON/long_type_name_identifier.json @@ -8,6 +8,7 @@ ] }, "id": 16, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/long_type_name_identifier_legacy.json b/test/libsolidity/ASTJSON/long_type_name_identifier_legacy.json index bc90e0d6a..537746abd 100644 --- a/test/libsolidity/ASTJSON/long_type_name_identifier_legacy.json +++ b/test/libsolidity/ASTJSON/long_type_name_identifier_legacy.json @@ -8,7 +8,8 @@ [ 15 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/mappings.json b/test/libsolidity/ASTJSON/mappings.json index 5c24e3a12..8df004d4b 100644 --- a/test/libsolidity/ASTJSON/mappings.json +++ b/test/libsolidity/ASTJSON/mappings.json @@ -8,6 +8,7 @@ ] }, "id": 18, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/mappings_legacy.json b/test/libsolidity/ASTJSON/mappings_legacy.json index 700097b66..49737edee 100644 --- a/test/libsolidity/ASTJSON/mappings_legacy.json +++ b/test/libsolidity/ASTJSON/mappings_legacy.json @@ -8,7 +8,8 @@ [ 17 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/modifier_definition.json b/test/libsolidity/ASTJSON/modifier_definition.json index a3c71159a..c5070f1da 100644 --- a/test/libsolidity/ASTJSON/modifier_definition.json +++ b/test/libsolidity/ASTJSON/modifier_definition.json @@ -8,6 +8,7 @@ ] }, "id": 15, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/modifier_definition_legacy.json b/test/libsolidity/ASTJSON/modifier_definition_legacy.json index 369562171..05876ae3e 100644 --- a/test/libsolidity/ASTJSON/modifier_definition_legacy.json +++ b/test/libsolidity/ASTJSON/modifier_definition_legacy.json @@ -8,7 +8,8 @@ [ 14 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/modifier_invocation.json b/test/libsolidity/ASTJSON/modifier_invocation.json index a3c71159a..c5070f1da 100644 --- a/test/libsolidity/ASTJSON/modifier_invocation.json +++ b/test/libsolidity/ASTJSON/modifier_invocation.json @@ -8,6 +8,7 @@ ] }, "id": 15, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/modifier_invocation_legacy.json b/test/libsolidity/ASTJSON/modifier_invocation_legacy.json index 369562171..05876ae3e 100644 --- a/test/libsolidity/ASTJSON/modifier_invocation_legacy.json +++ b/test/libsolidity/ASTJSON/modifier_invocation_legacy.json @@ -8,7 +8,8 @@ [ 14 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/mutability.json b/test/libsolidity/ASTJSON/mutability.json index 81d668702..3f5d610ed 100644 --- a/test/libsolidity/ASTJSON/mutability.json +++ b/test/libsolidity/ASTJSON/mutability.json @@ -8,6 +8,7 @@ ] }, "id": 11, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/mutability_legacy.json b/test/libsolidity/ASTJSON/mutability_legacy.json index 98f28f636..387ebc267 100644 --- a/test/libsolidity/ASTJSON/mutability_legacy.json +++ b/test/libsolidity/ASTJSON/mutability_legacy.json @@ -8,7 +8,8 @@ [ 10 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/non_utf8.json b/test/libsolidity/ASTJSON/non_utf8.json index c925389d7..d716d91c2 100644 --- a/test/libsolidity/ASTJSON/non_utf8.json +++ b/test/libsolidity/ASTJSON/non_utf8.json @@ -8,6 +8,7 @@ ] }, "id": 9, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/non_utf8_legacy.json b/test/libsolidity/ASTJSON/non_utf8_legacy.json index d3a212b0c..d49d2013d 100644 --- a/test/libsolidity/ASTJSON/non_utf8_legacy.json +++ b/test/libsolidity/ASTJSON/non_utf8_legacy.json @@ -8,7 +8,8 @@ [ 8 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/override.json b/test/libsolidity/ASTJSON/override.json index cb3d0268b..3e5a8c9da 100644 --- a/test/libsolidity/ASTJSON/override.json +++ b/test/libsolidity/ASTJSON/override.json @@ -16,6 +16,7 @@ ] }, "id": 32, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/override_legacy.json b/test/libsolidity/ASTJSON/override_legacy.json index a9bece4ac..23cf18b2b 100644 --- a/test/libsolidity/ASTJSON/override_legacy.json +++ b/test/libsolidity/ASTJSON/override_legacy.json @@ -16,7 +16,8 @@ [ 31 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/placeholder_statement.json b/test/libsolidity/ASTJSON/placeholder_statement.json index 4b37ba417..3be70c463 100644 --- a/test/libsolidity/ASTJSON/placeholder_statement.json +++ b/test/libsolidity/ASTJSON/placeholder_statement.json @@ -8,6 +8,7 @@ ] }, "id": 6, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/placeholder_statement_legacy.json b/test/libsolidity/ASTJSON/placeholder_statement_legacy.json index f478862f4..7ab1f4879 100644 --- a/test/libsolidity/ASTJSON/placeholder_statement_legacy.json +++ b/test/libsolidity/ASTJSON/placeholder_statement_legacy.json @@ -8,7 +8,8 @@ [ 5 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/receive_ether.json b/test/libsolidity/ASTJSON/receive_ether.json index f861e4271..a837dae15 100644 --- a/test/libsolidity/ASTJSON/receive_ether.json +++ b/test/libsolidity/ASTJSON/receive_ether.json @@ -8,6 +8,7 @@ ] }, "id": 6, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/receive_ether_legacy.json b/test/libsolidity/ASTJSON/receive_ether_legacy.json index e8f025234..964bd991b 100644 --- a/test/libsolidity/ASTJSON/receive_ether_legacy.json +++ b/test/libsolidity/ASTJSON/receive_ether_legacy.json @@ -8,7 +8,8 @@ [ 5 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/short_type_name.json b/test/libsolidity/ASTJSON/short_type_name.json index 75defa9ab..54c9b99ea 100644 --- a/test/libsolidity/ASTJSON/short_type_name.json +++ b/test/libsolidity/ASTJSON/short_type_name.json @@ -8,6 +8,7 @@ ] }, "id": 12, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/short_type_name_legacy.json b/test/libsolidity/ASTJSON/short_type_name_legacy.json index 0d428bcb1..c813bcdf4 100644 --- a/test/libsolidity/ASTJSON/short_type_name_legacy.json +++ b/test/libsolidity/ASTJSON/short_type_name_legacy.json @@ -8,7 +8,8 @@ [ 11 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/short_type_name_ref.json b/test/libsolidity/ASTJSON/short_type_name_ref.json index 46096a914..1a22f1f24 100644 --- a/test/libsolidity/ASTJSON/short_type_name_ref.json +++ b/test/libsolidity/ASTJSON/short_type_name_ref.json @@ -8,6 +8,7 @@ ] }, "id": 13, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/short_type_name_ref_legacy.json b/test/libsolidity/ASTJSON/short_type_name_ref_legacy.json index b1f4b88d2..086a21584 100644 --- a/test/libsolidity/ASTJSON/short_type_name_ref_legacy.json +++ b/test/libsolidity/ASTJSON/short_type_name_ref_legacy.json @@ -8,7 +8,8 @@ [ 12 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/smoke.json b/test/libsolidity/ASTJSON/smoke.json index 9aa2eda01..d72018e09 100644 --- a/test/libsolidity/ASTJSON/smoke.json +++ b/test/libsolidity/ASTJSON/smoke.json @@ -8,6 +8,7 @@ ] }, "id": 2, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/smoke_legacy.json b/test/libsolidity/ASTJSON/smoke_legacy.json index a3254c4e8..da56b0e77 100644 --- a/test/libsolidity/ASTJSON/smoke_legacy.json +++ b/test/libsolidity/ASTJSON/smoke_legacy.json @@ -8,7 +8,8 @@ [ 1 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/source_location.json b/test/libsolidity/ASTJSON/source_location.json index 54bffe378..b0b81d8f8 100644 --- a/test/libsolidity/ASTJSON/source_location.json +++ b/test/libsolidity/ASTJSON/source_location.json @@ -8,6 +8,7 @@ ] }, "id": 12, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/source_location_legacy.json b/test/libsolidity/ASTJSON/source_location_legacy.json index dbd578dd2..42f81ad16 100644 --- a/test/libsolidity/ASTJSON/source_location_legacy.json +++ b/test/libsolidity/ASTJSON/source_location_legacy.json @@ -8,7 +8,8 @@ [ 11 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/two_base_functions.json b/test/libsolidity/ASTJSON/two_base_functions.json index 7e6e15395..18412bbc7 100644 --- a/test/libsolidity/ASTJSON/two_base_functions.json +++ b/test/libsolidity/ASTJSON/two_base_functions.json @@ -16,6 +16,7 @@ ] }, "id": 23, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/two_base_functions_legacy.json b/test/libsolidity/ASTJSON/two_base_functions_legacy.json index bc9e4545c..b58008b75 100644 --- a/test/libsolidity/ASTJSON/two_base_functions_legacy.json +++ b/test/libsolidity/ASTJSON/two_base_functions_legacy.json @@ -16,7 +16,8 @@ [ 22 ] - } + }, + "license": null }, "children": [ diff --git a/test/libsolidity/ASTJSON/using_for_directive.json b/test/libsolidity/ASTJSON/using_for_directive.json index 9b973141c..66674f589 100644 --- a/test/libsolidity/ASTJSON/using_for_directive.json +++ b/test/libsolidity/ASTJSON/using_for_directive.json @@ -12,6 +12,7 @@ ] }, "id": 6, + "license": null, "nodeType": "SourceUnit", "nodes": [ diff --git a/test/libsolidity/ASTJSON/using_for_directive_legacy.json b/test/libsolidity/ASTJSON/using_for_directive_legacy.json index 13df0d5c2..280e9be4a 100644 --- a/test/libsolidity/ASTJSON/using_for_directive_legacy.json +++ b/test/libsolidity/ASTJSON/using_for_directive_legacy.json @@ -12,7 +12,8 @@ [ 1 ] - } + }, + "license": null }, "children": [ From af44c05f1abcad1c0c8a47a637e9286487c97690 Mon Sep 17 00:00:00 2001 From: Alexander Arlt Date: Tue, 12 May 2020 20:52:33 -0500 Subject: [PATCH 80/89] Add new test. --- test/libsolidity/ASTJSON/license.json | 35 +++++++++++++ test/libsolidity/ASTJSON/license.sol | 4 ++ test/libsolidity/ASTJSON/license_legacy.json | 50 +++++++++++++++++++ test/libsolidity/StandardCompiler.cpp | 40 +++++++++++++++ .../syntaxTests/license/license_double.sol | 5 ++ .../syntaxTests/license/license_missing.sol | 1 + 6 files changed, 135 insertions(+) create mode 100644 test/libsolidity/ASTJSON/license.json create mode 100644 test/libsolidity/ASTJSON/license.sol create mode 100644 test/libsolidity/ASTJSON/license_legacy.json create mode 100644 test/libsolidity/syntaxTests/license/license_double.sol create mode 100644 test/libsolidity/syntaxTests/license/license_missing.sol diff --git a/test/libsolidity/ASTJSON/license.json b/test/libsolidity/ASTJSON/license.json new file mode 100644 index 000000000..e8c6616a3 --- /dev/null +++ b/test/libsolidity/ASTJSON/license.json @@ -0,0 +1,35 @@ +{ + "absolutePath": "a", + "exportedSymbols": + { + "C": + [ + 1 + ] + }, + "id": 2, + "license": "GPL-3.0", + "nodeType": "SourceUnit", + "nodes": + [ + { + "abstract": false, + "baseContracts": [], + "contractDependencies": [], + "contractKind": "contract", + "documentation": null, + "fullyImplemented": true, + "id": 1, + "linearizedBaseContracts": + [ + 1 + ], + "name": "C", + "nodeType": "ContractDefinition", + "nodes": [], + "scope": 2, + "src": "36:13:1" + } + ], + "src": "36:14:1" +} diff --git a/test/libsolidity/ASTJSON/license.sol b/test/libsolidity/ASTJSON/license.sol new file mode 100644 index 000000000..92ffb8fa6 --- /dev/null +++ b/test/libsolidity/ASTJSON/license.sol @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0 +contract C {} + +// ---- diff --git a/test/libsolidity/ASTJSON/license_legacy.json b/test/libsolidity/ASTJSON/license_legacy.json new file mode 100644 index 000000000..2f1405b62 --- /dev/null +++ b/test/libsolidity/ASTJSON/license_legacy.json @@ -0,0 +1,50 @@ +{ + "attributes": + { + "absolutePath": "a", + "exportedSymbols": + { + "C": + [ + 1 + ] + }, + "license": "GPL-3.0" + }, + "children": + [ + { + "attributes": + { + "abstract": false, + "baseContracts": + [ + null + ], + "contractDependencies": + [ + null + ], + "contractKind": "contract", + "documentation": null, + "fullyImplemented": true, + "linearizedBaseContracts": + [ + 1 + ], + "name": "C", + "nodes": + [ + null + ], + "scope": 2 + }, + "id": 1, + "name": "ContractDefinition", + "src": "36:13:1" + } + ], + "id": 2, + "name": "SourceUnit", + "src": "36:14:1" +} diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index 288bba3fe..5f4a4e3d4 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -1105,6 +1105,46 @@ BOOST_AUTO_TEST_CASE(metadata_without_compilation) BOOST_CHECK(solidity::test::isValidMetadata(contract["metadata"].asString())); } + +BOOST_AUTO_TEST_CASE(license_in_metadata) +{ + string const input = R"( + { + "language": "Solidity", + "sources": { + "fileA": { "content": "import \"fileB\"; contract A { } // SPDX-License-Identifier: GPL-3.0 \n" }, + "fileB": { "content": "import \"fileC\"; /* SPDX-License-Identifier: MIT */ contract B { }" }, + "fileC": { "content": "import \"fileD\"; /* SPDX-License-Identifier: MIT AND GPL-3.0 */ contract C { }" }, + "fileD": { "content": "// SPDX-License-Identifier: (GPL-3.0+ OR MIT) AND MIT \n import \"fileE\"; contract D { }" }, + "fileE": { "content": "import \"fileF\"; /// SPDX-License-Identifier: MIT \n contract E { }" }, + "fileF": { "content": "/*\n * SPDX-License-Identifier: MIT\n */ contract F { }" } + }, + "settings": { + "outputSelection": { + "fileA": { + "*": [ "metadata" ] + } + } + } + } + )"; + Json::Value result = compile(input); + BOOST_CHECK(containsAtMostWarnings(result)); + Json::Value contract = getContractResult(result, "fileA", "A"); + BOOST_CHECK(contract.isObject()); + BOOST_CHECK(contract["metadata"].isString()); + Json::Value metadata; + BOOST_REQUIRE(util::jsonParseStrict(contract["metadata"].asString(), metadata)); + BOOST_CHECK_EQUAL(metadata["sources"]["fileA"]["license"], "GPL-3.0"); + BOOST_CHECK_EQUAL(metadata["sources"]["fileB"]["license"], "MIT"); + BOOST_CHECK_EQUAL(metadata["sources"]["fileC"]["license"], "MIT AND GPL-3.0"); + BOOST_CHECK_EQUAL(metadata["sources"]["fileD"]["license"], "(GPL-3.0+ OR MIT) AND MIT"); + // This is actually part of the docstring, but still picked up + // because the source location of the contract does not cover the docstring. + BOOST_CHECK_EQUAL(metadata["sources"]["fileE"]["license"], "MIT"); + BOOST_CHECK_EQUAL(metadata["sources"]["fileF"]["license"], "MIT"); +} + BOOST_AUTO_TEST_CASE(common_pattern) { char const* input = R"( diff --git a/test/libsolidity/syntaxTests/license/license_double.sol b/test/libsolidity/syntaxTests/license/license_double.sol new file mode 100644 index 000000000..47d7eae1b --- /dev/null +++ b/test/libsolidity/syntaxTests/license/license_double.sol @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-3.0 +contract C {} +// SPDX-License-Identifier: MIT +// ---- +// ParserError: Multiple SPDX license identifiers found in source file. Use "AND" or "OR" to combine multiple licenses. Please see https://spdx.org for more information. diff --git a/test/libsolidity/syntaxTests/license/license_missing.sol b/test/libsolidity/syntaxTests/license/license_missing.sol new file mode 100644 index 000000000..2dde0d209 --- /dev/null +++ b/test/libsolidity/syntaxTests/license/license_missing.sol @@ -0,0 +1 @@ +contract C {} From 97296d86225ee9f1069a28616ce6869351e06fbf Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 13 May 2020 10:25:46 +0200 Subject: [PATCH 81/89] Allow ABI encoding for array slices without explicit casts. --- Changelog.md | 1 + libsolidity/ast/Types.cpp | 15 ++++- libsolidity/ast/Types.h | 1 + libsolidity/codegen/ABIFunctions.cpp | 46 +++++++++----- libsolidity/codegen/CompilerUtils.cpp | 41 +++++++++--- .../abi_encode_calldata_slice.sol | 62 ++++++++++++++++++ .../abi_encode_calldata_slice.sol | 63 +++++++++++++++++++ .../array/slice/assign_to_storage.sol | 8 +++ .../array/slice/calldata_dynamic_encode.sol | 1 - 9 files changed, 214 insertions(+), 24 deletions(-) create mode 100644 test/libsolidity/semanticTests/abiEncoderV1/abi_encode_calldata_slice.sol create mode 100644 test/libsolidity/semanticTests/abiEncoderV2/abi_encode_calldata_slice.sol create mode 100644 test/libsolidity/syntaxTests/array/slice/assign_to_storage.sol diff --git a/Changelog.md b/Changelog.md index 8d7ff006a..09f4acff3 100644 --- a/Changelog.md +++ b/Changelog.md @@ -11,6 +11,7 @@ Language Features: Compiler Features: * Commandline Interface: Don't ignore `--yul-optimizations` in assembly mode. + * Allow using abi encoding functions for calldata array slices without explicit casts. diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index c9d40a1ce..b19ab4c4b 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -330,7 +330,7 @@ TypePointer Type::fullEncodingType(bool _inLibraryCall, bool _encoderV2, bool) c // Structs are fine in the following circumstances: // - ABIv2 or, // - storage struct for a library - if (_inLibraryCall && encodingType->dataStoredIn(DataLocation::Storage)) + if (_inLibraryCall && encodingType && encodingType->dataStoredIn(DataLocation::Storage)) return encodingType; TypePointer baseType = encodingType; while (auto const* arrayType = dynamic_cast(baseType)) @@ -1971,6 +1971,19 @@ string ArraySliceType::toString(bool _short) const return m_arrayType.toString(_short) + " slice"; } +TypePointer ArraySliceType::mobileType() const +{ + if ( + m_arrayType.dataStoredIn(DataLocation::CallData) && + m_arrayType.isDynamicallySized() && + !m_arrayType.baseType()->isDynamicallyEncoded() + ) + return &m_arrayType; + else + return this; +} + + std::vector> ArraySliceType::makeStackItems() const { return {{"offset", TypeProvider::uint256()}, {"length", TypeProvider::uint256()}}; diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index d549d4f24..11e948f26 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -831,6 +831,7 @@ public: bool isDynamicallyEncoded() const override { return true; } bool canLiveOutsideStorage() const override { return m_arrayType.canLiveOutsideStorage(); } std::string toString(bool _short) const override; + TypePointer mobileType() const override; BoolResult validForLocation(DataLocation _loc) const override { return m_arrayType.validForLocation(_loc); } diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index 5018346b4..189fba165 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -279,31 +279,47 @@ string ABIFunctions::abiEncodingFunction( return abiEncodingFunctionStringLiteral(_from, to, _options); else if (auto toArray = dynamic_cast(&to)) { - solAssert(_from.category() == Type::Category::Array, ""); - solAssert(to.dataStoredIn(DataLocation::Memory), ""); - ArrayType const& fromArray = dynamic_cast(_from); + ArrayType const* fromArray = nullptr; + switch (_from.category()) + { + case Type::Category::Array: + fromArray = dynamic_cast(&_from); + break; + case Type::Category::ArraySlice: + fromArray = &dynamic_cast(&_from)->arrayType(); + solAssert( + fromArray->dataStoredIn(DataLocation::CallData) && + fromArray->isDynamicallySized() && + !fromArray->baseType()->isDynamicallyEncoded(), + "" + ); + break; + default: + solAssert(false, ""); + break; + } - switch (fromArray.location()) + switch (fromArray->location()) { case DataLocation::CallData: if ( - fromArray.isByteArray() || - *fromArray.baseType() == *TypeProvider::uint256() || - *fromArray.baseType() == FixedBytesType(32) + fromArray->isByteArray() || + *fromArray->baseType() == *TypeProvider::uint256() || + *fromArray->baseType() == FixedBytesType(32) ) - return abiEncodingFunctionCalldataArrayWithoutCleanup(fromArray, *toArray, _options); + return abiEncodingFunctionCalldataArrayWithoutCleanup(*fromArray, *toArray, _options); else - return abiEncodingFunctionSimpleArray(fromArray, *toArray, _options); + return abiEncodingFunctionSimpleArray(*fromArray, *toArray, _options); case DataLocation::Memory: - if (fromArray.isByteArray()) - return abiEncodingFunctionMemoryByteArray(fromArray, *toArray, _options); + if (fromArray->isByteArray()) + return abiEncodingFunctionMemoryByteArray(*fromArray, *toArray, _options); else - return abiEncodingFunctionSimpleArray(fromArray, *toArray, _options); + return abiEncodingFunctionSimpleArray(*fromArray, *toArray, _options); case DataLocation::Storage: - if (fromArray.baseType()->storageBytes() <= 16) - return abiEncodingFunctionCompactStorageArray(fromArray, *toArray, _options); + if (fromArray->baseType()->storageBytes() <= 16) + return abiEncodingFunctionCompactStorageArray(*fromArray, *toArray, _options); else - return abiEncodingFunctionSimpleArray(fromArray, *toArray, _options); + return abiEncodingFunctionSimpleArray(*fromArray, *toArray, _options); default: solAssert(false, ""); } diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index feae52caa..8bf0a21e2 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -480,6 +480,16 @@ void CompilerUtils::encodeToMemory( convertType(*_givenTypes[i], *targetType, true); if (auto arrayType = dynamic_cast(type)) ArrayUtils(m_context).copyArrayToMemory(*arrayType, _padToWordBoundaries); + else if (auto arraySliceType = dynamic_cast(type)) + { + solAssert( + arraySliceType->dataStoredIn(DataLocation::CallData) && + arraySliceType->isDynamicallySized() && + !arraySliceType->arrayType().baseType()->isDynamicallyEncoded(), + "" + ); + ArrayUtils(m_context).copyArrayToMemory(arraySliceType->arrayType(), _padToWordBoundaries); + } else storeInMemoryDynamic(*type, _padToWordBoundaries); } @@ -516,22 +526,39 @@ void CompilerUtils::encodeToMemory( } else { - solAssert(_givenTypes[i]->category() == Type::Category::Array, "Unknown dynamic type."); - auto const& arrayType = dynamic_cast(*_givenTypes[i]); + ArrayType const* arrayType = nullptr; + switch (_givenTypes[i]->category()) + { + case Type::Category::Array: + arrayType = dynamic_cast(_givenTypes[i]); + break; + case Type::Category::ArraySlice: + arrayType = &dynamic_cast(_givenTypes[i])->arrayType(); + solAssert( + arrayType->isDynamicallySized() && + arrayType->dataStoredIn(DataLocation::CallData) && + !arrayType->baseType()->isDynamicallyEncoded(), + "" + ); + break; + default: + solAssert(false, "Unknown dynamic type."); + break; + } // now copy the array - copyToStackTop(argSize - stackPos + dynPointers + 2, arrayType.sizeOnStack()); + copyToStackTop(argSize - stackPos + dynPointers + 2, arrayType->sizeOnStack()); // stack: ... // copy length to memory - m_context << dupInstruction(1 + arrayType.sizeOnStack()); - ArrayUtils(m_context).retrieveLength(arrayType, 1); + m_context << dupInstruction(1 + arrayType->sizeOnStack()); + ArrayUtils(m_context).retrieveLength(*arrayType, 1); // stack: ... storeInMemoryDynamic(*TypeProvider::uint256(), true); // stack: ... // copy the new memory pointer - m_context << swapInstruction(arrayType.sizeOnStack() + 1) << Instruction::POP; + m_context << swapInstruction(arrayType->sizeOnStack() + 1) << Instruction::POP; // stack: ... // copy data part - ArrayUtils(m_context).copyArrayToMemory(arrayType, _padToWordBoundaries); + ArrayUtils(m_context).copyArrayToMemory(*arrayType, _padToWordBoundaries); // stack: ... } diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_calldata_slice.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_calldata_slice.sol new file mode 100644 index 000000000..917704e53 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_calldata_slice.sol @@ -0,0 +1,62 @@ +contract C { + function enc_packed_bytes(bytes calldata data, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encodePacked(data[start:end]); + } + function enc_packed_bytes_reference(bytes calldata data, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encodePacked(bytes(data[start:end])); + } + + function enc_bytes(bytes calldata data, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encode(data[start:end]); + } + function enc_bytes_reference(bytes calldata data, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encode(bytes(data[start:end])); + } + + function enc_uint256(uint256[] calldata x, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encode(x[start:end]); + } + function enc_uint256_reference(uint256[] calldata x, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encode(x[start:end]); + } + + function enc_packed_uint256(uint256[] calldata x, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encodePacked(x[start:end]); + } + function enc_packed_uint256_reference(uint256[] calldata x, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encodePacked(x[start:end]); + } + + function compare(bytes memory x, bytes memory y) internal { + assert(x.length == y.length); + for (uint i = 0; i < x.length; ++i) + assert(x[i] == y[i]); + } + + function test_bytes() public { + bytes memory test = new bytes(3); + test[0] = 0x41; test[1] = 0x42; test[2] = 0x42; + for (uint i = 0; i < test.length; i++) + for (uint j = i; j <= test.length; j++) + { + compare(this.enc_packed_bytes(test, i, j), this.enc_packed_bytes_reference(test, i, j)); + compare(this.enc_bytes(test, i, j), this.enc_bytes_reference(test, i, j)); + } + } + + function test_uint256() public { + uint256[] memory test = new uint256[](3); + test[0] = 0x41; test[1] = 0x42; test[2] = 0x42; + for (uint i = 0; i < test.length; i++) + for (uint j = i; j <= test.length; j++) + { + compare(this.enc_packed_uint256(test, i, j), this.enc_packed_uint256_reference(test, i, j)); + compare(this.enc_uint256(test, i, j), this.enc_uint256_reference(test, i, j)); + } + } +} +// ==== +// EVMVersion: >homestead +// ---- +// test_bytes() -> +// test_uint256() -> diff --git a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_calldata_slice.sol b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_calldata_slice.sol new file mode 100644 index 000000000..1f1444672 --- /dev/null +++ b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_calldata_slice.sol @@ -0,0 +1,63 @@ +pragma experimental ABIEncoderV2; +contract C { + function enc_packed_bytes(bytes calldata data, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encodePacked(data[start:end]); + } + function enc_packed_bytes_reference(bytes calldata data, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encodePacked(bytes(data[start:end])); + } + + function enc_bytes(bytes calldata data, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encode(data[start:end]); + } + function enc_bytes_reference(bytes calldata data, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encode(bytes(data[start:end])); + } + + function enc_uint256(uint256[] calldata x, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encode(x[start:end]); + } + function enc_uint256_reference(uint256[] calldata x, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encode(x[start:end]); + } + + function enc_packed_uint256(uint256[] calldata x, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encodePacked(x[start:end]); + } + function enc_packed_uint256_reference(uint256[] calldata x, uint256 start, uint256 end) external returns (bytes memory) { + return abi.encodePacked(x[start:end]); + } + + function compare(bytes memory x, bytes memory y) internal { + assert(x.length == y.length); + for (uint i = 0; i < x.length; ++i) + assert(x[i] == y[i]); + } + + function test_bytes() public { + bytes memory test = new bytes(3); + test[0] = 0x41; test[1] = 0x42; test[2] = 0x42; + for (uint i = 0; i < test.length; i++) + for (uint j = i; j <= test.length; j++) + { + compare(this.enc_packed_bytes(test, i, j), this.enc_packed_bytes_reference(test, i, j)); + compare(this.enc_bytes(test, i, j), this.enc_bytes_reference(test, i, j)); + } + } + + function test_uint256() public { + uint256[] memory test = new uint256[](3); + test[0] = 0x41; test[1] = 0x42; test[2] = 0x42; + for (uint i = 0; i < test.length; i++) + for (uint j = i; j <= test.length; j++) + { + compare(this.enc_packed_uint256(test, i, j), this.enc_packed_uint256_reference(test, i, j)); + compare(this.enc_uint256(test, i, j), this.enc_uint256_reference(test, i, j)); + } + } +} +// ==== +// EVMVersion: >homestead +// ---- +// test_bytes() -> +// test_uint256() -> diff --git a/test/libsolidity/syntaxTests/array/slice/assign_to_storage.sol b/test/libsolidity/syntaxTests/array/slice/assign_to_storage.sol new file mode 100644 index 000000000..7b443949a --- /dev/null +++ b/test/libsolidity/syntaxTests/array/slice/assign_to_storage.sol @@ -0,0 +1,8 @@ +contract c { + bytes public b; + function f() public { + b = msg.data[:]; + } +} +// ---- +// TypeError: (63-74): Type bytes calldata slice is not implicitly convertible to expected type bytes storage ref. diff --git a/test/libsolidity/syntaxTests/array/slice/calldata_dynamic_encode.sol b/test/libsolidity/syntaxTests/array/slice/calldata_dynamic_encode.sol index a31e5ab85..de90b0f75 100644 --- a/test/libsolidity/syntaxTests/array/slice/calldata_dynamic_encode.sol +++ b/test/libsolidity/syntaxTests/array/slice/calldata_dynamic_encode.sol @@ -4,4 +4,3 @@ contract C { } } // ---- -// TypeError: (85-91): This type cannot be encoded. From 0148525aeece160d2898bf185ba1fc136d3b04f9 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 13 May 2020 16:53:54 +0200 Subject: [PATCH 82/89] Documentation changes. --- docs/introduction-to-smart-contracts.rst | 8 ++++-- docs/layout-of-source-files.rst | 32 ++++++++++++++++++++++++ docs/metadata.rst | 6 ++++- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/docs/introduction-to-smart-contracts.rst b/docs/introduction-to-smart-contracts.rst index e3e38b92c..9bba24c2f 100644 --- a/docs/introduction-to-smart-contracts.rst +++ b/docs/introduction-to-smart-contracts.rst @@ -31,8 +31,12 @@ Storage Example } } -The first line tells you that the source code is written for -Solidity version 0.4.0, or a newer version of the language up to, but not including version 0.7.0. +The first line tells you that the source code is licensed under the +GPL version 3.0. Machine-readable license specifiers are important +in a setting where publishing the source code is the default. + +The next line specifies that the source code is written for +Solidity version 0.4.16, or a newer version of the language up to, but not including version 0.7.0. This is to ensure that the contract is not compilable with a new (breaking) compiler version, where it could behave differently. :ref:`Pragmas` are common instructions for compilers about how to treat the source code (e.g. `pragma once `_). diff --git a/docs/layout-of-source-files.rst b/docs/layout-of-source-files.rst index a2629319b..f817f04ff 100644 --- a/docs/layout-of-source-files.rst +++ b/docs/layout-of-source-files.rst @@ -7,6 +7,38 @@ Source files can contain an arbitrary number of :ref:`pragma directives` and :ref:`struct` and :ref:`enum` definitions. +.. index:: ! license, spdx + +SPDX License Identifier +======================= + +Trust in smart contract can be better established if their source code +is available. Since making source code available always touches on legal problems +with regards to copyright, the Solidity compiler encouranges the use +of machine-readable `SPDX license identifiers `_. +Every source file should start with a comment indicating its license: + +``// SPDX-License-Identifier: MIT`` + +The compiler does not validate that the license is part of the +`list allowed by SPDX `_, but +it does include the supplied string in the `bytecode metadata `_. + +If you do not want to specify a license or if the source code is +not open-source, please use the special value ``UNLICENSED``. + +Supplying this comment of course does not free you from other +obligations related to licensing like having to mention +a specific license header in each source file or the +original copyright holder. + +The comment is recognized by the compiler anywhere in the file at the +file level, but it is recommended to put it at the top of the file. + +More information about how to use SPDX license identifiers +can be found at the `SPDX website `_. + + .. index:: ! pragma .. _pragma: diff --git a/docs/metadata.rst b/docs/metadata.rst index 96a02c43a..240814adc 100644 --- a/docs/metadata.rst +++ b/docs/metadata.rst @@ -1,3 +1,5 @@ +.. _metadata: + ################# Contract Metadata ################# @@ -54,7 +56,9 @@ explanatory purposes. // Required (unless "content" is used, see below): Sorted URL(s) // to the source file, protocol is more or less arbitrary, but a // Swarm URL is recommended - "urls": [ "bzzr://56ab..." ] + "urls": [ "bzzr://56ab..." ], + // Optional: SPDX license identifier as given in the source file + "license": "MIT" }, "destructible": { // Required: keccak256 hash of the source file From bcc4bbcad77aee74936652ebb565b332dc94d5e7 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 13 May 2020 17:41:56 +0200 Subject: [PATCH 83/89] Update test extraction script to recognize license identifier. --- scripts/isolate_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/isolate_tests.py b/scripts/isolate_tests.py index 9dea81aa5..768f94801 100755 --- a/scripts/isolate_tests.py +++ b/scripts/isolate_tests.py @@ -52,7 +52,7 @@ def extract_docs_cases(path): if inside: extractedLines[-1] += l + '\n' - codeStart = "(pragma solidity|contract.*{|library.*{|interface.*{)" + codeStart = "(// SPDX-License-Identifier:|pragma solidity|contract.*{|library.*{|interface.*{)" # Filter all tests that do not contain Solidity or are intended incorrectly. for lines in extractedLines: From d33b67b3c29108e4375afbc07a9b59e1d92c71f5 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 13 May 2020 17:45:58 +0200 Subject: [PATCH 84/89] Add license tags to documentation snippets. --- docs/050-breaking-changes.rst | 6 ++++++ docs/abi-spec.rst | 3 +++ docs/assembly.rst | 3 +++ docs/common-patterns.rst | 4 ++++ docs/contracts/abstract-contracts.rst | 2 ++ docs/contracts/constant-state-variables.rst | 1 + docs/contracts/creating-contracts.rst | 1 + docs/contracts/events.rst | 2 ++ docs/contracts/function-modifiers.rst | 1 + docs/contracts/functions.rst | 10 ++++++++++ docs/contracts/inheritance.rst | 13 +++++++++++++ docs/contracts/interfaces.rst | 2 ++ docs/contracts/libraries.rst | 3 +++ docs/contracts/using-for.rst | 2 ++ docs/contracts/visibility-and-getters.rst | 6 ++++++ docs/control-structures.rst | 14 ++++++++++++++ docs/examples/blind-auction.rst | 2 ++ docs/examples/micropayment.rst | 2 ++ docs/examples/modular.rst | 1 + docs/examples/safe-remote.rst | 1 + docs/examples/voting.rst | 1 + docs/internals/layout_in_storage.rst | 2 ++ docs/introduction-to-smart-contracts.rst | 2 ++ docs/layout-of-source-files.rst | 1 + docs/natspec-format.rst | 1 + docs/security-considerations.rst | 8 ++++++++ docs/structure-of-a-contract.rst | 6 ++++++ docs/style-guide.rst | 16 ++++++++++++++++ docs/types/mapping-types.rst | 3 +++ docs/types/operators.rst | 1 + docs/types/reference-types.rst | 7 +++++++ docs/types/value-types.rst | 4 ++++ docs/using-the-compiler.rst | 2 ++ 33 files changed, 133 insertions(+) diff --git a/docs/050-breaking-changes.rst b/docs/050-breaking-changes.rst index 9461cb6bd..68d917f9f 100644 --- a/docs/050-breaking-changes.rst +++ b/docs/050-breaking-changes.rst @@ -292,6 +292,7 @@ Consider you have the following pre-0.5.0 contract already deployed: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.4.25; // This will report a warning until version 0.4.25 of the compiler // This will not compile after 0.5.0 @@ -309,6 +310,7 @@ This will no longer compile with Solidity v0.5.0. However, you can define a comp :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; interface OldContract { function someOldFunction(uint8 a) external; @@ -326,6 +328,7 @@ Given the interface defined above, you can now easily use the already deployed p :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; interface OldContract { @@ -347,6 +350,7 @@ commandline compiler for linking): :: // This will not compile after 0.6.0 + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.5.99; library OldLibrary { @@ -370,6 +374,7 @@ Old version: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.4.25; // This will not compile after 0.5.0 @@ -432,6 +437,7 @@ New version: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.5.99; // This will not compile after 0.6.0 diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst index ec31654dd..1d3e8efd0 100644 --- a/docs/abi-spec.rst +++ b/docs/abi-spec.rst @@ -232,6 +232,7 @@ Given the contract: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract Foo { @@ -535,6 +536,7 @@ For example, :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; @@ -583,6 +585,7 @@ As an example, the code :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.19 <0.7.0; pragma experimental ABIEncoderV2; diff --git a/docs/assembly.rst b/docs/assembly.rst index 19e4449e6..c42e9d70d 100644 --- a/docs/assembly.rst +++ b/docs/assembly.rst @@ -41,6 +41,7 @@ without a compiler change. .. code:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; library GetCode { @@ -66,6 +67,7 @@ efficient code, for example: .. code:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; @@ -136,6 +138,7 @@ Local Solidity variables are available for assignments, for example: .. code:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract C { diff --git a/docs/common-patterns.rst b/docs/common-patterns.rst index ab25cb4b9..ad33c52fc 100644 --- a/docs/common-patterns.rst +++ b/docs/common-patterns.rst @@ -27,6 +27,7 @@ you receive the funds of the person who is now the richest. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract WithdrawalContract { @@ -60,6 +61,7 @@ This is as opposed to the more intuitive sending pattern: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract SendContract { @@ -121,6 +123,7 @@ restrictions highly readable. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; contract AccessRestriction { @@ -273,6 +276,7 @@ function finishes. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; contract StateMachine { diff --git a/docs/contracts/abstract-contracts.rst b/docs/contracts/abstract-contracts.rst index 4571f45b2..908fa5072 100644 --- a/docs/contracts/abstract-contracts.rst +++ b/docs/contracts/abstract-contracts.rst @@ -13,6 +13,7 @@ This can be done by using the ``abstract`` keyword as shown in the following exa defined as abstract, because the function ``utterance()`` was defined, but no implementation was provided (no implementation body ``{ }`` was given).:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; abstract contract Feline { @@ -22,6 +23,7 @@ provided (no implementation body ``{ }`` was given).:: Such abstract contracts can not be instantiated directly. This is also true, if an abstract contract itself does implement all defined functions. The usage of an abstract contract as a base class is shown in the following example:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; abstract contract Feline { diff --git a/docs/contracts/constant-state-variables.rst b/docs/contracts/constant-state-variables.rst index 7a0a7380a..7424cd66a 100644 --- a/docs/contracts/constant-state-variables.rst +++ b/docs/contracts/constant-state-variables.rst @@ -17,6 +17,7 @@ Not all types for constants and immutables are implemented at this time. The onl :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >0.6.4 <0.7.0; contract C { diff --git a/docs/contracts/creating-contracts.rst b/docs/contracts/creating-contracts.rst index 90578f784..a2a628237 100644 --- a/docs/contracts/creating-contracts.rst +++ b/docs/contracts/creating-contracts.rst @@ -34,6 +34,7 @@ This means that cyclic creation dependencies are impossible. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; diff --git a/docs/contracts/events.rst b/docs/contracts/events.rst index 46b426d8e..e4e74bde4 100644 --- a/docs/contracts/events.rst +++ b/docs/contracts/events.rst @@ -65,6 +65,7 @@ is that they are cheaper to deploy and call. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.21 <0.7.0; contract ClientReceipt { @@ -138,6 +139,7 @@ as topics. The event call above can be performed in the same way as :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.10 <0.7.0; contract C { diff --git a/docs/contracts/function-modifiers.rst b/docs/contracts/function-modifiers.rst index 758ba74ea..b64143d90 100644 --- a/docs/contracts/function-modifiers.rst +++ b/docs/contracts/function-modifiers.rst @@ -17,6 +17,7 @@ if they are marked ``virtual``. For details, please see :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract owned { diff --git a/docs/contracts/functions.rst b/docs/contracts/functions.rst index 7a0ec2e08..f33258fe1 100644 --- a/docs/contracts/functions.rst +++ b/docs/contracts/functions.rst @@ -23,6 +23,7 @@ unused parameters can be omitted. For example, if you want your contract to accept one kind of external call with two integers, you would use something like the following:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract Simple { @@ -55,6 +56,7 @@ Function return variables are declared with the same syntax after the For example, suppose you want to return two results: the sum and the product of two integers passed as function parameters, then you use something like:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract Simple { @@ -79,6 +81,7 @@ or you can provide return values (either a single or :ref:`multiple ones`) directly with the ``return`` statement:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract Simple { @@ -142,6 +145,7 @@ The following statements are considered modifying the state: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract C { @@ -187,6 +191,7 @@ In addition to the list of state modifying statements explained above, the follo :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract C { @@ -280,6 +285,7 @@ Below you can see an example of a Sink contract that uses function ``receive``. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; // This contract keeps all Ether sent to it with no way @@ -335,6 +341,7 @@ operations as long as there is enough gas passed on to it. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.2 <0.7.0; contract Test { @@ -407,6 +414,7 @@ The following example shows overloading of the function :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract A { @@ -425,6 +433,7 @@ externally visible functions differ by their Solidity types but not by their ext :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; // This will not compile @@ -458,6 +467,7 @@ candidate, resolution fails. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract A { diff --git a/docs/contracts/inheritance.rst b/docs/contracts/inheritance.rst index d3dd0f164..83ccdf773 100644 --- a/docs/contracts/inheritance.rst +++ b/docs/contracts/inheritance.rst @@ -38,6 +38,7 @@ Details are given in the following example. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; @@ -125,6 +126,7 @@ Note that above, we call ``Destructible.destroy()`` to "forward" the destruction request. The way this is done is problematic, as seen in the following example:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; contract owned { @@ -154,6 +156,7 @@ A call to ``Final.destroy()`` will call ``Base2.destroy`` because we specify it explicitly in the final override, but this function will bypass ``Base1.destroy``. The way around this is to use ``super``:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; contract owned { @@ -204,6 +207,7 @@ use the ``override`` keyword in the function header as shown in this example: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; contract Base @@ -227,6 +231,7 @@ bases, it has to explicitly override it: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; contract Base1 @@ -253,6 +258,7 @@ that already overrides all other functions. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; contract A { function f() public pure{} } @@ -293,6 +299,7 @@ of the variable: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; contract A @@ -324,6 +331,7 @@ and the ``override`` keyword must be used in the overriding modifier: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; contract Base @@ -342,6 +350,7 @@ explicitly: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; contract Base1 @@ -389,6 +398,7 @@ equivalent to ``constructor() public {}``. For example: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract A { @@ -419,6 +429,7 @@ The constructors of all the base contracts will be called following the linearization rules explained below. If the base constructors have arguments, derived contracts need to specify all of them. This can be done in two ways:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; contract Base { @@ -478,6 +489,7 @@ error "Linearization of inheritance graph impossible". :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract X {} @@ -498,6 +510,7 @@ One area where inheritance linearization is especially important and perhaps not :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; contract Base1 { diff --git a/docs/contracts/interfaces.rst b/docs/contracts/interfaces.rst index bce974502..7b1421791 100644 --- a/docs/contracts/interfaces.rst +++ b/docs/contracts/interfaces.rst @@ -22,6 +22,7 @@ Interfaces are denoted by their own keyword: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.2 <0.7.0; interface Token { @@ -42,6 +43,7 @@ inheritance. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.2 <0.7.0; interface ParentA { diff --git a/docs/contracts/libraries.rst b/docs/contracts/libraries.rst index 86561ea7b..f58bf0f4e 100644 --- a/docs/contracts/libraries.rst +++ b/docs/contracts/libraries.rst @@ -47,6 +47,7 @@ more advanced example to implement a set). :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; @@ -125,6 +126,7 @@ custom types without the overhead of external function calls: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; struct bigint { @@ -239,6 +241,7 @@ Its value can be obtained from Solidity using the ``.selector`` member as follow :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.14 <0.7.0; library L { diff --git a/docs/contracts/using-for.rst b/docs/contracts/using-for.rst index 9e63abcf4..8853bad24 100644 --- a/docs/contracts/using-for.rst +++ b/docs/contracts/using-for.rst @@ -29,6 +29,7 @@ may only be used inside a contract, not inside any of its functions. Let us rewrite the set example from the :ref:`libraries` in this way:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; @@ -81,6 +82,7 @@ Let us rewrite the set example from the It is also possible to extend elementary types in that way:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; library Search { diff --git a/docs/contracts/visibility-and-getters.rst b/docs/contracts/visibility-and-getters.rst index 04af8a26f..7e7785f3a 100644 --- a/docs/contracts/visibility-and-getters.rst +++ b/docs/contracts/visibility-and-getters.rst @@ -54,6 +54,7 @@ return parameter list for functions. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract C { @@ -68,6 +69,7 @@ In the following example, ``D``, can call ``c.getData()`` to retrieve the value :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract C { @@ -112,6 +114,7 @@ when they are declared. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract C { @@ -132,6 +135,7 @@ it evaluates to a state variable. If it is accessed externally :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract C { @@ -151,6 +155,7 @@ to write a function, for example: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract arrayExample { @@ -177,6 +182,7 @@ The next example is more complex: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract Complex { diff --git a/docs/control-structures.rst b/docs/control-structures.rst index 7bbe290ba..9ecaa838b 100644 --- a/docs/control-structures.rst +++ b/docs/control-structures.rst @@ -41,6 +41,7 @@ Internal Function Calls Functions of the current contract can be called directly ("internally"), also recursively, as seen in this nonsensical example:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; contract C { @@ -82,6 +83,7 @@ to the total balance of that contract: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.2 <0.7.0; contract InfoFeed { @@ -137,6 +139,7 @@ parameters from the function declaration, but can be in arbitrary order. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract C { @@ -160,6 +163,7 @@ Those parameters will still be present on the stack, but they are inaccessible. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; contract C { @@ -183,6 +187,7 @@ is compiled so recursive creation-dependencies are not possible. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.2 <0.7.0; contract D { @@ -238,6 +243,7 @@ which only need to be created if there is a dispute. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.2 <0.7.0; contract D { @@ -307,6 +313,7 @@ groupings of expressions. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract C { @@ -352,6 +359,7 @@ because only a reference and not a copy is passed. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; contract C { @@ -410,6 +418,7 @@ the two variables have the same name but disjoint scopes. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract C { function minimalScoping() pure public { @@ -431,6 +440,7 @@ In any case, you will get a warning about the outer variable being shadowed. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; // This will report a warning contract C { @@ -452,6 +462,7 @@ In any case, you will get a warning about the outer variable being shadowed. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; // This will not compile contract C { @@ -540,6 +551,7 @@ and ``assert`` for internal error checking. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract Sharer { @@ -584,6 +596,7 @@ The following example shows how to use an error string together with ``revert`` :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract VendingMachine { @@ -627,6 +640,7 @@ A failure in an external call can be caught using a try/catch statement, as foll :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; interface DataFeed { function getData(address token) external returns (uint value); } diff --git a/docs/examples/blind-auction.rst b/docs/examples/blind-auction.rst index f2034272a..30c177baa 100644 --- a/docs/examples/blind-auction.rst +++ b/docs/examples/blind-auction.rst @@ -24,6 +24,7 @@ to receive their money - contracts cannot activate themselves. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract SimpleAuction { @@ -184,6 +185,7 @@ invalid bids. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract BlindAuction { diff --git a/docs/examples/micropayment.rst b/docs/examples/micropayment.rst index ab69fd296..93dcd26f0 100644 --- a/docs/examples/micropayment.rst +++ b/docs/examples/micropayment.rst @@ -142,6 +142,7 @@ The full contract :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.24 <0.7.0; contract ReceiverPays { @@ -338,6 +339,7 @@ The full contract :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract SimplePaymentChannel { diff --git a/docs/examples/modular.rst b/docs/examples/modular.rst index a95a675c6..ff6a64077 100644 --- a/docs/examples/modular.rst +++ b/docs/examples/modular.rst @@ -19,6 +19,7 @@ and the sum of all balances is an invariant across the lifetime of the contract. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; library Balances { diff --git a/docs/examples/safe-remote.rst b/docs/examples/safe-remote.rst index caafaa7ed..c8e0eecc1 100644 --- a/docs/examples/safe-remote.rst +++ b/docs/examples/safe-remote.rst @@ -25,6 +25,7 @@ you can use state machine-like constructs inside a contract. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract Purchase { diff --git a/docs/examples/voting.rst b/docs/examples/voting.rst index e4b6da200..8d97a57ee 100644 --- a/docs/examples/voting.rst +++ b/docs/examples/voting.rst @@ -32,6 +32,7 @@ of votes. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; /// @title Voting with delegation. diff --git a/docs/internals/layout_in_storage.rst b/docs/internals/layout_in_storage.rst index 0101556ef..5e102a38a 100644 --- a/docs/internals/layout_in_storage.rst +++ b/docs/internals/layout_in_storage.rst @@ -71,6 +71,7 @@ So for the following contract snippet the position of ``data[4][9].b`` is at ``keccak256(uint256(9) . keccak256(uint256(4) . uint256(1))) + 1``:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; @@ -171,6 +172,7 @@ value and reference types, types that are encoded packed, and nested types. .. code:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract A { struct S { diff --git a/docs/introduction-to-smart-contracts.rst b/docs/introduction-to-smart-contracts.rst index 9bba24c2f..6a59f1373 100644 --- a/docs/introduction-to-smart-contracts.rst +++ b/docs/introduction-to-smart-contracts.rst @@ -17,6 +17,7 @@ Storage Example :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract SimpleStorage { @@ -81,6 +82,7 @@ registering with a username and password, all you need is an Ethereum keypair. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract Coin { diff --git a/docs/layout-of-source-files.rst b/docs/layout-of-source-files.rst index f817f04ff..f01e23ac5 100644 --- a/docs/layout-of-source-files.rst +++ b/docs/layout-of-source-files.rst @@ -316,6 +316,7 @@ for the two function parameters and two return variables. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.21 <0.7.0; /** @title Shape calculator. */ diff --git a/docs/natspec-format.rst b/docs/natspec-format.rst index 1776925ee..fa1d0c665 100644 --- a/docs/natspec-format.rst +++ b/docs/natspec-format.rst @@ -49,6 +49,7 @@ The following example shows a contract and a function using all available tags. .. code:: solidity + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; /// @title A simulator for trees diff --git a/docs/security-considerations.rst b/docs/security-considerations.rst index cf706fb7b..f899736aa 100644 --- a/docs/security-considerations.rst +++ b/docs/security-considerations.rst @@ -58,6 +58,7 @@ complete contract): :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; // THIS CONTRACT CONTAINS A BUG - DO NOT USE @@ -81,6 +82,7 @@ as it uses ``call`` which forwards all remaining gas by default: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.2 <0.7.0; // THIS CONTRACT CONTAINS A BUG - DO NOT USE @@ -100,6 +102,7 @@ outlined further below: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.11 <0.7.0; contract Fund { @@ -197,6 +200,7 @@ Never use tx.origin for authorization. Let's say you have a wallet contract like :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; // THIS CONTRACT CONTAINS A BUG - DO NOT USE @@ -217,6 +221,7 @@ Now someone tricks you into sending Ether to the address of this attack wallet: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; interface TxUserWallet { @@ -277,6 +282,7 @@ field of a ``struct`` that is the base type of a dynamic storage array. The :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; contract Map { @@ -555,6 +561,7 @@ not mean loss of proving power. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0; pragma experimental SMTChecker; // This may report a warning if no SMT solver available. @@ -609,6 +616,7 @@ types. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0; pragma experimental SMTChecker; // This will report a warning diff --git a/docs/structure-of-a-contract.rst b/docs/structure-of-a-contract.rst index b6d70c5a3..8e744bef2 100644 --- a/docs/structure-of-a-contract.rst +++ b/docs/structure-of-a-contract.rst @@ -26,6 +26,7 @@ storage. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract SimpleStorage { @@ -46,6 +47,7 @@ Functions are the executable units of code within a contract. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract SimpleAuction { @@ -74,6 +76,7 @@ Like functions, modifiers can be :ref:`overridden `. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; contract Purchase { @@ -101,6 +104,7 @@ Events are convenience interfaces with the EVM logging facilities. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.21 <0.7.0; contract SimpleAuction { @@ -125,6 +129,7 @@ Structs are custom defined types that can group several variables (see :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract Ballot { @@ -146,6 +151,7 @@ Enums can be used to create custom types with a finite set of 'constant values' :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract Purchase { diff --git a/docs/style-guide.rst b/docs/style-guide.rst index c2990824d..9d51bb224 100644 --- a/docs/style-guide.rst +++ b/docs/style-guide.rst @@ -55,6 +55,7 @@ Surround top level declarations in solidity source with two blank lines. Yes:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract A { @@ -73,6 +74,7 @@ Yes:: No:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract A { @@ -92,6 +94,7 @@ Blank lines may be omitted between groups of related one-liners (such as stub fu Yes:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; abstract contract A { @@ -112,6 +115,7 @@ Yes:: No:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; abstract contract A { @@ -246,6 +250,7 @@ Import statements should always be placed at the top of the file. Yes:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; import "./Owned.sol"; @@ -260,6 +265,7 @@ Yes:: No:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract A { @@ -293,6 +299,7 @@ Within a grouping, place the ``view`` and ``pure`` functions last. Yes:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; contract A { @@ -329,6 +336,7 @@ Yes:: No:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.0; contract A { @@ -436,6 +444,7 @@ should: Yes:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract Coin { @@ -447,6 +456,7 @@ Yes:: No:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract Coin @@ -747,6 +757,7 @@ manner as modifiers if the function declaration is long or hard to read. Yes:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; // Base contracts just to make this compile @@ -779,6 +790,7 @@ Yes:: No:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; @@ -1002,6 +1014,7 @@ As shown in the example below, if the contract name is ``Congress`` and the libr Yes:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; @@ -1025,6 +1038,7 @@ Yes:: and in ``Congress.sol``:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; import "./Owned.sol"; @@ -1036,6 +1050,7 @@ and in ``Congress.sol``:: No:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; @@ -1140,6 +1155,7 @@ multiline comment starting with ``/**`` and ending with ``*/``. For example, the contract from `a simple smart contract `_ with the comments added looks like the one below:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; diff --git a/docs/types/mapping-types.rst b/docs/types/mapping-types.rst index d84da8ec5..5226f36a3 100644 --- a/docs/types/mapping-types.rst +++ b/docs/types/mapping-types.rst @@ -41,6 +41,7 @@ contract that returns the value at the specified address. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract MappingExample { @@ -66,6 +67,7 @@ The example below uses ``_allowances`` to record the amount someone else is allo :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; contract MappingExample { @@ -120,6 +122,7 @@ the ``sum`` function iterates over to sum all the values. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; struct IndexValue { uint keyIndex; uint value; } diff --git a/docs/types/operators.rst b/docs/types/operators.rst index c65e545c5..76726ec6f 100644 --- a/docs/types/operators.rst +++ b/docs/types/operators.rst @@ -42,6 +42,7 @@ value it referred to previously. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; contract DeleteExample { diff --git a/docs/types/reference-types.rst b/docs/types/reference-types.rst index f7aca7190..5a59997c4 100644 --- a/docs/types/reference-types.rst +++ b/docs/types/reference-types.rst @@ -57,6 +57,7 @@ Data locations are not only relevant for persistency of data, but also for the s :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.5.0 <0.7.0; contract C { @@ -167,6 +168,7 @@ or create a new memory array and copy every element. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract C { @@ -198,6 +200,7 @@ the first element to ``uint``. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract C { @@ -214,6 +217,7 @@ memory arrays, i.e. the following is not possible: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.0 <0.7.0; // This will not compile. @@ -274,6 +278,7 @@ Array Members :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; contract ArrayContract { @@ -406,6 +411,7 @@ Array slices are useful to ABI-decode secondary data passed in function paramete :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; contract Proxy { @@ -443,6 +449,7 @@ shown in the following example: :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; // Defines a new type with two fields. diff --git a/docs/types/value-types.rst b/docs/types/value-types.rst index 65cbd5504..29a91c836 100644 --- a/docs/types/value-types.rst +++ b/docs/types/value-types.rst @@ -543,6 +543,7 @@ subsequent unsigned integer values starting from ``0``. :: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; contract test { @@ -653,6 +654,7 @@ External (or public) functions have the following members: Example that shows how to use the members:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; // This will report a warning @@ -671,6 +673,7 @@ Example that shows how to use the members:: Example that shows how to use internal function types:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.7.0; library ArrayUtils { @@ -728,6 +731,7 @@ Example that shows how to use internal function types:: Another example that uses external function types:: + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.22 <0.7.0; diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index 84b4ef9d7..9009fac01 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -617,6 +617,7 @@ Assume you have the following contracts you want to update declared in ``Source. .. code-block:: none // This will not compile after 0.5.0 + // SPDX-License-Identifier: GPL-3.0 pragma solidity >0.4.23 <0.5.0; contract Updateable { @@ -698,6 +699,7 @@ The command above applies all changes as shown below. Please review them careful .. code-block:: solidity + // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.7.0; abstract contract Updateable { From 098cfd333f322212458e37dbe1f679c187a8671d Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 13 May 2020 22:29:35 +0100 Subject: [PATCH 85/89] Update EVMC to 7.2.0 --- test/evmc/README.md | 2 +- test/evmc/evmc.h | 4 +- test/evmc/evmc.hpp | 252 ++++++++++++++++++++++++-------------- test/evmc/mocked_host.hpp | 3 +- 4 files changed, 167 insertions(+), 94 deletions(-) diff --git a/test/evmc/README.md b/test/evmc/README.md index 436a47e68..1d5d55422 100644 --- a/test/evmc/README.md +++ b/test/evmc/README.md @@ -1,3 +1,3 @@ # EVMC -This is an import of [EVMC](https://github.com/ethereum/evmc) version [7.1.0](https://github.com/ethereum/evmc/releases/tag/v7.1.0). +This is an import of [EVMC](https://github.com/ethereum/evmc) version [7.2.0](https://github.com/ethereum/evmc/releases/tag/v7.2.0). diff --git a/test/evmc/evmc.h b/test/evmc/evmc.h index 3fc3ca610..51d9f842a 100644 --- a/test/evmc/evmc.h +++ b/test/evmc/evmc.h @@ -345,8 +345,8 @@ struct evmc_result /** * The amount of gas left after the execution. * - * If evmc_result::code is not ::EVMC_SUCCESS nor ::EVMC_REVERT - * the value MUST be 0. + * If evmc_result::status_code is neither ::EVMC_SUCCESS nor ::EVMC_REVERT + * the value MUST be 0. */ int64_t gas_left; diff --git a/test/evmc/evmc.hpp b/test/evmc/evmc.hpp index 0b44cd12c..36f9063b3 100644 --- a/test/evmc/evmc.hpp +++ b/test/evmc/evmc.hpp @@ -25,6 +25,33 @@ struct address : evmc_address /// Initializes bytes to zeros if not other @p init value provided. constexpr address(evmc_address init = {}) noexcept : evmc_address{init} {} + /// Converting constructor from unsigned integer value. + /// + /// This constructor assigns the @p v value to the last 8 bytes [12:19] + /// in big-endian order. + constexpr explicit address(uint64_t v) noexcept + : evmc_address{{0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + static_cast(v >> 56), + static_cast(v >> 48), + static_cast(v >> 40), + static_cast(v >> 32), + static_cast(v >> 24), + static_cast(v >> 16), + static_cast(v >> 8), + static_cast(v >> 0)}} + {} + /// Explicit operator converting to bool. constexpr inline explicit operator bool() const noexcept; }; @@ -39,6 +66,45 @@ struct bytes32 : evmc_bytes32 /// Initializes bytes to zeros if not other @p init value provided. constexpr bytes32(evmc_bytes32 init = {}) noexcept : evmc_bytes32{init} {} + /// Converting constructor from unsigned integer value. + /// + /// This constructor assigns the @p v value to the last 8 bytes [24:31] + /// in big-endian order. + constexpr explicit bytes32(uint64_t v) noexcept + : evmc_bytes32{{0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + static_cast(v >> 56), + static_cast(v >> 48), + static_cast(v >> 40), + static_cast(v >> 32), + static_cast(v >> 24), + static_cast(v >> 16), + static_cast(v >> 8), + static_cast(v >> 0)}} + {} + /// Explicit operator converting to bool. constexpr inline explicit operator bool() const noexcept; }; @@ -50,7 +116,6 @@ using uint256be = bytes32; /// Loads 64 bits / 8 bytes of data from the given @p bytes array in big-endian order. constexpr inline uint64_t load64be(const uint8_t* bytes) noexcept { - // TODO: Report bug in clang incorrectly optimizing this with AVX2 enabled. return (uint64_t{bytes[0]} << 56) | (uint64_t{bytes[1]} << 48) | (uint64_t{bytes[2]} << 40) | (uint64_t{bytes[3]} << 32) | (uint64_t{bytes[4]} << 24) | (uint64_t{bytes[5]} << 16) | (uint64_t{bytes[6]} << 8) | uint64_t{bytes[7]}; @@ -76,7 +141,7 @@ constexpr inline uint64_t fnv1a_by64(uint64_t h, uint64_t x) noexcept } // namespace fnv -/// The "equal" comparison operator for the evmc::address type. +/// The "equal to" comparison operator for the evmc::address type. constexpr bool operator==(const address& a, const address& b) noexcept { // TODO: Report bug in clang keeping unnecessary bswap. @@ -85,23 +150,41 @@ constexpr bool operator==(const address& a, const address& b) noexcept load32be(&a.bytes[16]) == load32be(&b.bytes[16]); } -/// The "not equal" comparison operator for the evmc::address type. +/// The "not equal to" comparison operator for the evmc::address type. constexpr bool operator!=(const address& a, const address& b) noexcept { return !(a == b); } -/// The "less" comparison operator for the evmc::address type. +/// The "less than" comparison operator for the evmc::address type. constexpr bool operator<(const address& a, const address& b) noexcept { return load64be(&a.bytes[0]) < load64be(&b.bytes[0]) || (load64be(&a.bytes[0]) == load64be(&b.bytes[0]) && - load64be(&a.bytes[8]) < load64be(&b.bytes[8])) || - (load64be(&a.bytes[8]) == load64be(&b.bytes[8]) && - load32be(&a.bytes[16]) < load32be(&b.bytes[16])); + (load64be(&a.bytes[8]) < load64be(&b.bytes[8]) || + (load64be(&a.bytes[8]) == load64be(&b.bytes[8]) && + load32be(&a.bytes[16]) < load32be(&b.bytes[16])))); } -/// The "equal" comparison operator for the evmc::bytes32 type. +/// The "greater than" comparison operator for the evmc::address type. +constexpr bool operator>(const address& a, const address& b) noexcept +{ + return b < a; +} + +/// The "less than or equal to" comparison operator for the evmc::address type. +constexpr bool operator<=(const address& a, const address& b) noexcept +{ + return !(b < a); +} + +/// The "greater than or equal to" comparison operator for the evmc::address type. +constexpr bool operator>=(const address& a, const address& b) noexcept +{ + return !(a < b); +} + +/// The "equal to" comparison operator for the evmc::bytes32 type. constexpr bool operator==(const bytes32& a, const bytes32& b) noexcept { return load64be(&a.bytes[0]) == load64be(&b.bytes[0]) && @@ -110,22 +193,40 @@ constexpr bool operator==(const bytes32& a, const bytes32& b) noexcept load64be(&a.bytes[24]) == load64be(&b.bytes[24]); } -/// The "not equal" comparison operator for the evmc::bytes32 type. +/// The "not equal to" comparison operator for the evmc::bytes32 type. constexpr bool operator!=(const bytes32& a, const bytes32& b) noexcept { return !(a == b); } -/// The "less" comparison operator for the evmc::bytes32 type. +/// The "less than" comparison operator for the evmc::bytes32 type. constexpr bool operator<(const bytes32& a, const bytes32& b) noexcept { return load64be(&a.bytes[0]) < load64be(&b.bytes[0]) || (load64be(&a.bytes[0]) == load64be(&b.bytes[0]) && - load64be(&a.bytes[8]) < load64be(&b.bytes[8])) || - (load64be(&a.bytes[8]) == load64be(&b.bytes[8]) && - load64be(&a.bytes[16]) < load64be(&b.bytes[16])) || - (load64be(&a.bytes[16]) == load64be(&b.bytes[16]) && - load64be(&a.bytes[24]) < load64be(&b.bytes[24])); + (load64be(&a.bytes[8]) < load64be(&b.bytes[8]) || + (load64be(&a.bytes[8]) == load64be(&b.bytes[8]) && + (load64be(&a.bytes[16]) < load64be(&b.bytes[16]) || + (load64be(&a.bytes[16]) == load64be(&b.bytes[16]) && + load64be(&a.bytes[24]) < load64be(&b.bytes[24])))))); +} + +/// The "greater than" comparison operator for the evmc::bytes32 type. +constexpr bool operator>(const bytes32& a, const bytes32& b) noexcept +{ + return b < a; +} + +/// The "less than or equal to" comparison operator for the evmc::bytes32 type. +constexpr bool operator<=(const bytes32& a, const bytes32& b) noexcept +{ + return !(b < a); +} + +/// The "greater than or equal to" comparison operator for the evmc::bytes32 type. +constexpr bool operator>=(const bytes32& a, const bytes32& b) noexcept +{ + return !(a < b); } /// Checks if the given address is the zero address. @@ -154,108 +255,72 @@ namespace literals { namespace internal { -template -struct integer_sequence +constexpr size_t length(const char* s) noexcept { -}; - -template -using byte_sequence = integer_sequence; - -template -using char_sequence = integer_sequence; - - -template -struct concatenate; - -template -struct concatenate, byte_sequence> -{ - using type = byte_sequence; -}; - -template -constexpr uint8_t parse_hex_digit() noexcept -{ - static_assert((D >= '0' && D <= '9') || (D >= 'a' && D <= 'f') || (D >= 'A' && D <= 'F'), - "literal must be hexadecimal integer"); - return static_cast( - (D >= '0' && D <= '9') ? D - '0' : (D >= 'a' && D <= 'f') ? D - 'a' + 10 : D - 'A' + 10); + return (*s != '\0') ? length(s + 1) + 1 : 0; } - -template -struct parse_digits; - -template -struct parse_digits> +constexpr int from_hex(char c) noexcept { - using type = byte_sequence(parse_hex_digit() << 4) | - parse_hex_digit()>; -}; + return (c >= 'a' && c <= 'f') ? c - ('a' - 10) : + (c >= 'A' && c <= 'F') ? c - ('A' - 10) : c - '0'; +} -template -struct parse_digits> +constexpr uint8_t byte(const char* s, size_t i) noexcept { - using type = typename concatenate>::type, - typename parse_digits>::type>::type; -}; + return static_cast((from_hex(s[2 * i]) << 4) | from_hex(s[2 * i + 1])); +} +template +T from_hex(const char*) noexcept; -template -struct parse_literal; - -template -struct parse_literal> +template <> +constexpr bytes32 from_hex(const char* s) noexcept { - static_assert(Prefix1 == '0' && Prefix2 == 'x', "literal must be in hexadecimal notation"); - static_assert(sizeof...(Literal) == sizeof(T) * 2, "literal must match the result type size"); + return { + {{byte(s, 0), byte(s, 1), byte(s, 2), byte(s, 3), byte(s, 4), byte(s, 5), byte(s, 6), + byte(s, 7), byte(s, 8), byte(s, 9), byte(s, 10), byte(s, 11), byte(s, 12), byte(s, 13), + byte(s, 14), byte(s, 15), byte(s, 16), byte(s, 17), byte(s, 18), byte(s, 19), byte(s, 20), + byte(s, 21), byte(s, 22), byte(s, 23), byte(s, 24), byte(s, 25), byte(s, 26), byte(s, 27), + byte(s, 28), byte(s, 29), byte(s, 30), byte(s, 31)}}}; +} - template - static constexpr T create_from(byte_sequence) noexcept - { - return T{{{Bytes...}}}; - } - - static constexpr T get() noexcept - { - return create_from(typename parse_digits>::type{}); - } -}; - -template -struct parse_literal> +template <> +constexpr address from_hex
(const char* s) noexcept { - static_assert(Digit == '0', "only 0 is allowed as a single digit literal"); - static constexpr T get() noexcept { return {}; } -}; + return { + {{byte(s, 0), byte(s, 1), byte(s, 2), byte(s, 3), byte(s, 4), byte(s, 5), byte(s, 6), + byte(s, 7), byte(s, 8), byte(s, 9), byte(s, 10), byte(s, 11), byte(s, 12), byte(s, 13), + byte(s, 14), byte(s, 15), byte(s, 16), byte(s, 17), byte(s, 18), byte(s, 19)}}}; +} -template -constexpr T parse() noexcept +template +constexpr T from_literal(const char* s) { - return parse_literal>::get(); + return (s[0] == '0' && s[1] == '\0') ? + T{} : + !(s[0] == '0' && s[1] == 'x') ? + throw "literal must be in hexadecimal notation" : + (length(s + 2) != sizeof(T) * 2) ? throw "literal must match the result type size" : + from_hex(s + 2); } } // namespace internal /// Literal for evmc::address. -template -constexpr address operator"" _address() noexcept +constexpr address operator""_address(const char* s) noexcept { - return internal::parse(); + return internal::from_literal
(s); } /// Literal for evmc::bytes32. -template -constexpr bytes32 operator"" _bytes32() noexcept +constexpr bytes32 operator""_bytes32(const char* s) noexcept { - return internal::parse(); + return internal::from_literal(s); } } // namespace literals using namespace literals; - /// Alias for evmc_make_result(). constexpr auto make_result = evmc_make_result; @@ -626,6 +691,13 @@ public: m_instance->execute(m_instance, nullptr, nullptr, rev, &msg, code, code_size)}; } + /// Returns the pointer to C EVMC struct representing the VM. + /// + /// Gives access to the C EVMC VM struct to allow advanced interaction with the VM not supported + /// by the C++ interface. Use as the last resort. + /// This object still owns the VM after returning the pointer. The returned pointer MAY be null. + evmc_vm* get_raw_pointer() const noexcept { return m_instance; } + private: evmc_vm* m_instance = nullptr; }; diff --git a/test/evmc/mocked_host.hpp b/test/evmc/mocked_host.hpp index 2ff1701a4..57f0cb79b 100644 --- a/test/evmc/mocked_host.hpp +++ b/test/evmc/mocked_host.hpp @@ -133,10 +133,11 @@ public: /// The record of all SELFDESTRUCTs from the selfdestruct() method. std::vector recorded_selfdestructs; -protected: +private: /// The copy of call inputs for the recorded_calls record. std::vector m_recorded_calls_inputs; +public: /// Record an account access. /// @param addr The address of the accessed account. void record_account_access(const address& addr) const From 7353804252b56d97bd5075d75feb569f9a737916 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 13 May 2020 22:37:07 +0100 Subject: [PATCH 86/89] EVMHost: simplify code using new evmc features --- test/EVMHost.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/EVMHost.cpp b/test/EVMHost.cpp index 3c9e6449e..505964aa0 100644 --- a/test/EVMHost.cpp +++ b/test/EVMHost.cpp @@ -99,17 +99,16 @@ EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM& _vm): evmc::address address{}; address.bytes[19] = precompiledAddress; // 1wei - accounts[address].balance.bytes[31] = 1; + accounts[address].balance = evmc::uint256be{1}; } - // TODO: support short literals in EVMC and use them here - tx_context.block_difficulty = convertToEVMC(u256("200000000")); + tx_context.block_difficulty = evmc::uint256be{200000000}; tx_context.block_gas_limit = 20000000; tx_context.block_coinbase = 0x7878787878787878787878787878787878787878_address; - tx_context.tx_gas_price = convertToEVMC(u256("3000000000")); + tx_context.tx_gas_price = evmc::uint256be{3000000000}; tx_context.tx_origin = 0x9292929292929292929292929292929292929292_address; // Mainnet according to EIP-155 - tx_context.chain_id = convertToEVMC(u256(1)); + tx_context.chain_id = evmc::uint256be{1}; } void EVMHost::selfdestruct(const evmc::address& _addr, const evmc::address& _beneficiary) noexcept From c9745ea10132cd7a04c0685ac72629d4e5145767 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 13 May 2020 22:38:50 +0100 Subject: [PATCH 87/89] EVMHost: enable support for Berlin --- test/EVMHost.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/EVMHost.cpp b/test/EVMHost.cpp index 505964aa0..836d61057 100644 --- a/test/EVMHost.cpp +++ b/test/EVMHost.cpp @@ -81,12 +81,14 @@ EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM& _vm): m_evmRevision = EVMC_BYZANTIUM; else if (_evmVersion == langutil::EVMVersion::constantinople()) m_evmRevision = EVMC_CONSTANTINOPLE; + else if (_evmVersion == langutil::EVMVersion::petersburg()) + m_evmRevision = EVMC_PETERSBURG; else if (_evmVersion == langutil::EVMVersion::istanbul()) m_evmRevision = EVMC_ISTANBUL; else if (_evmVersion == langutil::EVMVersion::berlin()) - assertThrow(false, Exception, "Berlin is not supported yet."); - else //if (_evmVersion == langutil::EVMVersion::petersburg()) - m_evmRevision = EVMC_PETERSBURG; + m_evmRevision = EVMC_BERLIN; + else + assertThrow(false, Exception, "Unsupported EVM version"); // Mark all precompiled contracts as existing. Existing here means to have a balance (as per EIP-161). // NOTE: keep this in sync with `EVMHost::call` below. From 6308ca4a228e38f3b93d70337297e9bbd4bfc8dc Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 12 May 2020 21:01:39 +0200 Subject: [PATCH 88/89] Binary transform for br and br_if. --- Changelog.md | 1 + libyul/backends/wasm/BinaryTransform.cpp | 43 +- libyul/backends/wasm/BinaryTransform.h | 4 +- libyul/backends/wasm/TextTransform.cpp | 2 +- test/cmdlineTests/evm_to_wasm_break/args | 1 + test/cmdlineTests/evm_to_wasm_break/err | 1 + test/cmdlineTests/evm_to_wasm_break/input.sol | 8 + test/cmdlineTests/evm_to_wasm_break/output | 551 ++++++++++++++++++ .../ewasmTranslationTests/loop_break.yul | 13 + .../ewasmTranslationTests/loop_continue.yul | 22 + 10 files changed, 631 insertions(+), 15 deletions(-) create mode 100644 test/cmdlineTests/evm_to_wasm_break/args create mode 100644 test/cmdlineTests/evm_to_wasm_break/err create mode 100644 test/cmdlineTests/evm_to_wasm_break/input.sol create mode 100644 test/cmdlineTests/evm_to_wasm_break/output create mode 100644 test/libyul/ewasmTranslationTests/loop_break.yul create mode 100644 test/libyul/ewasmTranslationTests/loop_continue.yul diff --git a/Changelog.md b/Changelog.md index 1faf29393..53c77ce9c 100644 --- a/Changelog.md +++ b/Changelog.md @@ -13,6 +13,7 @@ Language Features: Compiler Features: * Commandline Interface: Don't ignore `--yul-optimizations` in assembly mode. * Allow using abi encoding functions for calldata array slices without explicit casts. + * Wasm binary output: Implement ``br`` and ``br_if``. diff --git a/libyul/backends/wasm/BinaryTransform.cpp b/libyul/backends/wasm/BinaryTransform.cpp index ad2628695..249d87a33 100644 --- a/libyul/backends/wasm/BinaryTransform.cpp +++ b/libyul/backends/wasm/BinaryTransform.cpp @@ -358,13 +358,13 @@ bytes BinaryTransform::operator()(If const& _if) toBytes(Opcode::If) + toBytes(ValueType::Void); - m_labels.push({}); + m_labels.emplace_back(); result += visit(_if.statements); if (_if.elseStatements) result += toBytes(Opcode::Else) + visit(*_if.elseStatements); - m_labels.pop(); + m_labels.pop_back(); result += toBytes(Opcode::End); return result; @@ -374,26 +374,24 @@ bytes BinaryTransform::operator()(Loop const& _loop) { bytes result = toBytes(Opcode::Loop) + toBytes(ValueType::Void); - m_labels.push(_loop.labelName); + m_labels.emplace_back(_loop.labelName); result += visit(_loop.statements); - m_labels.pop(); + m_labels.pop_back(); result += toBytes(Opcode::End); return result; } -bytes BinaryTransform::operator()(Break const&) +bytes BinaryTransform::operator()(Break const& _break) { - yulAssert(false, "br not yet implemented."); - // TODO the index is just the nesting depth. - return {}; + return toBytes(Opcode::Br) + encodeLabelIdx(_break.label.name); } -bytes BinaryTransform::operator()(BreakIf const&) +bytes BinaryTransform::operator()(BreakIf const& _breakIf) { - yulAssert(false, "br_if not yet implemented."); - // TODO the index is just the nesting depth. - return {}; + bytes result = std::visit(*this, *_breakIf.condition); + result += toBytes(Opcode::BrIf) + encodeLabelIdx(_breakIf.label.name); + return result; } bytes BinaryTransform::operator()(Return const&) @@ -403,11 +401,14 @@ bytes BinaryTransform::operator()(Return const&) bytes BinaryTransform::operator()(Block const& _block) { - return + m_labels.emplace_back(_block.labelName); + bytes result = toBytes(Opcode::Block) + toBytes(ValueType::Void) + visit(_block.statements) + toBytes(Opcode::End); + m_labels.pop_back(); + return result; } bytes BinaryTransform::operator()(FunctionDefinition const& _function) @@ -427,9 +428,13 @@ bytes BinaryTransform::operator()(FunctionDefinition const& _function) for (size_t i = 0; i < _function.locals.size(); ++i) m_locals[_function.locals[i].variableName] = varIdx++; + yulAssert(m_labels.empty(), "Stray labels."); + ret += visit(_function.body); ret += toBytes(Opcode::End); + yulAssert(m_labels.empty(), "Stray labels."); + return prefixSize(std::move(ret)); } @@ -581,6 +586,18 @@ bytes BinaryTransform::visitReversed(vector const& _expressions) return result; } +bytes BinaryTransform::encodeLabelIdx(string const& _label) const +{ + yulAssert(!_label.empty(), "Empty label."); + size_t depth = 0; + for (string const& label: m_labels | boost::adaptors::reversed) + if (label == _label) + return lebEncode(depth); + else + ++depth; + yulAssert(false, "Label not found."); +} + bytes BinaryTransform::encodeName(std::string const& _name) { // UTF-8 is allowed here by the Wasm spec, but since all names here should stem from diff --git a/libyul/backends/wasm/BinaryTransform.h b/libyul/backends/wasm/BinaryTransform.h index d4e4375c2..e11c92bf6 100644 --- a/libyul/backends/wasm/BinaryTransform.h +++ b/libyul/backends/wasm/BinaryTransform.h @@ -77,13 +77,15 @@ private: bytes visit(std::vector const& _expressions); bytes visitReversed(std::vector const& _expressions); + bytes encodeLabelIdx(std::string const& _label) const; + static bytes encodeName(std::string const& _name); std::map m_locals; std::map m_globals; std::map m_functions; std::map m_functionTypes; - std::stack m_labels; + std::vector m_labels; std::map> m_subModulePosAndSize; }; diff --git a/libyul/backends/wasm/TextTransform.cpp b/libyul/backends/wasm/TextTransform.cpp index 3edeb9365..2a2499b61 100644 --- a/libyul/backends/wasm/TextTransform.cpp +++ b/libyul/backends/wasm/TextTransform.cpp @@ -123,7 +123,7 @@ string TextTransform::operator()(wasm::Loop const& _loop) string TextTransform::operator()(wasm::Break const& _break) { - return "(break $" + _break.label.name + ")\n"; + return "(br $" + _break.label.name + ")\n"; } string TextTransform::operator()(wasm::BreakIf const& _break) diff --git a/test/cmdlineTests/evm_to_wasm_break/args b/test/cmdlineTests/evm_to_wasm_break/args new file mode 100644 index 000000000..099ebdc3a --- /dev/null +++ b/test/cmdlineTests/evm_to_wasm_break/args @@ -0,0 +1 @@ +--assemble --optimize --yul-dialect evm --machine ewasm diff --git a/test/cmdlineTests/evm_to_wasm_break/err b/test/cmdlineTests/evm_to_wasm_break/err new file mode 100644 index 000000000..014a1178f --- /dev/null +++ b/test/cmdlineTests/evm_to_wasm_break/err @@ -0,0 +1 @@ +Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/evm_to_wasm_break/input.sol b/test/cmdlineTests/evm_to_wasm_break/input.sol new file mode 100644 index 000000000..a625eea08 --- /dev/null +++ b/test/cmdlineTests/evm_to_wasm_break/input.sol @@ -0,0 +1,8 @@ +{ + let x := calldataload(0) + for { } lt(x, 10) { x := add(x, 1) } { + if eq(x, 2) { break } + if eq(x, 4) { continue } + } + sstore(0, x) +} diff --git a/test/cmdlineTests/evm_to_wasm_break/output b/test/cmdlineTests/evm_to_wasm_break/output new file mode 100644 index 000000000..3ed2a2dd0 --- /dev/null +++ b/test/cmdlineTests/evm_to_wasm_break/output @@ -0,0 +1,551 @@ + +======= evm_to_wasm_break/input.sol (Ewasm) ======= + +Pretty printed source: +object "object" { + code { + { + let x := calldataload(0) + for { } lt(x, 10) { x := add(x, 1) } + { + if eq(x, 2) { break } + if eq(x, 4) { continue } + } + sstore(0, x) + } + } +} + + +========================== + +Translated source: +object "object" { + code { + function main() + { + let _1 := 0 + let x, x_1, x_2, x_3 := calldataload(_1, _1, _1, _1) + let x_4 := x + let x_5 := x_1 + let x_6 := x_2 + let x_7 := x_3 + let _2 := 1 + let _3:i32 := i32.eqz(i32.eqz(i64.eqz(i64.or(i64.or(_1, _1), i64.or(_1, _2))))) + for { } + i32.eqz(_3) + { + let x_8, x_9, x_10, x_11 := add(x_4, x_5, x_6, x_7, _1, _1, _1, _2) + x_4 := x_8 + x_5 := x_9 + x_6 := x_10 + x_7 := x_11 + } + { + let _4, _5, _6, _7 := lt(x_4, x_5, x_6, x_7, _1, _1, _1, 10) + let _8, _9, _10, _11 := iszero(_4, _5, _6, _7) + if i32.eqz(i64.eqz(i64.or(i64.or(_8, _9), i64.or(_10, _11)))) { break } + let _12, _13, _14, _15 := eq(x_4, x_5, x_6, x_7, _1, _1, _1, 2) + if i32.eqz(i64.eqz(i64.or(i64.or(_12, _13), i64.or(_14, _15)))) { break } + let _16, _17, _18, _19 := eq(x_4, x_5, x_6, x_7, _1, _1, _1, 4) + if i32.eqz(i64.eqz(i64.or(i64.or(_16, _17), i64.or(_18, _19)))) { continue } + } + sstore(_1, _1, _1, _1, x_4, x_5, x_6, x_7) + } + function add_carry(x, y, c) -> r, r_c + { + let t := i64.add(x, y) + r := i64.add(t, c) + r_c := i64.extend_i32_u(i32.or(i64.lt_u(t, x), i64.lt_u(r, t))) + } + function add(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4 + { + let t := i64.add(x4, y4) + r4 := i64.add(t, 0) + let r3_1, carry := add_carry(x3, y3, i64.extend_i32_u(i32.or(i64.lt_u(t, x4), i64.lt_u(r4, t)))) + r3 := r3_1 + let r2_1, carry_1 := add_carry(x2, y2, carry) + r2 := r2_1 + let r1_1, carry_2 := add_carry(x1, y1, carry_1) + r1 := r1_1 + } + function iszero(x1, x2, x3, x4) -> r1, r2, r3, r4 + { + r4 := i64.extend_i32_u(i64.eqz(i64.or(i64.or(x1, x2), i64.or(x3, x4)))) + } + function eq(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4 + { + if i64.eq(x1, y1) + { + if i64.eq(x2, y2) + { + if i64.eq(x3, y3) { if i64.eq(x4, y4) { r4 := 1 } } + } + } + } + function cmp(a, b) -> r:i32 + { + switch i64.lt_u(a, b) + case 1:i32 { r := 0xffffffff:i32 } + default { r := i64.ne(a, b) } + } + function lt(x1, x2, x3, x4, y1, y2, y3, y4) -> z1, z2, z3, z4 + { + let z:i32 := false + switch cmp(x1, y1) + case 0:i32 { + switch cmp(x2, y2) + case 0:i32 { + switch cmp(x3, y3) + case 0:i32 { z := i64.lt_u(x4, y4) } + case 1:i32 { z := 0:i32 } + default { z := 1:i32 } + } + case 1:i32 { z := 0:i32 } + default { z := 1:i32 } + } + case 1:i32 { z := 0:i32 } + default { z := 1:i32 } + z4 := i64.extend_i32_u(z) + } + function calldataload(x1, x2, x3, x4) -> z1, z2, z3, z4 + { + if i64.ne(0, i64.or(i64.or(x1, x2), x3)) { unreachable() } + if i64.ne(0, i64.shr_u(x4, 32)) { unreachable() } + eth.callDataCopy(0:i32, i32.wrap_i64(x4), 32:i32) + let z1_1 := endian_swap(i64.load(0:i32)) + let z2_1 := endian_swap(i64.load(i32.add(0:i32, 8:i32))) + let z3_1 := endian_swap(i64.load(i32.add(0:i32, 16:i32))) + let z4_1 := endian_swap(i64.load(i32.add(0:i32, 24:i32))) + z1 := z1_1 + z2 := z2_1 + z3 := z3_1 + z4 := z4_1 + } + function endian_swap_16(x) -> y + { + y := i64.or(i64.and(i64.shl(x, 8), 0xff00), i64.and(i64.shr_u(x, 8), 0xff)) + } + function endian_swap_32(x) -> y + { + let hi := i64.shl(endian_swap_16(x), 16) + y := i64.or(hi, endian_swap_16(i64.shr_u(x, 16))) + } + function endian_swap(x) -> y + { + let hi := i64.shl(endian_swap_32(x), 32) + y := i64.or(hi, endian_swap_32(i64.shr_u(x, 32))) + } + function mstore_internal(pos:i32, y1, y2, y3, y4) + { + i64.store(pos, endian_swap(y1)) + i64.store(i32.add(pos, 8:i32), endian_swap(y2)) + i64.store(i32.add(pos, 16:i32), endian_swap(y3)) + i64.store(i32.add(pos, 24:i32), endian_swap(y4)) + } + function sstore(x1, x2, x3, x4, y1, y2, y3, y4) + { + mstore_internal(0:i32, x1, x2, x3, x4) + mstore_internal(32:i32, y1, y2, y3, y4) + eth.storageStore(0:i32, 32:i32) + } + } +} + + +Binary representation: +0061736d0100000001480a60000060017e017e60027e7e017e60037e7e7e017e60047e7e7e7e017e60057e7e7e7e7e0060087e7e7e7e7e7e7e7e0060087e7e7e7e7e7e7e7e017e60027f7f0060037f7f7f0002310208657468657265756d0c73746f7261676553746f7265000808657468657265756d0c63616c6c44617461436f70790009030e0d0003070407020704010101050605030100010610037e0142000b7e0142000b7e0142000b071102066d656d6f72790200046d61696e00020a80090dee02011f7e4200210002402000200020002000100921012300210223012103230221040b2001210520022106200321072004210842012109200020008420002009848450ada745ada745ad210a02400340200aa745ad500d01024002402005200620072008200020002000420a1008210b2300210c2301210d2302210e0b0240200b200c200d200e1005210f2300211023012111230221120b200f20108420112012848450ada745ad42005204400c030b024020052006200720082000200020004202100621132300211423012115230221160b201320148420152016848450ada745ad42005204400c030b0240200520062007200820002000200042041006211723002118230121192302211a0b20172018842019201a848450ada745ad42005204400c010b0b0240200520062007200820002000200020091004211b2300211c2301211d2302211e0b201b2105201c2106201d2107201e21080b0b20002000200020002005200620072008100e0b2c01037e200020017c2105200520027c21032005200054ada72003200554ada772ada7ad21042004240020030b6f010b7e200320077c210c200c42007c210b024020022006200c200354ada7200b200c54ada772ada7ad1003210d2300210e0b200d210a024020012005200e1003210f230021100b200f2109024020002004201010032111230021120b2011210820092400200a2401200b240220080b2301047e200020018420022003848450ada7ad210720052400200624012007240220040b4601047e2000200451ad42005204402001200551ad42005204402002200651ad42005204402003200751ad42005204404201210b0b0b0b0b20092400200a2401200b240220080b2a01027e02402000200154ad21032003420151044042ffffffff0f2102052000200152ad21020b0b20020b930101087e4200210c0240200020041007210d200d42005104400240200120051007210e200e42005104400240200220061007210f200f42005104402003200754ad210c05200f42015104404200210c054201210c0b0b0b05200e42015104404200210c054201210c0b0b0b05200d42015104404200210c054201210c0b0b0b200ca7ad210b20092400200a2401200b240220080b8c0101087e4200200020018420028452ad4200520440000b4200200342208852ad4200520440000b4200a72003a7ada74220a710014200a7290300100c21084200a74208a76aada7290300100c21094200a74210a76aada7290300100c210a4200a74218a76aada7290300100c210b2008210420092105200a2106200b210720052400200624012007240220040b1c01017e20004208864280fe0383200042088842ff018384210120010b1b01027e2000100a421086210220022000421088100a84210120010b1b01027e2000100b422086210220022000422088100b84210120010b3e01007e2000a72001100c3703002000a74208a76aada72002100c3703002000a74210a76aada72003100c3703002000a74218a76aada72004100c3703000b2401007e42002000200120022003100d42202004200520062007100d4200a74220a710000b + +Text representation: +(module + (import "ethereum" "storageStore" (func $eth.storageStore (param i32 i32))) + (import "ethereum" "callDataCopy" (func $eth.callDataCopy (param i32 i32 i32))) + (memory $memory (export "memory") 1) + (export "main" (func $main)) + (global $global_ (mut i64) (i64.const 0)) + (global $global__1 (mut i64) (i64.const 0)) + (global $global__2 (mut i64) (i64.const 0)) + +(func $main + (local $_1 i64) + (local $x i64) + (local $x_1 i64) + (local $x_2 i64) + (local $x_3 i64) + (local $x_4 i64) + (local $x_5 i64) + (local $x_6 i64) + (local $x_7 i64) + (local $_2 i64) + (local $_3 i64) + (local $_4 i64) + (local $_5 i64) + (local $_6 i64) + (local $_7 i64) + (local $_8 i64) + (local $_9 i64) + (local $_10 i64) + (local $_11 i64) + (local $_12 i64) + (local $_13 i64) + (local $_14 i64) + (local $_15 i64) + (local $_16 i64) + (local $_17 i64) + (local $_18 i64) + (local $_19 i64) + (local $x_8 i64) + (local $x_9 i64) + (local $x_10 i64) + (local $x_11 i64) + (local.set $_1 (i64.const 0)) + (block + (local.set $x (call $calldataload (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))) + (local.set $x_1 (global.get $global_)) + (local.set $x_2 (global.get $global__1)) + (local.set $x_3 (global.get $global__2)) + + ) + (local.set $x_4 (local.get $x)) + (local.set $x_5 (local.get $x_1)) + (local.set $x_6 (local.get $x_2)) + (local.set $x_7 (local.get $x_3)) + (local.set $_2 (i64.const 1)) + (local.set $_3 (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $_1) (local.get $_1)) (i64.or (local.get $_1) (local.get $_2)))))))))))) + (block $label_ + (loop + (br_if $label_ (i64.eqz (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (local.get $_3)))))) + (block $label__3 + (block + (local.set $_4 (call $lt (local.get $x_4) (local.get $x_5) (local.get $x_6) (local.get $x_7) (local.get $_1) (local.get $_1) (local.get $_1) (i64.const 10))) + (local.set $_5 (global.get $global_)) + (local.set $_6 (global.get $global__1)) + (local.set $_7 (global.get $global__2)) + + ) + (block + (local.set $_8 (call $iszero (local.get $_4) (local.get $_5) (local.get $_6) (local.get $_7))) + (local.set $_9 (global.get $global_)) + (local.set $_10 (global.get $global__1)) + (local.set $_11 (global.get $global__2)) + + ) + (if (i64.ne (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $_8) (local.get $_9)) (i64.or (local.get $_10) (local.get $_11)))))))) (i64.const 0)) (then + (br $label_) + )) + (block + (local.set $_12 (call $eq (local.get $x_4) (local.get $x_5) (local.get $x_6) (local.get $x_7) (local.get $_1) (local.get $_1) (local.get $_1) (i64.const 2))) + (local.set $_13 (global.get $global_)) + (local.set $_14 (global.get $global__1)) + (local.set $_15 (global.get $global__2)) + + ) + (if (i64.ne (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $_12) (local.get $_13)) (i64.or (local.get $_14) (local.get $_15)))))))) (i64.const 0)) (then + (br $label_) + )) + (block + (local.set $_16 (call $eq (local.get $x_4) (local.get $x_5) (local.get $x_6) (local.get $x_7) (local.get $_1) (local.get $_1) (local.get $_1) (i64.const 4))) + (local.set $_17 (global.get $global_)) + (local.set $_18 (global.get $global__1)) + (local.set $_19 (global.get $global__2)) + + ) + (if (i64.ne (i64.extend_i32_u (i32.eqz (i32.wrap_i64 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $_16) (local.get $_17)) (i64.or (local.get $_18) (local.get $_19)))))))) (i64.const 0)) (then + (br $label__3) + )) + + ) + (block + (local.set $x_8 (call $add (local.get $x_4) (local.get $x_5) (local.get $x_6) (local.get $x_7) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_2))) + (local.set $x_9 (global.get $global_)) + (local.set $x_10 (global.get $global__1)) + (local.set $x_11 (global.get $global__2)) + + ) + (local.set $x_4 (local.get $x_8)) + (local.set $x_5 (local.get $x_9)) + (local.set $x_6 (local.get $x_10)) + (local.set $x_7 (local.get $x_11)) + ) + + ) + (call $sstore (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $x_4) (local.get $x_5) (local.get $x_6) (local.get $x_7)) +) + +(func $add_carry + (param $x i64) + (param $y i64) + (param $c i64) + (result i64) + (local $r i64) + (local $r_c i64) + (local $t i64) + (local.set $t (i64.add (local.get $x) (local.get $y))) + (local.set $r (i64.add (local.get $t) (local.get $c))) + (local.set $r_c (i64.extend_i32_u (i32.wrap_i64 (i64.extend_i32_u (i32.or (i32.wrap_i64 (i64.extend_i32_u (i64.lt_u (local.get $t) (local.get $x)))) (i32.wrap_i64 (i64.extend_i32_u (i64.lt_u (local.get $r) (local.get $t))))))))) + (global.set $global_ (local.get $r_c)) + (local.get $r) +) + +(func $add + (param $x1 i64) + (param $x2 i64) + (param $x3 i64) + (param $x4 i64) + (param $y1 i64) + (param $y2 i64) + (param $y3 i64) + (param $y4 i64) + (result i64) + (local $r1 i64) + (local $r2 i64) + (local $r3 i64) + (local $r4 i64) + (local $t i64) + (local $r3_1 i64) + (local $carry i64) + (local $r2_1 i64) + (local $carry_1 i64) + (local $r1_1 i64) + (local $carry_2 i64) + (local.set $t (i64.add (local.get $x4) (local.get $y4))) + (local.set $r4 (i64.add (local.get $t) (i64.const 0))) + (block + (local.set $r3_1 (call $add_carry (local.get $x3) (local.get $y3) (i64.extend_i32_u (i32.wrap_i64 (i64.extend_i32_u (i32.or (i32.wrap_i64 (i64.extend_i32_u (i64.lt_u (local.get $t) (local.get $x4)))) (i32.wrap_i64 (i64.extend_i32_u (i64.lt_u (local.get $r4) (local.get $t)))))))))) + (local.set $carry (global.get $global_)) + + ) + (local.set $r3 (local.get $r3_1)) + (block + (local.set $r2_1 (call $add_carry (local.get $x2) (local.get $y2) (local.get $carry))) + (local.set $carry_1 (global.get $global_)) + + ) + (local.set $r2 (local.get $r2_1)) + (block + (local.set $r1_1 (call $add_carry (local.get $x1) (local.get $y1) (local.get $carry_1))) + (local.set $carry_2 (global.get $global_)) + + ) + (local.set $r1 (local.get $r1_1)) + (global.set $global_ (local.get $r2)) + (global.set $global__1 (local.get $r3)) + (global.set $global__2 (local.get $r4)) + (local.get $r1) +) + +(func $iszero + (param $x1 i64) + (param $x2 i64) + (param $x3 i64) + (param $x4 i64) + (result i64) + (local $r1 i64) + (local $r2 i64) + (local $r3 i64) + (local $r4 i64) + (local.set $r4 (i64.extend_i32_u (i32.wrap_i64 (i64.extend_i32_u (i64.eqz (i64.or (i64.or (local.get $x1) (local.get $x2)) (i64.or (local.get $x3) (local.get $x4)))))))) + (global.set $global_ (local.get $r2)) + (global.set $global__1 (local.get $r3)) + (global.set $global__2 (local.get $r4)) + (local.get $r1) +) + +(func $eq + (param $x1 i64) + (param $x2 i64) + (param $x3 i64) + (param $x4 i64) + (param $y1 i64) + (param $y2 i64) + (param $y3 i64) + (param $y4 i64) + (result i64) + (local $r1 i64) + (local $r2 i64) + (local $r3 i64) + (local $r4 i64) + (if (i64.ne (i64.extend_i32_u (i64.eq (local.get $x1) (local.get $y1))) (i64.const 0)) (then + (if (i64.ne (i64.extend_i32_u (i64.eq (local.get $x2) (local.get $y2))) (i64.const 0)) (then + (if (i64.ne (i64.extend_i32_u (i64.eq (local.get $x3) (local.get $y3))) (i64.const 0)) (then + (if (i64.ne (i64.extend_i32_u (i64.eq (local.get $x4) (local.get $y4))) (i64.const 0)) (then + (local.set $r4 (i64.const 1)) + )) + )) + )) + )) + (global.set $global_ (local.get $r2)) + (global.set $global__1 (local.get $r3)) + (global.set $global__2 (local.get $r4)) + (local.get $r1) +) + +(func $cmp + (param $a i64) + (param $b i64) + (result i64) + (local $r i64) + (local $condition i64) + (block + (local.set $condition (i64.extend_i32_u (i64.lt_u (local.get $a) (local.get $b)))) + (if (i64.eq (local.get $condition) (i64.const 1)) (then + (local.set $r (i64.const 4294967295)) + )(else + (local.set $r (i64.extend_i32_u (i64.ne (local.get $a) (local.get $b)))) + )) + + ) + (local.get $r) +) + +(func $lt + (param $x1 i64) + (param $x2 i64) + (param $x3 i64) + (param $x4 i64) + (param $y1 i64) + (param $y2 i64) + (param $y3 i64) + (param $y4 i64) + (result i64) + (local $z1 i64) + (local $z2 i64) + (local $z3 i64) + (local $z4 i64) + (local $z i64) + (local $condition_4 i64) + (local $condition_5 i64) + (local $condition_6 i64) + (local.set $z (i64.const 0)) + (block + (local.set $condition_4 (call $cmp (local.get $x1) (local.get $y1))) + (if (i64.eq (local.get $condition_4) (i64.const 0)) (then + (block + (local.set $condition_5 (call $cmp (local.get $x2) (local.get $y2))) + (if (i64.eq (local.get $condition_5) (i64.const 0)) (then + (block + (local.set $condition_6 (call $cmp (local.get $x3) (local.get $y3))) + (if (i64.eq (local.get $condition_6) (i64.const 0)) (then + (local.set $z (i64.extend_i32_u (i64.lt_u (local.get $x4) (local.get $y4)))) + )(else + (if (i64.eq (local.get $condition_6) (i64.const 1)) (then + (local.set $z (i64.const 0)) + )(else + (local.set $z (i64.const 1)) + )) + )) + + ) + )(else + (if (i64.eq (local.get $condition_5) (i64.const 1)) (then + (local.set $z (i64.const 0)) + )(else + (local.set $z (i64.const 1)) + )) + )) + + ) + )(else + (if (i64.eq (local.get $condition_4) (i64.const 1)) (then + (local.set $z (i64.const 0)) + )(else + (local.set $z (i64.const 1)) + )) + )) + + ) + (local.set $z4 (i64.extend_i32_u (i32.wrap_i64 (local.get $z)))) + (global.set $global_ (local.get $z2)) + (global.set $global__1 (local.get $z3)) + (global.set $global__2 (local.get $z4)) + (local.get $z1) +) + +(func $calldataload + (param $x1 i64) + (param $x2 i64) + (param $x3 i64) + (param $x4 i64) + (result i64) + (local $z1 i64) + (local $z2 i64) + (local $z3 i64) + (local $z4 i64) + (local $z1_1 i64) + (local $z2_1 i64) + (local $z3_1 i64) + (local $z4_1 i64) + (if (i64.ne (i64.extend_i32_u (i64.ne (i64.const 0) (i64.or (i64.or (local.get $x1) (local.get $x2)) (local.get $x3)))) (i64.const 0)) (then + (unreachable))) + (if (i64.ne (i64.extend_i32_u (i64.ne (i64.const 0) (i64.shr_u (local.get $x4) (i64.const 32)))) (i64.const 0)) (then + (unreachable))) + (call $eth.callDataCopy (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.extend_i32_u (i32.wrap_i64 (local.get $x4)))) (i32.wrap_i64 (i64.const 32))) + (local.set $z1_1 (call $endian_swap (i64.load (i32.wrap_i64 (i64.const 0))))) + (local.set $z2_1 (call $endian_swap (i64.load (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 8)))))))) + (local.set $z3_1 (call $endian_swap (i64.load (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 16)))))))) + (local.set $z4_1 (call $endian_swap (i64.load (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 24)))))))) + (local.set $z1 (local.get $z1_1)) + (local.set $z2 (local.get $z2_1)) + (local.set $z3 (local.get $z3_1)) + (local.set $z4 (local.get $z4_1)) + (global.set $global_ (local.get $z2)) + (global.set $global__1 (local.get $z3)) + (global.set $global__2 (local.get $z4)) + (local.get $z1) +) + +(func $endian_swap_16 + (param $x i64) + (result i64) + (local $y i64) + (local.set $y (i64.or (i64.and (i64.shl (local.get $x) (i64.const 8)) (i64.const 65280)) (i64.and (i64.shr_u (local.get $x) (i64.const 8)) (i64.const 255)))) + (local.get $y) +) + +(func $endian_swap_32 + (param $x i64) + (result i64) + (local $y i64) + (local $hi i64) + (local.set $hi (i64.shl (call $endian_swap_16 (local.get $x)) (i64.const 16))) + (local.set $y (i64.or (local.get $hi) (call $endian_swap_16 (i64.shr_u (local.get $x) (i64.const 16))))) + (local.get $y) +) + +(func $endian_swap + (param $x i64) + (result i64) + (local $y i64) + (local $hi i64) + (local.set $hi (i64.shl (call $endian_swap_32 (local.get $x)) (i64.const 32))) + (local.set $y (i64.or (local.get $hi) (call $endian_swap_32 (i64.shr_u (local.get $x) (i64.const 32))))) + (local.get $y) +) + +(func $mstore_internal + (param $pos i64) + (param $y1 i64) + (param $y2 i64) + (param $y3 i64) + (param $y4 i64) + (i64.store (i32.wrap_i64 (local.get $pos)) (call $endian_swap (local.get $y1))) + (i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $pos)) (i32.wrap_i64 (i64.const 8))))) (call $endian_swap (local.get $y2))) + (i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $pos)) (i32.wrap_i64 (i64.const 16))))) (call $endian_swap (local.get $y3))) + (i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $pos)) (i32.wrap_i64 (i64.const 24))))) (call $endian_swap (local.get $y4))) +) + +(func $sstore + (param $x1 i64) + (param $x2 i64) + (param $x3 i64) + (param $x4 i64) + (param $y1 i64) + (param $y2 i64) + (param $y3 i64) + (param $y4 i64) + (call $mstore_internal (i64.const 0) (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4)) + (call $mstore_internal (i64.const 32) (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4)) + (call $eth.storageStore (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 32))) +) + +) diff --git a/test/libyul/ewasmTranslationTests/loop_break.yul b/test/libyul/ewasmTranslationTests/loop_break.yul new file mode 100644 index 000000000..b473988d5 --- /dev/null +++ b/test/libyul/ewasmTranslationTests/loop_break.yul @@ -0,0 +1,13 @@ +{ + let i := 0 + for { } lt(i, 10) { i := add(i, 1) } { + if eq(i, 3) { break } + } + sstore(0, i) +} +// ---- +// Trace: +// Memory dump: +// 20: 0000000000000000000000000000000000000000000000000000000000000003 +// Storage dump: +// 0000000000000000000000000000000000000000000000000000000000000000: 0000000000000000000000000000000000000000000000000000000000000003 diff --git a/test/libyul/ewasmTranslationTests/loop_continue.yul b/test/libyul/ewasmTranslationTests/loop_continue.yul new file mode 100644 index 000000000..31200c2fe --- /dev/null +++ b/test/libyul/ewasmTranslationTests/loop_continue.yul @@ -0,0 +1,22 @@ +{ + let i := 0 + for { } lt(i, 10) { i := add(i, 1) } { + if eq(i, 3) { continue } + sstore(add(i, 0x10), i) + } + sstore(0, i) +} +// ---- +// Trace: +// Memory dump: +// 20: 000000000000000000000000000000000000000000000000000000000000000a +// Storage dump: +// 0000000000000000000000000000000000000000000000000000000000000000: 000000000000000000000000000000000000000000000000000000000000000a +// 0000000000000000000000000000000000000000000000000000000000000011: 0000000000000000000000000000000000000000000000000000000000000001 +// 0000000000000000000000000000000000000000000000000000000000000012: 0000000000000000000000000000000000000000000000000000000000000002 +// 0000000000000000000000000000000000000000000000000000000000000014: 0000000000000000000000000000000000000000000000000000000000000004 +// 0000000000000000000000000000000000000000000000000000000000000015: 0000000000000000000000000000000000000000000000000000000000000005 +// 0000000000000000000000000000000000000000000000000000000000000016: 0000000000000000000000000000000000000000000000000000000000000006 +// 0000000000000000000000000000000000000000000000000000000000000017: 0000000000000000000000000000000000000000000000000000000000000007 +// 0000000000000000000000000000000000000000000000000000000000000018: 0000000000000000000000000000000000000000000000000000000000000008 +// 0000000000000000000000000000000000000000000000000000000000000019: 0000000000000000000000000000000000000000000000000000000000000009 From a16a8c6123a9278bfc1640955b85c05d7b83957d Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 14 May 2020 11:36:24 +0200 Subject: [PATCH 89/89] Sort and copyedit changelog. --- Changelog.md | 15 +++++++-------- docs/bugs_by_version.json | 4 ++++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Changelog.md b/Changelog.md index 53c77ce9c..48eea3597 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,13 +1,13 @@ -### 0.6.8 (unreleased) +### 0.6.8 (2020-05-14) Important Bugfixes: * Add missing callvalue check to the creation code of a contract that does not define a constructor but has a base that does define a constructor. - * Disallow index range accesses for arrays with dynamically encoded base types. - * Code Generator: Fixed that string literals containing backslash characters could cause incorrect code to be generated when passed directly to function calls or encoding functions when ABIEncoderV2 is active. + * Disallow array slices of arrays with dynamically encoded base types. + * String literals containing backslash characters can no longer cause incorrect code to be generated when passed directly to function calls or encoding functions when ABIEncoderV2 is active. Language Features: - * Implemented ``type(X).min`` and ``type(X).max`` for every integer type ``X`` that returns the smallest and largest value representable by the type. + * Implemented ``type(T).min`` and ``type(T).max`` for every integer type ``T`` that returns the smallest and largest value representable by the type. Compiler Features: @@ -16,14 +16,13 @@ Compiler Features: * Wasm binary output: Implement ``br`` and ``br_if``. - Bugfixes: * ABI: Skip ``private`` or ``internal`` constructors. - * Type Checker: Disallow accessing ``runtimeCode`` for contract types that contain immutable state variables. * Fixed an "Assembly Exception in Bytecode" error where requested functions were generated twice. * Natspec: Fixed a bug that ignored ``@return`` tag when no other developer-documentation tags were present. - * Yul assembler: Fix source location of variable declarations without value. - * Type checker: Checks if a literal exponent in the ``**`` operation is too large or fractional. + * Type Checker: Checks if a literal exponent in the ``**`` operation is too large or fractional. + * Type Checker: Disallow accessing ``runtimeCode`` for contract types that contain immutable state variables. + * Yul Assembler: Fix source location of variable declarations without value. ### 0.6.7 (2020-05-04) diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index 0f96fb509..248517b8b 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -1159,5 +1159,9 @@ "ImplicitConstructorCallvalueCheck" ], "released": "2020-05-04" + }, + "0.6.8": { + "bugs": [], + "released": "2020-05-14" } } \ No newline at end of file