From 81f54a170b1c2db9c77d0f47783543bb6b597bf4 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 3 Jun 2020 21:54:43 +0200 Subject: [PATCH 01/24] Cleanup from storage. --- .../getters/struct_with_bytes_simple.sol | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 test/libsolidity/semanticTests/getters/struct_with_bytes_simple.sol diff --git a/test/libsolidity/semanticTests/getters/struct_with_bytes_simple.sol b/test/libsolidity/semanticTests/getters/struct_with_bytes_simple.sol new file mode 100644 index 000000000..974ca9e80 --- /dev/null +++ b/test/libsolidity/semanticTests/getters/struct_with_bytes_simple.sol @@ -0,0 +1,17 @@ +contract C { + struct S { + uint a; + bytes b; + mapping(uint => uint) c; + uint[] d; + } + uint shifter; + S public s; + constructor() public { + s.a = 7; + s.b = "abc"; + s.c[0] = 9; + } +} +// ---- +// s() -> 0x07, 0x40, 0x03, 0x6162630000000000000000000000000000000000000000000000000000000000 From c6e4943089c0f5dc6be668841901cd50d5913a31 Mon Sep 17 00:00:00 2001 From: Djordje Mijovic Date: Tue, 2 Jun 2020 15:42:46 +0200 Subject: [PATCH 02/24] Adding fixes for signedness warnings in libsolidity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kamil Śliwak --- libsolidity/analysis/OverrideChecker.cpp | 29 ++++++----- libsolidity/analysis/TypeChecker.cpp | 34 ++++++------- libsolidity/ast/AST.cpp | 2 +- libsolidity/ast/AST.h | 2 +- libsolidity/ast/ASTJsonConverter.cpp | 3 +- libsolidity/ast/ASTJsonImporter.cpp | 2 +- libsolidity/ast/Types.cpp | 10 ++-- libsolidity/codegen/ABIFunctions.cpp | 2 +- libsolidity/codegen/ArrayUtils.cpp | 2 +- libsolidity/codegen/CompilerContext.cpp | 20 ++++---- libsolidity/codegen/CompilerContext.h | 2 +- libsolidity/codegen/CompilerUtils.cpp | 4 +- libsolidity/codegen/ContractCompiler.cpp | 50 +++++++++---------- libsolidity/codegen/ExpressionCompiler.cpp | 20 ++++---- .../codegen/ir/IRGeneratorForStatements.cpp | 4 +- libsolidity/formal/CHC.cpp | 14 +++--- libsolidity/formal/CHC.h | 4 +- libsolidity/formal/SMTEncoder.cpp | 15 +++--- libsolidity/formal/SMTEncoder.h | 2 +- libsolidity/formal/SymbolicVariables.cpp | 10 ++-- libsolidity/formal/SymbolicVariables.h | 10 ++-- libsolidity/interface/CompilerStack.cpp | 2 +- libsolidity/interface/GasEstimator.cpp | 4 +- libsolidity/interface/StorageLayout.cpp | 2 +- test/libsolidity/ABIEncoderTests.cpp | 4 +- test/libsolidity/SMTCheckerJSONTest.cpp | 12 ++--- .../SolidityExpressionCompiler.cpp | 4 +- test/libsolidity/SolidityOptimizer.cpp | 2 +- test/libsolidity/SolidityParser.cpp | 2 +- test/libsolidity/SyntaxTest.cpp | 4 +- test/libsolidity/util/BytesUtils.cpp | 4 +- test/libsolidity/util/TestFileParserTests.cpp | 2 +- 32 files changed, 145 insertions(+), 138 deletions(-) diff --git a/libsolidity/analysis/OverrideChecker.cpp b/libsolidity/analysis/OverrideChecker.cpp index 89f9a6637..c488fd278 100644 --- a/libsolidity/analysis/OverrideChecker.cpp +++ b/libsolidity/analysis/OverrideChecker.cpp @@ -68,7 +68,7 @@ struct OverrideGraph std::map nodes; std::map nodeInv; std::map> edges; - int numNodes = 2; + size_t numNodes = 2; void addEdge(int _a, int _b) { edges[_a].insert(_b); @@ -82,7 +82,7 @@ private: auto it = nodes.find(_function); if (it != nodes.end()) return it->second; - int currentNode = numNodes++; + int currentNode = static_cast(numNodes++); nodes[_function] = currentNode; nodeInv[currentNode] = _function; if (_function.overrides()) @@ -116,21 +116,24 @@ private: std::vector m_parent = std::vector(m_graph.numNodes, -1); std::set m_cutVertices{}; - void run(int _u = 0, int _depth = 0) + void run(size_t _u = 0, size_t _depth = 0) { m_visited.at(_u) = true; - m_depths.at(_u) = m_low.at(_u) = _depth; - for (int v: m_graph.edges.at(_u)) - if (!m_visited.at(v)) + m_depths.at(_u) = m_low.at(_u) = static_cast(_depth); + for (int const v: m_graph.edges.at(static_cast(_u))) + { + auto const vInd = static_cast(v); + if (!m_visited.at(vInd)) { - m_parent[v] = _u; - run(v, _depth + 1); - if (m_low[v] >= m_depths[_u] && m_parent[_u] != -1) - m_cutVertices.insert(m_graph.nodeInv.at(_u)); - m_low[_u] = min(m_low[_u], m_low[v]); + m_parent[vInd] = static_cast(_u); + run(vInd, _depth + 1); + if (m_low[vInd] >= m_depths[_u] && m_parent[_u] != -1) + m_cutVertices.insert(m_graph.nodeInv.at(static_cast(_u))); + m_low[_u] = min(m_low[_u], m_low[vInd]); } else if (v != m_parent[_u]) - m_low[_u] = min(m_low[_u], m_depths[v]); + m_low[_u] = min(m_low[_u], m_depths[vInd]); + } } }; @@ -213,7 +216,7 @@ bool OverrideProxy::CompareBySignature::operator()(OverrideProxy const& _a, Over size_t OverrideProxy::id() const { return std::visit(GenericVisitor{ - [&](auto const* _item) -> size_t { return _item->id(); } + [&](auto const* _item) -> size_t { return static_cast(_item->id()); } }, m_item); } diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index bdf27585d..c308fadd8 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -666,7 +666,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) { auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier); if (ref == _inlineAssembly.annotation().externalReferences.end()) - return size_t(-1); + return numeric_limits::max(); Declaration const* declaration = ref->second.declaration; solAssert(!!declaration, ""); bool requiresStorage = ref->second.isSlot || ref->second.isOffset; @@ -676,7 +676,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) if (var->immutable()) { m_errorReporter.typeError(3773_error, _identifier.location, "Assembly access to immutable variables is not supported."); - return size_t(-1); + return numeric_limits::max(); } if (var->isConstant()) { @@ -685,17 +685,17 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) if (var && !var->value()) { m_errorReporter.typeError(3224_error, _identifier.location, "Constant has no value."); - return size_t(-1); + return numeric_limits::max(); } else if (_context == yul::IdentifierContext::LValue) { m_errorReporter.typeError(6252_error, _identifier.location, "Constant variables cannot be assigned to."); - return size_t(-1); + return numeric_limits::max(); } else if (requiresStorage) { m_errorReporter.typeError(6617_error, _identifier.location, "The suffixes _offset and _slot can only be used on non-constant storage variables."); - return size_t(-1); + return numeric_limits::max(); } else if (var && var->value() && !var->value()->annotation().type && !dynamic_cast(var->value().get())) { @@ -723,19 +723,19 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) if (!var->isStateVariable() && !var->type()->dataStoredIn(DataLocation::Storage)) { m_errorReporter.typeError(3622_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables."); - return size_t(-1); + return numeric_limits::max(); } else if (_context == yul::IdentifierContext::LValue) { if (var->isStateVariable()) { m_errorReporter.typeError(4713_error, _identifier.location, "State variables cannot be assigned to - you have to use \"sstore()\"."); - return size_t(-1); + return numeric_limits::max(); } else if (ref->second.isOffset) { m_errorReporter.typeError(9739_error, _identifier.location, "Only _slot can be assigned to."); - return size_t(-1); + return numeric_limits::max(); } else solAssert(ref->second.isSlot, ""); @@ -744,12 +744,12 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) else if (!var->isConstant() && var->isStateVariable()) { m_errorReporter.typeError(1408_error, _identifier.location, "Only local variables are supported. To access storage variables, use the _slot and _offset suffixes."); - return size_t(-1); + return numeric_limits::max(); } else if (var->type()->dataStoredIn(DataLocation::Storage)) { m_errorReporter.typeError(9068_error, _identifier.location, "You have to use the _slot or _offset suffix to access storage reference variables."); - return size_t(-1); + return numeric_limits::max(); } else if (var->type()->sizeOnStack() != 1) { @@ -757,21 +757,21 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) m_errorReporter.typeError(2370_error, _identifier.location, "Call data elements cannot be accessed directly. Copy to a local variable first or use \"calldataload\" or \"calldatacopy\" with manually determined offsets and sizes."); else m_errorReporter.typeError(9857_error, _identifier.location, "Only types that use one stack slot are supported."); - return size_t(-1); + return numeric_limits::max(); } } else if (requiresStorage) { m_errorReporter.typeError(7944_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables."); - return size_t(-1); + return numeric_limits::max(); } else if (_context == yul::IdentifierContext::LValue) { if (dynamic_cast(declaration)) - return size_t(-1); + return numeric_limits::max(); m_errorReporter.typeError(1990_error, _identifier.location, "Only local variables can be assigned to in inline assembly."); - return size_t(-1); + return numeric_limits::max(); } if (_context == yul::IdentifierContext::RValue) @@ -780,7 +780,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) if (dynamic_cast(declaration)) { m_errorReporter.declarationError(2025_error, _identifier.location, "Access to functions is not allowed in inline assembly."); - return size_t(-1); + return numeric_limits::max(); } else if (dynamic_cast(declaration)) { @@ -790,11 +790,11 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) if (!contract->isLibrary()) { m_errorReporter.typeError(4977_error, _identifier.location, "Expected a library."); - return size_t(-1); + return numeric_limits::max(); } } else - return size_t(-1); + return numeric_limits::max(); } ref->second.valueSize = 1; return size_t(1); diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index c11a05a02..3492bfc45 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -38,7 +38,7 @@ using namespace solidity; using namespace solidity::frontend; ASTNode::ASTNode(int64_t _id, SourceLocation _location): - m_id(_id), + m_id(static_cast(_id)), m_location(std::move(_location)) { } diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index c1c02b2bb..c6c560988 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -88,7 +88,7 @@ public: virtual ~ASTNode() {} /// @returns an identifier of this AST node that is unique for a single compilation run. - int64_t id() const { return m_id; } + int64_t id() const { return int64_t(m_id); } virtual void accept(ASTVisitor& _visitor) = 0; virtual void accept(ASTConstVisitor& _visitor) const = 0; diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index 8da1dddd7..219151f89 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -37,6 +37,7 @@ #include #include #include +#include using namespace std; using namespace solidity::langutil; @@ -134,7 +135,7 @@ size_t ASTJsonConverter::sourceIndexFromLocation(SourceLocation const& _location if (_location.source && m_sourceIndices.count(_location.source->name())) return m_sourceIndices.at(_location.source->name()); else - return size_t(-1); + return numeric_limits::max(); } string ASTJsonConverter::sourceLocationToString(SourceLocation const& _location) const diff --git a/libsolidity/ast/ASTJsonImporter.cpp b/libsolidity/ast/ASTJsonImporter.cpp index 97e3ba964..65f9fa718 100644 --- a/libsolidity/ast/ASTJsonImporter.cpp +++ b/libsolidity/ast/ASTJsonImporter.cpp @@ -92,7 +92,7 @@ SourceLocation const ASTJsonImporter::createSourceLocation(Json::Value const& _n { astAssert(member(_node, "src").isString(), "'src' must be a string"); - return solidity::langutil::parseSourceLocation(_node["src"].asString(), m_currentSourceName, int(m_sourceLocations.size())); + return solidity::langutil::parseSourceLocation(_node["src"].asString(), m_currentSourceName, m_sourceLocations.size()); } template diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 66681ea10..669e54d0e 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -773,7 +773,7 @@ tuple RationalNumberType::parseRational(string const& _value) denominator = bigint(string(fractionalBegin, _value.end())); denominator /= boost::multiprecision::pow( bigint(10), - distance(radixPoint + 1, _value.end()) + static_cast(distance(radixPoint + 1, _value.end())) ); numerator = bigint(string(_value.begin(), radixPoint)); value = numerator + denominator; @@ -1065,7 +1065,7 @@ TypeResult RationalNumberType::binaryOperatorResult(Token _operator, Type const* if (_base == 1) return 1; else if (_base == -1) - return 1 - 2 * int(_exponent & 1); + return 1 - 2 * static_cast(_exponent & 1); else return boost::multiprecision::pow(_base, _exponent); }; @@ -1171,7 +1171,7 @@ string RationalNumberType::bigintToReadableString(bigint const& _num) string str = _num.str(); if (str.size() > 32) { - int omitted = str.size() - 8; + size_t omitted = str.size() - 8; str = str.substr(0, 4) + "...(" + to_string(omitted) + " digits omitted)..." + str.substr(str.size() - 4, 4); } return str; @@ -1201,7 +1201,7 @@ u256 RationalNumberType::literalValue(Literal const*) const { auto fixed = fixedPointType(); solAssert(fixed, "Rational number cannot be represented as fixed point type."); - int fractionalDigits = fixed->fractionalDigits(); + unsigned fractionalDigits = fixed->fractionalDigits(); shiftedValue = m_value.numerator() * boost::multiprecision::pow(bigint(10), fractionalDigits) / m_value.denominator(); } @@ -1291,7 +1291,7 @@ StringLiteralType::StringLiteralType(string _value): BoolResult StringLiteralType::isImplicitlyConvertibleTo(Type const& _convertTo) const { if (auto fixedBytes = dynamic_cast(&_convertTo)) - return size_t(fixedBytes->numBytes()) >= m_value.size(); + return static_cast(fixedBytes->numBytes()) >= m_value.size(); else if (auto arrayType = dynamic_cast(&_convertTo)) return arrayType->isByteArray() && diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index 189fba165..9f244fdb1 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -725,7 +725,7 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray( size_t itemsPerSlot = 32 / storageBytes; solAssert(itemsPerSlot > 0, ""); // The number of elements we need to handle manually after the loop. - size_t spill = size_t(_from.length() % itemsPerSlot); + size_t spill = static_cast(_from.length() % itemsPerSlot); Whiskers templ( R"( // -> diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp index 732deca6f..9f12f648f 100644 --- a/libsolidity/codegen/ArrayUtils.cpp +++ b/libsolidity/codegen/ArrayUtils.cpp @@ -56,7 +56,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons bool directCopy = sourceIsStorage && sourceBaseType->isValueType() && *sourceBaseType == *targetBaseType; bool haveByteOffsetSource = !directCopy && sourceIsStorage && sourceBaseType->storageBytes() <= 16; bool haveByteOffsetTarget = !directCopy && targetBaseType->storageBytes() <= 16; - unsigned byteOffsetSize = (haveByteOffsetSource ? 1 : 0) + (haveByteOffsetTarget ? 1 : 0); + unsigned byteOffsetSize = (haveByteOffsetSource ? 1u : 0u) + (haveByteOffsetTarget ? 1u : 0u); // stack: source_ref [source_length] target_ref // store target_ref diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 9e2c0663b..fea449f7f 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -133,7 +133,7 @@ void CompilerContext::callLowLevelFunction( *this << lowLevelFunctionTag(_name, _inArgs, _outArgs, _generator); appendJump(evmasm::AssemblyItem::JumpType::IntoFunction); - adjustStackOffset(int(_outArgs) - 1 - _inArgs); + adjustStackOffset(static_cast(_outArgs) - 1 - static_cast(_inArgs)); *this << retTag.tag(); } @@ -147,7 +147,7 @@ void CompilerContext::callYulFunction( auto const retTag = pushNewTag(); CompilerUtils(*this).moveIntoStack(_inArgs); appendJumpTo(namedTag(_name)); - adjustStackOffset(int(_outArgs) - 1 - _inArgs); + adjustStackOffset(static_cast(_outArgs) - 1 - static_cast(_inArgs)); *this << retTag.tag(); } @@ -181,7 +181,7 @@ void CompilerContext::appendMissingLowLevelFunctions() tie(name, inArgs, outArgs, generator) = m_lowLevelFunctionGenerationQueue.front(); m_lowLevelFunctionGenerationQueue.pop(); - setStackOffset(inArgs + 1); + setStackOffset(static_cast(inArgs) + 1); *this << m_lowLevelFunctions.at(name).tag(); generator(*this); CompilerUtils(*this).moveToStackTop(outArgs); @@ -298,12 +298,12 @@ unsigned CompilerContext::baseStackOffsetOfVariable(Declaration const& _declarat unsigned CompilerContext::baseToCurrentStackOffset(unsigned _baseOffset) const { - return m_asm->deposit() - _baseOffset - 1; + return static_cast(m_asm->deposit()) - _baseOffset - 1; } unsigned CompilerContext::currentToBaseStackOffset(unsigned _offset) const { - return m_asm->deposit() - _offset - 1; + return static_cast(m_asm->deposit()) - _offset - 1; } pair CompilerContext::storageLocationOfVariable(Declaration const& _declaration) const @@ -371,7 +371,7 @@ void CompilerContext::appendInlineAssembly( OptimiserSettings const& _optimiserSettings ) { - int startStackHeight = stackHeight(); + unsigned startStackHeight = stackHeight(); set externallyUsedIdentifiers; for (auto const& fun: _externallyUsedFunctions) @@ -387,9 +387,9 @@ void CompilerContext::appendInlineAssembly( ) -> size_t { if (_insideFunction) - return size_t(-1); + return numeric_limits::max(); auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str()); - return it == _localVariables.end() ? size_t(-1) : 1; + return it == _localVariables.end() ? numeric_limits::max() : 1; }; identifierAccess.generateCode = [&]( yul::Identifier const& _identifier, @@ -399,8 +399,8 @@ void CompilerContext::appendInlineAssembly( { auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str()); solAssert(it != _localVariables.end(), ""); - int stackDepth = _localVariables.end() - it; - int stackDiff = _assembly.stackHeight() - startStackHeight + stackDepth; + auto stackDepth = static_cast(distance(it, _localVariables.end())); + size_t stackDiff = static_cast(_assembly.stackHeight()) - startStackHeight + stackDepth; if (_context == yul::IdentifierContext::LValue) stackDiff -= 1; if (stackDiff < 1 || stackDiff > 16) diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index 51d3afe1c..c32b51406 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -377,7 +377,7 @@ private: /// The runtime context if in Creation mode, this is used for generating tags that would be stored into the storage and then used at runtime. CompilerContext *m_runtimeContext; /// The index of the runtime subroutine. - size_t m_runtimeSub = -1; + size_t m_runtimeSub = std::numeric_limits::max(); /// An index of low-level function labels by name. std::map m_lowLevelFunctions; /// Collector for yul functions. diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 2735c2fce..c3e81d13a 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -1351,7 +1351,7 @@ void CompilerUtils::popAndJump(unsigned _toHeight, evmasm::AssemblyItem const& _ unsigned amount = m_context.stackHeight() - _toHeight; popStackSlots(amount); m_context.appendJumpTo(_jumpTo); - m_context.adjustStackOffset(amount); + m_context.adjustStackOffset(static_cast(amount)); } unsigned CompilerUtils::sizeOnStack(vector const& _variableTypes) @@ -1436,7 +1436,7 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda { bool leftAligned = _type.category() == Type::Category::FixedBytes; // add leading or trailing zeros by dividing/multiplying depending on alignment - int shiftFactor = (32 - numBytes) * 8; + unsigned shiftFactor = (32 - numBytes) * 8; rightShiftNumberOnStack(shiftFactor); if (leftAligned) { diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 269d9a5bf..6f8603a51 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -185,7 +185,7 @@ size_t ContractCompiler::packIntoContractCreator(ContractDefinition const& _cont CompilerContext::LocationSetter locationSetter(m_context, _contract); m_context << deployRoutine; - solAssert(m_context.runtimeSub() != size_t(-1), "Runtime sub not registered"); + solAssert(m_context.runtimeSub() != numeric_limits::max(), "Runtime sub not registered"); ContractType contractType(_contract); auto const& immutables = contractType.immutableVariables(); @@ -221,7 +221,7 @@ size_t ContractCompiler::deployLibrary(ContractDefinition const& _contract) CompilerContext::LocationSetter locationSetter(m_context, _contract); - solAssert(m_context.runtimeSub() != size_t(-1), "Runtime sub not registered"); + solAssert(m_context.runtimeSub() != numeric_limits::max(), "Runtime sub not registered"); m_context.pushSubroutineSize(m_context.runtimeSub()); m_context.pushSubroutineOffset(m_context.runtimeSub()); // This code replaces the address added by appendDeployTimeAddress(). @@ -349,11 +349,11 @@ void ContractCompiler::appendInternalSelector( m_context << dupInstruction(1) << u256(FixedHash<4>::Arith(pivot)) << Instruction::GT; evmasm::AssemblyItem lessTag{m_context.appendConditionalJump()}; // Here, we have funid >= pivot - vector> larger{_ids.begin() + pivotIndex, _ids.end()}; + vector> larger{_ids.begin() + static_cast(pivotIndex), _ids.end()}; appendInternalSelector(_entryPoints, larger, _notFoundTag, _runs); m_context << lessTag; // Here, we have funid < pivot - vector> smaller{_ids.begin(), _ids.begin() + pivotIndex}; + vector> smaller{_ids.begin(), _ids.begin() + static_cast(pivotIndex)}; appendInternalSelector(_entryPoints, smaller, _notFoundTag, _runs); } else @@ -512,8 +512,8 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac m_context << returnTag; // Return tag and input parameters get consumed. m_context.adjustStackOffset( - CompilerUtils(m_context).sizeOnStack(functionType->returnParameterTypes()) - - CompilerUtils(m_context).sizeOnStack(functionType->parameterTypes()) - + static_cast(CompilerUtils::sizeOnStack(functionType->returnParameterTypes())) - + static_cast(CompilerUtils::sizeOnStack(functionType->parameterTypes())) - 1 ); // Consumes the return parameters. @@ -589,7 +589,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) unsigned parametersSize = CompilerUtils::sizeOnStack(_function.parameters()); if (!_function.isConstructor()) // adding 1 for return address. - m_context.adjustStackOffset(parametersSize + 1); + m_context.adjustStackOffset(static_cast(parametersSize) + 1); for (ASTPointer const& variable: _function.parameters()) { m_context.addVariable(*variable, parametersSize); @@ -609,7 +609,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) m_breakTags.clear(); m_continueTags.clear(); m_currentFunction = &_function; - m_modifierDepth = -1; + m_modifierDepth = numeric_limits::max(); m_scopeStackHeight.clear(); m_context.setModifierDepth(0); @@ -627,10 +627,10 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) unsigned const c_returnValuesSize = CompilerUtils::sizeOnStack(_function.returnParameters()); vector stackLayout; - stackLayout.push_back(c_returnValuesSize); // target of return address + stackLayout.push_back(static_cast(c_returnValuesSize)); // target of return address stackLayout += vector(c_argumentsSize, -1); // discard all arguments - for (unsigned i = 0; i < c_returnValuesSize; ++i) - stackLayout.push_back(i); + for (size_t i = 0; i < c_returnValuesSize; ++i) + stackLayout.push_back(static_cast(i)); if (stackLayout.size() > 17) BOOST_THROW_EXCEPTION( @@ -638,7 +638,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) errinfo_sourceLocation(_function.location()) << errinfo_comment("Stack too deep, try removing local variables.") ); - while (stackLayout.back() != int(stackLayout.size() - 1)) + while (stackLayout.back() != static_cast(stackLayout.size() - 1)) if (stackLayout.back() < 0) { m_context << Instruction::POP; @@ -646,11 +646,11 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) } else { - m_context << swapInstruction(stackLayout.size() - stackLayout.back() - 1); - swap(stackLayout[stackLayout.back()], stackLayout.back()); + m_context << swapInstruction(stackLayout.size() - static_cast(stackLayout.back()) - 1); + swap(stackLayout[static_cast(stackLayout.back())], stackLayout.back()); } - for (int i = 0; i < int(stackLayout.size()); ++i) - if (stackLayout[i] != i) + for (size_t i = 0; i < stackLayout.size(); ++i) + if (stackLayout[i] != static_cast(i)) solAssert(false, "Invalid stack layout on cleanup."); for (ASTPointer const& variable: _function.parameters() + _function.returnParameters()) @@ -677,7 +677,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) { auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier); if (ref == _inlineAssembly.annotation().externalReferences.end()) - return size_t(-1); + return numeric_limits::max(); return ref->second.valueSize; }; identifierAccess.generateCode = [&](yul::Identifier const& _identifier, yul::IdentifierContext _context, yul::AbstractAssembly& _assembly) @@ -696,7 +696,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) functionDef = &functionDef->resolveVirtual(m_context.mostDerivedContract()); auto functionEntryLabel = m_context.functionEntryLabel(*functionDef).pushTag(); solAssert(functionEntryLabel.data() <= std::numeric_limits::max(), ""); - _assembly.appendLabelReference(size_t(functionEntryLabel.data())); + _assembly.appendLabelReference(static_cast(functionEntryLabel.data())); // If there is a runtime context, we have to merge both labels into the same // stack slot in case we store it in storage. if (CompilerContext* rtc = m_context.runtimeContext()) @@ -705,7 +705,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) _assembly.appendInstruction(Instruction::MUL); auto runtimeEntryLabel = rtc->functionEntryLabel(*functionDef).toSubAssemblyTag(m_context.runtimeSub()); solAssert(runtimeEntryLabel.data() <= std::numeric_limits::max(), ""); - _assembly.appendLabelReference(size_t(runtimeEntryLabel.data())); + _assembly.appendLabelReference(static_cast(runtimeEntryLabel.data())); _assembly.appendInstruction(Instruction::OR); } } @@ -772,7 +772,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) } else if (m_context.isLocalVariable(decl)) { - int stackDiff = _assembly.stackHeight() - m_context.baseStackOffsetOfVariable(*variable); + unsigned stackDiff = static_cast(_assembly.stackHeight()) - m_context.baseStackOffsetOfVariable(*variable); if (ref->second.isSlot || ref->second.isOffset) { solAssert(variable->type()->dataStoredIn(DataLocation::Storage), ""); @@ -816,7 +816,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) } else solAssert(false, "Invalid declaration type."); - solAssert(_assembly.stackHeight() - depositBefore == int(ref->second.valueSize), ""); + solAssert(_assembly.stackHeight() - depositBefore == static_cast(ref->second.valueSize), ""); } else { @@ -828,7 +828,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) "Can only assign to stack variables in inline assembly." ); solAssert(variable->type()->sizeOnStack() == 1, ""); - int stackDiff = _assembly.stackHeight() - m_context.baseStackOffsetOfVariable(*variable) - 1; + unsigned stackDiff = static_cast(_assembly.stackHeight()) - m_context.baseStackOffsetOfVariable(*variable) - 1; if (stackDiff > 16 || stackDiff < 1) BOOST_THROW_EXCEPTION( CompilerError() << @@ -875,7 +875,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) false, m_optimiserSettings.optimizeStackAllocation ); - m_context.setStackOffset(startStackHeight); + m_context.setStackOffset(static_cast(startStackHeight)); return false; } @@ -914,7 +914,7 @@ bool ContractCompiler::visit(TryStatement const& _tryStatement) solAssert(params[i] && exprTypes[i] && *params[i]->annotation().type == *exprTypes[i], ""); } else - CompilerUtils(m_context).popStackSlots(returnSize); + CompilerUtils(m_context).popStackSlots(static_cast(returnSize)); _tryStatement.clauses().front()->accept(*this); } @@ -937,7 +937,7 @@ void ContractCompiler::handleCatch(vector> const& _ca else solAssert(false, ""); - solAssert(_catchClauses.size() == size_t(1 + (structured ? 1 : 0) + (fallback ? 1 : 0)), ""); + solAssert(_catchClauses.size() == 1ul + (structured ? 1 : 0) + (fallback ? 1 : 0), ""); evmasm::AssemblyItem endTag = m_context.newTag(); evmasm::AssemblyItem fallbackTag = m_context.newTag(); diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 6397c7492..a020551f3 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -100,7 +100,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& if (_varDecl.immutable()) solAssert(paramTypes.empty(), ""); - m_context.adjustStackOffset(1 + CompilerUtils::sizeOnStack(paramTypes)); + m_context.adjustStackOffset(static_cast(1 + CompilerUtils::sizeOnStack(paramTypes))); if (!_varDecl.immutable()) { @@ -242,7 +242,7 @@ bool ExpressionCompiler::visit(Conditional const& _condition) acceptAndConvert(_condition.falseExpression(), *_condition.annotation().type); evmasm::AssemblyItem endTag = m_context.appendJumpToNew(); m_context << trueTag; - int offset = _condition.annotation().type->sizeOnStack(); + int offset = static_cast(_condition.annotation().type->sizeOnStack()); m_context.adjustStackOffset(-offset); acceptAndConvert(_condition.trueExpression(), *_condition.annotation().type); m_context << endTag; @@ -619,7 +619,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) unsigned returnParametersSize = CompilerUtils::sizeOnStack(function.returnParameterTypes()); // callee adds return parameters, but removes arguments and return label - m_context.adjustStackOffset(returnParametersSize - parameterSize - 1); + m_context.adjustStackOffset(static_cast(returnParametersSize - parameterSize) - 1); break; } case FunctionType::Kind::BareCall: @@ -705,7 +705,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) acceptAndConvert(*arguments.front(), *TypeProvider::uint256(), true); // Note that function is not the original function, but the ".gas" function. // Its values of gasSet and valueSet is equal to the original function's though. - unsigned stackDepth = (function.gasSet() ? 1 : 0) + (function.valueSet() ? 1 : 0); + unsigned stackDepth = (function.gasSet() ? 1u : 0u) + (function.valueSet() ? 1u : 0u); if (stackDepth > 0) m_context << swapInstruction(stackDepth); if (function.gasSet()) @@ -814,7 +814,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) case FunctionType::Kind::Log3: case FunctionType::Kind::Log4: { - unsigned logNumber = int(function.kind()) - int(FunctionType::Kind::Log0); + unsigned logNumber = static_cast(function.kind()) - static_cast(FunctionType::Kind::Log0); for (unsigned arg = logNumber; arg > 0; --arg) acceptAndConvert(*arguments[arg], *function.parameterTypes()[arg], true); arguments.front()->accept(*this); @@ -1088,7 +1088,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) { utils().revertWithStringData(*arguments.at(1)->annotation().type); // Here, the argument is consumed, but in the other branch, it is still there. - m_context.adjustStackOffset(arguments.at(1)->annotation().type->sizeOnStack()); + m_context.adjustStackOffset(static_cast(arguments.at(1)->annotation().type->sizeOnStack())); } else m_context.appendRevert(); @@ -1271,9 +1271,9 @@ bool ExpressionCompiler::visit(FunctionCallOptions const& _functionCallOptions) acceptAndConvert(*_functionCallOptions.options()[i], *requiredType); solAssert(!contains(presentOptions, newOption), ""); - size_t insertPos = presentOptions.end() - lower_bound(presentOptions.begin(), presentOptions.end(), newOption); + ptrdiff_t insertPos = presentOptions.end() - lower_bound(presentOptions.begin(), presentOptions.end(), newOption); - utils().moveIntoStack(insertPos, 1); + utils().moveIntoStack(static_cast(insertPos), 1); presentOptions.insert(presentOptions.end() - insertPos, newOption); } @@ -2190,7 +2190,7 @@ void ExpressionCompiler::appendExternalFunctionCall( // contract address unsigned selfSize = _functionType.bound() ? _functionType.selfType()->sizeOnStack() : 0; - unsigned gasValueSize = (_functionType.gasSet() ? 1 : 0) + (_functionType.valueSet() ? 1 : 0); + unsigned gasValueSize = (_functionType.gasSet() ? 1u : 0u) + (_functionType.valueSet() ? 1u : 0u); unsigned contractStackPos = m_context.currentToBaseStackOffset(1 + gasValueSize + selfSize + (_functionType.isBareCall() ? 0 : 1)); unsigned gasStackPos = m_context.currentToBaseStackOffset(gasValueSize); unsigned valueStackPos = m_context.currentToBaseStackOffset(1); @@ -2361,7 +2361,7 @@ void ExpressionCompiler::appendExternalFunctionCall( m_context << Instruction::CALL; unsigned remainsSize = - 2 + // contract address, input_memory_end + 2u + // contract address, input_memory_end (_functionType.valueSet() ? 1 : 0) + (_functionType.gasSet() ? 1 : 0) + (!_functionType.isBareCall() ? 1 : 0); diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index a62251ab1..beaff69ae 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -636,7 +636,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) }); solAssert(it != callArgumentNames.cend(), ""); - arguments.push_back(callArguments[std::distance(callArgumentNames.begin(), it)]); + arguments.push_back(callArguments[static_cast(std::distance(callArgumentNames.begin(), it))]); } auto memberAccess = dynamic_cast(&_functionCall.expression()); @@ -1092,7 +1092,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) case FunctionType::Kind::Log3: case FunctionType::Kind::Log4: { - unsigned logNumber = int(functionType->kind()) - int(FunctionType::Kind::Log0); + unsigned logNumber = static_cast(functionType->kind()) - static_cast(FunctionType::Kind::Log0); solAssert(arguments.size() == logNumber + 1, ""); ABIFunctions abi(m_context.evmVersion(), m_context.revertStrings(), m_context.functionCollector()); string indexedArgs; diff --git a/libsolidity/formal/CHC.cpp b/libsolidity/formal/CHC.cpp index f0ba6d0de..791a4f41d 100644 --- a/libsolidity/formal/CHC.cpp +++ b/libsolidity/formal/CHC.cpp @@ -104,7 +104,7 @@ void CHC::analyze(SourceUnit const& _source) for (auto const* assertion: assertions) { createErrorBlock(); - connectBlocks(target.value, error(), target.constraints && (target.errorId == assertion->id())); + connectBlocks(target.value, error(), target.constraints && (target.errorId == static_cast(assertion->id()))); auto [result, model] = query(error(), assertion->location()); // This should be fine but it's a bug in the old compiler (void)model; @@ -116,7 +116,7 @@ void CHC::analyze(SourceUnit const& _source) { solAssert(dynamic_cast(scope), ""); createErrorBlock(); - connectBlocks(target.value, error(), target.constraints && (target.errorId == scope->id())); + connectBlocks(target.value, error(), target.constraints && (target.errorId == static_cast(scope->id()))); auto [result, model] = query(error(), scope->location()); // This should be fine but it's a bug in the old compiler (void)model; @@ -533,7 +533,9 @@ void CHC::visitAssert(FunctionCall const& _funCall) connectBlocks( m_currentBlock, m_currentFunction->isConstructor() ? summary(*m_currentContract) : summary(*m_currentFunction), - currentPathConditions() && !m_context.expression(*args.front())->currentValue() && (m_error.currentValue() == _funCall.id()) + currentPathConditions() && !m_context.expression(*args.front())->currentValue() && ( + m_error.currentValue() == static_cast(_funCall.id()) + ) ); m_context.addAssertion(m_error.currentValue() == previousError); @@ -601,7 +603,7 @@ void CHC::makeArrayPopVerificationTarget(FunctionCall const& _arrayPop) connectBlocks( m_currentBlock, m_currentFunction->isConstructor() ? summary(*m_currentContract) : summary(*m_currentFunction), - currentPathConditions() && symbArray->length() <= 0 && m_error.currentValue() == _arrayPop.id() + currentPathConditions() && symbArray->length() <= 0 && m_error.currentValue() == static_cast(_arrayPop.id()) ); m_context.addAssertion(m_error.currentValue() == previousError); @@ -891,13 +893,13 @@ vector CHC::initialStateVariables() return stateVariablesAtIndex(0); } -vector CHC::stateVariablesAtIndex(int _index) +vector CHC::stateVariablesAtIndex(unsigned _index) { solAssert(m_currentContract, ""); return applyMap(m_stateVariables, [&](auto _var) { return valueAtIndex(*_var, _index); }); } -vector CHC::stateVariablesAtIndex(int _index, ContractDefinition const& _contract) +vector CHC::stateVariablesAtIndex(unsigned _index, ContractDefinition const& _contract) { return applyMap( stateVariablesIncludingInheritedAndPrivate(_contract), diff --git a/libsolidity/formal/CHC.h b/libsolidity/formal/CHC.h index b1235a188..b52ce6667 100644 --- a/libsolidity/formal/CHC.h +++ b/libsolidity/formal/CHC.h @@ -149,8 +149,8 @@ private: /// @returns the symbolic values of the state variables at the beginning /// of the current transaction. std::vector initialStateVariables(); - std::vector stateVariablesAtIndex(int _index); - std::vector stateVariablesAtIndex(int _index, ContractDefinition const& _contract); + std::vector stateVariablesAtIndex(unsigned _index); + std::vector stateVariablesAtIndex(unsigned _index, ContractDefinition const& _contract); /// @returns the current symbolic values of the current state variables. std::vector currentStateVariables(); diff --git a/libsolidity/formal/SMTEncoder.cpp b/libsolidity/formal/SMTEncoder.cpp index b9c43f2c5..82cd75578 100644 --- a/libsolidity/formal/SMTEncoder.cpp +++ b/libsolidity/formal/SMTEncoder.cpp @@ -154,15 +154,16 @@ void SMTEncoder::visitFunctionOrModifier() ++m_modifierDepthStack.back(); FunctionDefinition const& function = dynamic_cast(*m_callStack.back().first); - if (m_modifierDepthStack.back() == int(function.modifiers().size())) + if (m_modifierDepthStack.back() == static_cast(function.modifiers().size())) { if (function.isImplemented()) function.body().accept(*this); } else { - solAssert(m_modifierDepthStack.back() < int(function.modifiers().size()), ""); - ASTPointer const& modifierInvocation = function.modifiers()[m_modifierDepthStack.back()]; + solAssert(m_modifierDepthStack.back() < static_cast(function.modifiers().size()), ""); + ASTPointer const& modifierInvocation = + function.modifiers()[static_cast(m_modifierDepthStack.back())]; solAssert(modifierInvocation, ""); auto refDecl = modifierInvocation->name()->annotation().referencedDeclaration; if (dynamic_cast(refDecl)) @@ -1679,8 +1680,8 @@ void SMTEncoder::mergeVariables(set const& _variable for (auto const* decl: sortedVars) { solAssert(_indicesEndTrue.count(decl) && _indicesEndFalse.count(decl), ""); - int trueIndex = _indicesEndTrue.at(decl); - int falseIndex = _indicesEndFalse.at(decl); + auto trueIndex = static_cast(_indicesEndTrue.at(decl)); + auto falseIndex = static_cast(_indicesEndFalse.at(decl)); solAssert(trueIndex != falseIndex, ""); m_context.addAssertion(m_context.newValue(*decl) == smtutil::Expression::ite( _condition, @@ -1696,7 +1697,7 @@ smtutil::Expression SMTEncoder::currentValue(VariableDeclaration const& _decl) return m_context.variable(_decl)->currentValue(); } -smtutil::Expression SMTEncoder::valueAtIndex(VariableDeclaration const& _decl, int _index) +smtutil::Expression SMTEncoder::valueAtIndex(VariableDeclaration const& _decl, unsigned _index) { solAssert(m_context.knownVariable(_decl), ""); return m_context.variable(_decl)->valueAtIndex(_index); @@ -1819,7 +1820,7 @@ SMTEncoder::VariableIndices SMTEncoder::copyVariableIndices() void SMTEncoder::resetVariableIndices(VariableIndices const& _indices) { for (auto const& var: _indices) - m_context.variable(*var.first)->setIndex(var.second); + m_context.variable(*var.first)->setIndex(static_cast(var.second)); } void SMTEncoder::clearIndices(ContractDefinition const* _contract, FunctionDefinition const* _function) diff --git a/libsolidity/formal/SMTEncoder.h b/libsolidity/formal/SMTEncoder.h index 824d39b34..86ed21ef9 100644 --- a/libsolidity/formal/SMTEncoder.h +++ b/libsolidity/formal/SMTEncoder.h @@ -201,7 +201,7 @@ protected: smtutil::Expression currentValue(VariableDeclaration const& _decl); /// @returns an expression denoting the value of the variable declared in @a _decl /// at the given index. Does not ensure that this index exists. - smtutil::Expression valueAtIndex(VariableDeclaration const& _decl, int _index); + smtutil::Expression valueAtIndex(VariableDeclaration const& _decl, unsigned _index); /// Returns the expression corresponding to the AST node. /// If _targetType is not null apply conversion. /// Throws if the expression does not exist. diff --git a/libsolidity/formal/SymbolicVariables.cpp b/libsolidity/formal/SymbolicVariables.cpp index 002df6002..3f86b48d9 100644 --- a/libsolidity/formal/SymbolicVariables.cpp +++ b/libsolidity/formal/SymbolicVariables.cpp @@ -66,12 +66,12 @@ string SymbolicVariable::currentName() const return uniqueSymbol(m_ssa->index()); } -smtutil::Expression SymbolicVariable::valueAtIndex(int _index) const +smtutil::Expression SymbolicVariable::valueAtIndex(unsigned _index) const { return m_context.newVariable(uniqueSymbol(_index), m_sort); } -string SymbolicVariable::nameAtIndex(int _index) const +string SymbolicVariable::nameAtIndex(unsigned _index) const { return uniqueSymbol(_index); } @@ -170,12 +170,12 @@ smtutil::Expression SymbolicFunctionVariable::currentFunctionValue() const return m_declaration; } -smtutil::Expression SymbolicFunctionVariable::valueAtIndex(int _index) const +smtutil::Expression SymbolicFunctionVariable::valueAtIndex(unsigned _index) const { return m_abstract.valueAtIndex(_index); } -smtutil::Expression SymbolicFunctionVariable::functionValueAtIndex(int _index) const +smtutil::Expression SymbolicFunctionVariable::functionValueAtIndex(unsigned _index) const { return SymbolicVariable::valueAtIndex(_index); } @@ -304,7 +304,7 @@ smtutil::Expression SymbolicArrayVariable::currentValue(frontend::TypePointer co return m_pair.currentValue(); } -smtutil::Expression SymbolicArrayVariable::valueAtIndex(int _index) const +smtutil::Expression SymbolicArrayVariable::valueAtIndex(unsigned _index) const { return m_pair.valueAtIndex(_index); } diff --git a/libsolidity/formal/SymbolicVariables.h b/libsolidity/formal/SymbolicVariables.h index a7c0bd170..65dce43f0 100644 --- a/libsolidity/formal/SymbolicVariables.h +++ b/libsolidity/formal/SymbolicVariables.h @@ -54,8 +54,8 @@ public: virtual smtutil::Expression currentValue(frontend::TypePointer const& _targetType = TypePointer{}) const; std::string currentName() const; - virtual smtutil::Expression valueAtIndex(int _index) const; - virtual std::string nameAtIndex(int _index) const; + virtual smtutil::Expression valueAtIndex(unsigned _index) const; + virtual std::string nameAtIndex(unsigned _index) const; virtual smtutil::Expression resetIndex(); virtual smtutil::Expression setIndex(unsigned _index); virtual smtutil::Expression increaseIndex(); @@ -165,10 +165,10 @@ public: // Explicit request the function declaration. smtutil::Expression currentFunctionValue() const; - smtutil::Expression valueAtIndex(int _index) const override; + smtutil::Expression valueAtIndex(unsigned _index) const override; // Explicit request the function declaration. - smtutil::Expression functionValueAtIndex(int _index) const; + smtutil::Expression functionValueAtIndex(unsigned _index) const; smtutil::Expression resetIndex() override; smtutil::Expression setIndex(unsigned _index) override; @@ -251,7 +251,7 @@ public: SymbolicArrayVariable(SymbolicArrayVariable&&) = default; smtutil::Expression currentValue(frontend::TypePointer const& _targetType = TypePointer{}) const override; - smtutil::Expression valueAtIndex(int _index) const override; + smtutil::Expression valueAtIndex(unsigned _index) const override; smtutil::Expression resetIndex() override { SymbolicVariable::resetIndex(); return m_pair.resetIndex(); } smtutil::Expression setIndex(unsigned _index) override { SymbolicVariable::setIndex(_index); return m_pair.setIndex(_index); } smtutil::Expression increaseIndex() override { SymbolicVariable::increaseIndex(); return m_pair.increaseIndex(); } diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index f662d361e..a8efdfb0b 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -982,7 +982,7 @@ string CompilerStack::applyRemapping(string const& _path, string const& _context bestMatchTarget = util::sanitizePath(redir.target); } string path = bestMatchTarget; - path.append(_path.begin() + longestPrefix, _path.end()); + path.append(_path.begin() + static_cast(longestPrefix), _path.end()); return path; } diff --git a/libsolidity/interface/GasEstimator.cpp b/libsolidity/interface/GasEstimator.cpp index 7282b1598..1a86f36ce 100644 --- a/libsolidity/interface/GasEstimator.cpp +++ b/libsolidity/interface/GasEstimator.cpp @@ -54,8 +54,8 @@ GasEstimator::ASTGasConsumptionSelfAccumulated GasEstimator::structuralEstimatio { solAssert(!!block.startState, ""); GasMeter meter(block.startState->copy(), m_evmVersion); - auto const end = _items.begin() + block.end; - for (auto iter = _items.begin() + block.begin; iter != end; ++iter) + auto const end = _items.begin() + static_cast(block.end); + for (auto iter = _items.begin() + static_cast(block.begin); iter != end; ++iter) particularCosts[iter->location()] += meter.estimateMax(*iter); } diff --git a/libsolidity/interface/StorageLayout.cpp b/libsolidity/interface/StorageLayout.cpp index 8e6915085..806652cfe 100644 --- a/libsolidity/interface/StorageLayout.cpp +++ b/libsolidity/interface/StorageLayout.cpp @@ -50,7 +50,7 @@ Json::Value StorageLayout::generate(VariableDeclaration const& _var, u256 const& TypePointer varType = _var.type(); varEntry["label"] = _var.name(); - varEntry["astId"] = int(_var.id()); + varEntry["astId"] = static_cast(_var.id()); varEntry["contract"] = m_contract->fullyQualifiedName(); varEntry["slot"] = _slot.str(); varEntry["offset"] = _offset; diff --git a/test/libsolidity/ABIEncoderTests.cpp b/test/libsolidity/ABIEncoderTests.cpp index b816de6fd..2e50fe743 100644 --- a/test/libsolidity/ABIEncoderTests.cpp +++ b/test/libsolidity/ABIEncoderTests.cpp @@ -606,7 +606,7 @@ BOOST_AUTO_TEST_CASE(bytesNN_arrays) BOTH_ENCODERS( for (size_t size = 1; size < 15; size++) { - for (size_t width: {1, 2, 4, 5, 7, 15, 16, 17, 31, 32}) + for (size_t width: {1u, 2u, 4u, 5u, 7u, 15u, 16u, 17u, 31u, 32u}) { string source = boost::algorithm::replace_all_copy(sourceCode, "SIZE", to_string(size)); source = boost::algorithm::replace_all_copy(source, "UINTWIDTH", to_string(width * 8)); @@ -651,7 +651,7 @@ BOOST_AUTO_TEST_CASE(bytesNN_arrays_dyn) BOTH_ENCODERS( for (size_t size = 0; size < 15; size++) { - for (size_t width: {1, 2, 4, 5, 7, 15, 16, 17, 31, 32}) + for (size_t width: {1u, 2u, 4u, 5u, 7u, 15u, 16u, 17u, 31u, 32u}) { string source = boost::algorithm::replace_all_copy(sourceCode, "SIZE", to_string(size)); source = boost::algorithm::replace_all_copy(source, "UINTWIDTH", to_string(width * 8)); diff --git a/test/libsolidity/SMTCheckerJSONTest.cpp b/test/libsolidity/SMTCheckerJSONTest.cpp index 484db13ff..396ecb280 100644 --- a/test/libsolidity/SMTCheckerJSONTest.cpp +++ b/test/libsolidity/SMTCheckerJSONTest.cpp @@ -116,21 +116,21 @@ TestCase::TestResult SMTCheckerJSONTest::run(ostream& _stream, string const& _li !location["end"].isInt() ) BOOST_THROW_EXCEPTION(runtime_error("Error must have a SourceLocation with start and end.")); - int start = location["start"].asInt(); - int end = location["end"].asInt(); + size_t start = location["start"].asUInt(); + size_t end = location["end"].asUInt(); std::string sourceName; if (location.isMember("source") && location["source"].isString()) sourceName = location["source"].asString(); - if (start >= static_cast(preamble.size())) + if (start >= preamble.size()) start -= preamble.size(); - if (end >= static_cast(preamble.size())) + if (end >= preamble.size()) end -= preamble.size(); m_errorList.emplace_back(SyntaxTestError{ error["type"].asString(), error["message"].asString(), sourceName, - start, - end + static_cast(start), + static_cast(end) }); } } diff --git a/test/libsolidity/SolidityExpressionCompiler.cpp b/test/libsolidity/SolidityExpressionCompiler.cpp index d40e64ebf..41c850b4d 100644 --- a/test/libsolidity/SolidityExpressionCompiler.cpp +++ b/test/libsolidity/SolidityExpressionCompiler.cpp @@ -143,8 +143,8 @@ bytes compileFirstExpression( ); context.resetVisitedNodes(contract); context.setMostDerivedContract(*contract); - unsigned parametersSize = _localVariables.size(); // assume they are all one slot on the stack - context.adjustStackOffset(parametersSize); + size_t parametersSize = _localVariables.size(); // assume they are all one slot on the stack + context.adjustStackOffset(static_cast(parametersSize)); for (vector const& variable: _localVariables) context.addVariable( dynamic_cast(resolveDeclaration(*sourceUnit, variable, resolver)), diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp index fec67f0e6..4062b1928 100644 --- a/test/libsolidity/SolidityOptimizer.cpp +++ b/test/libsolidity/SolidityOptimizer.cpp @@ -491,7 +491,7 @@ BOOST_AUTO_TEST_CASE(constant_optimization_early_exit) #endif #endif #if __SANITIZE_ADDRESS__ - maxDuration = size_t(-1); + maxDuration = numeric_limits::max(); BOOST_TEST_MESSAGE("Disabled constant optimizer run time check for address sanitizer build."); #endif BOOST_CHECK_MESSAGE(duration <= maxDuration, "Compilation of constants took longer than 20 seconds."); diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp index 12fbc3fce..364c0e2d5 100644 --- a/test/libsolidity/SolidityParser.cpp +++ b/test/libsolidity/SolidityParser.cpp @@ -675,7 +675,7 @@ BOOST_AUTO_TEST_CASE(inline_asm_end_location) bool visit(InlineAssembly const& _inlineAsm) override { auto loc = _inlineAsm.location(); - auto asmStr = loc.source->source().substr(loc.start, loc.end - loc.start); + auto asmStr = loc.source->source().substr(static_cast(loc.start), static_cast(loc.end - loc.start)); BOOST_CHECK_EQUAL(asmStr, "assembly { a := 0x12345678 }"); visited = true; diff --git a/test/libsolidity/SyntaxTest.cpp b/test/libsolidity/SyntaxTest.cpp index 55a77ed30..47411748e 100644 --- a/test/libsolidity/SyntaxTest.cpp +++ b/test/libsolidity/SyntaxTest.cpp @@ -98,9 +98,9 @@ void SyntaxTest::filterObtainedErrors() { // ignore the version & license pragma inserted by the testing tool when calculating locations. if (location->start >= static_cast(preamble.size())) - locationStart = location->start - (preamble.size()); + locationStart = location->start - static_cast(preamble.size()); if (location->end >= static_cast(preamble.size())) - locationEnd = location->end - (preamble.size()); + locationEnd = location->end - static_cast(preamble.size()); if (location->source) sourceName = location->source->name(); } diff --git a/test/libsolidity/util/BytesUtils.cpp b/test/libsolidity/util/BytesUtils.cpp index 72f7c7594..fd2cd2fcf 100644 --- a/test/libsolidity/util/BytesUtils.cpp +++ b/test/libsolidity/util/BytesUtils.cpp @@ -348,10 +348,10 @@ string BytesUtils::formatBytesRange( size_t BytesUtils::countRightPaddedZeros(bytes const& _bytes) { - return find_if( + return static_cast(find_if( _bytes.rbegin(), _bytes.rend(), [](uint8_t b) { return b != '\0'; } - ) - _bytes.rbegin(); + ) - _bytes.rbegin()); } diff --git a/test/libsolidity/util/TestFileParserTests.cpp b/test/libsolidity/util/TestFileParserTests.cpp index d24a80b95..4fb44d7cd 100644 --- a/test/libsolidity/util/TestFileParserTests.cpp +++ b/test/libsolidity/util/TestFileParserTests.cpp @@ -66,7 +66,7 @@ void testFunctionCall( ABI_CHECK(_call.expectations.rawBytes(), _expectations); BOOST_REQUIRE_EQUAL(_call.displayMode, _mode); BOOST_REQUIRE_EQUAL(_call.value.value, _value.value); - BOOST_REQUIRE_EQUAL(size_t(_call.value.unit), size_t(_value.unit)); + BOOST_REQUIRE_EQUAL(static_cast(_call.value.unit), static_cast(_value.unit)); BOOST_REQUIRE_EQUAL(_call.arguments.comment, _argumentComment); BOOST_REQUIRE_EQUAL(_call.expectations.comment, _expectationComment); From b17915a6ba84a5f2373a03c40c4b0d893f3ae625 Mon Sep 17 00:00:00 2001 From: a3d4 Date: Sat, 30 May 2020 01:42:36 +0200 Subject: [PATCH 03/24] Add error IDs to JSON --- Changelog.md | 1 + docs/using-the-compiler.rst | 4 +++- libsolidity/interface/StandardCompiler.cpp | 13 ++++++++++--- .../output_selection_all_A1/output.json | 6 +++--- .../output_selection_all_A2/output.json | 6 +++--- .../output_selection_all_blank/output.json | 6 +++--- .../output_selection_all_star/output.json | 6 +++--- .../output_selection_single_A1/output.json | 2 +- .../output_selection_single_B1/output.json | 4 ++-- .../output_selection_single_all/output.json | 2 +- .../cmdlineTests/recovery_standard_json/output.json | 4 ++-- .../standard_empty_file_name/output.json | 2 +- .../standard_immutable_references/output.json | 2 +- .../standard_secondary_source_location/output.json | 2 +- test/cmdlineTests/storage_layout_bytes/output.json | 2 +- .../storage_layout_dyn_array/output.json | 2 +- test/cmdlineTests/storage_layout_many/output.json | 2 +- .../cmdlineTests/storage_layout_mapping/output.json | 2 +- test/cmdlineTests/storage_layout_smoke/output.json | 2 +- .../storage_layout_smoke_two_contracts/output.json | 2 +- test/cmdlineTests/storage_layout_string/output.json | 2 +- test/cmdlineTests/storage_layout_struct/output.json | 2 +- .../storage_layout_struct_packed/output.json | 2 +- .../storage_layout_value_types/output.json | 2 +- .../storage_layout_value_types_packed/output.json | 2 +- test/libsolidity/StandardCompiler.cpp | 2 +- 26 files changed, 47 insertions(+), 37 deletions(-) diff --git a/Changelog.md b/Changelog.md index 5da6cb372..417dacef6 100644 --- a/Changelog.md +++ b/Changelog.md @@ -5,6 +5,7 @@ Language Features: Compiler Features: * Yul: Raise warning for switch statements that only have a default and no other cases. + * Add error codes to JSON output. Bugfixes: diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index 3f0252884..65f3f7ace 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -374,8 +374,10 @@ Output Description "component": "general", // Mandatory ("error" or "warning") "severity": "error", + // Optional: unique code for the cause of the error + "errorCode": "3141", // Mandatory - "message": "Invalid keyword" + "message": "Invalid keyword", // Optional: the message formatted with source location "formattedMessage": "sourceFile.sol:100: Invalid keyword" } diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index e04b0b2f1..7293f94bc 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -111,7 +111,8 @@ Json::Value formatErrorWithException( bool const& _warning, string const& _type, string const& _component, - string const& _message + string const& _message, + optional _errorId = nullopt ) { string message; @@ -122,7 +123,7 @@ Json::Value formatErrorWithException( else message = _message; - return formatError( + Json::Value error = formatError( _warning, _type, _component, @@ -131,6 +132,11 @@ Json::Value formatErrorWithException( formatSourceLocation(boost::get_error_info(_exception)), formatSecondarySourceLocation(boost::get_error_info(_exception)) ); + + if (_errorId) + error["errorCode"] = to_string(_errorId.value().error); + + return error; } map> requestedContractNames(Json::Value const& _outputSelection) @@ -857,7 +863,8 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting err.type() == Error::Type::Warning, err.typeName(), "general", - "" + "", + err.errorId() )); } } diff --git a/test/cmdlineTests/output_selection_all_A1/output.json b/test/cmdlineTests/output_selection_all_A1/output.json index 074b2062b..1e4a0b11f 100644 --- a/test/cmdlineTests/output_selection_all_A1/output.json +++ b/test/cmdlineTests/output_selection_all_A1/output.json @@ -1,6 +1,6 @@ -{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}},"b.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure +{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}},"b.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"3420","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"2018","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } ^------------------------------------------^ ","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/output_selection_all_A2/output.json b/test/cmdlineTests/output_selection_all_A2/output.json index aa2ca9d0e..5b0b55bbf 100644 --- a/test/cmdlineTests/output_selection_all_A2/output.json +++ b/test/cmdlineTests/output_selection_all_A2/output.json @@ -1,6 +1,6 @@ -{"contracts":{"a.sol":{"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure +{"contracts":{"a.sol":{"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"3420","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"2018","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } ^------------------------------------------^ ","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/output_selection_all_blank/output.json b/test/cmdlineTests/output_selection_all_blank/output.json index e0872ca8c..32c04bf8e 100644 --- a/test/cmdlineTests/output_selection_all_blank/output.json +++ b/test/cmdlineTests/output_selection_all_blank/output.json @@ -1,6 +1,6 @@ -{"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure +{"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"3420","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"2018","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } ^------------------------------------------^ ","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/output_selection_all_star/output.json b/test/cmdlineTests/output_selection_all_star/output.json index 8997ed8e2..d885876d9 100644 --- a/test/cmdlineTests/output_selection_all_star/output.json +++ b/test/cmdlineTests/output_selection_all_star/output.json @@ -1,6 +1,6 @@ -{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}},"b.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"B2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure +{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}},"b.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"B2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"3420","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"2018","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } ^------------------------------------------^ ","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/output_selection_single_A1/output.json b/test/cmdlineTests/output_selection_single_A1/output.json index 5bdef1db9..b32b519dd 100644 --- a/test/cmdlineTests/output_selection_single_A1/output.json +++ b/test/cmdlineTests/output_selection_single_A1/output.json @@ -1,2 +1,2 @@ -{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! +{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/output_selection_single_B1/output.json b/test/cmdlineTests/output_selection_single_B1/output.json index c9c929b97..aeb29d7ae 100644 --- a/test/cmdlineTests/output_selection_single_B1/output.json +++ b/test/cmdlineTests/output_selection_single_B1/output.json @@ -1,5 +1,5 @@ -{"contracts":{"b.sol":{"B2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! -","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure +{"contracts":{"b.sol":{"B2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"b.sol: Warning: Source file does not specify required compiler version! +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"b.sol","start":-1},"type":"Warning"},{"component":"general","errorCode":"2018","formattedMessage":"b.sol:2:15: Warning: Function state mutability can be restricted to pure contract A1 { function b(uint x) public { assert(x > 0); } } contract B2 { function b(uint x) public pure { assert(x > 0); } } ^------------------------------------------^ ","message":"Function state mutability can be restricted to pure","severity":"warning","sourceLocation":{"end":93,"file":"b.sol","start":49},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/output_selection_single_all/output.json b/test/cmdlineTests/output_selection_single_all/output.json index f9203fa30..07b1a5453 100644 --- a/test/cmdlineTests/output_selection_single_all/output.json +++ b/test/cmdlineTests/output_selection_single_all/output.json @@ -1,2 +1,2 @@ -{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! +{"contracts":{"a.sol":{"A1":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}},"A2":{"evm":{"bytecode":{"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"sourceMap removed"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"}],"sources":{"a.sol":{"id":0},"b.sol":{"id":1}}} diff --git a/test/cmdlineTests/recovery_standard_json/output.json b/test/cmdlineTests/recovery_standard_json/output.json index 18a3b97ce..a4113e186 100644 --- a/test/cmdlineTests/recovery_standard_json/output.json +++ b/test/cmdlineTests/recovery_standard_json/output.json @@ -1,7 +1,7 @@ -{"errors":[{"component":"general","formattedMessage":"A:2:58: ParserError: Expected type name +{"errors":[{"component":"general","errorCode":"3546","formattedMessage":"A:2:58: ParserError: Expected type name pragma solidity >=0.0; contract Errort6 { using foo for ; /* missing type name */ } ^ -","message":"Expected type name","severity":"error","sourceLocation":{"end":94,"file":"A","start":93},"type":"ParserError"},{"component":"general","formattedMessage":"A:2:84: Warning: Recovered in ContractDefinition at '}'. +","message":"Expected type name","severity":"error","sourceLocation":{"end":94,"file":"A","start":93},"type":"ParserError"},{"component":"general","errorCode":"3796","formattedMessage":"A:2:84: Warning: Recovered in ContractDefinition at '}'. pragma solidity >=0.0; contract Errort6 { using foo for ; /* missing type name */ } ^ ","message":"Recovered in ContractDefinition at '}'.","severity":"warning","sourceLocation":{"end":120,"file":"A","start":119},"type":"Warning"}],"sources":{"A":{"ast":{"absolutePath":"A","exportedSymbols":{"Errort6":[3]},"id":4,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:0"},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","documentation":null,"fullyImplemented":true,"id":3,"linearizedBaseContracts":[3],"name":"Errort6","nodeType":"ContractDefinition","nodes":[],"scope":4,"src":"59:35:0"}],"src":"36:84:0"},"id":0}}} diff --git a/test/cmdlineTests/standard_empty_file_name/output.json b/test/cmdlineTests/standard_empty_file_name/output.json index d1ab4c870..04bc54a92 100644 --- a/test/cmdlineTests/standard_empty_file_name/output.json +++ b/test/cmdlineTests/standard_empty_file_name/output.json @@ -1,4 +1,4 @@ -{"errors":[{"component":"general","formattedMessage":":2:24: DeclarationError: Declaration \"A\" not found in \"\" (referenced as \".\"). +{"errors":[{"component":"general","errorCode":"2904","formattedMessage":":2:24: DeclarationError: Declaration \"A\" not found in \"\" (referenced as \".\"). pragma solidity >=0.0; import {A} from \".\"; ^------------------^ ","message":"Declaration \"A\" not found in \"\" (referenced as \".\").","severity":"error","type":"DeclarationError"}],"sources":{}} diff --git a/test/cmdlineTests/standard_immutable_references/output.json b/test/cmdlineTests/standard_immutable_references/output.json index f39a67c07..48376adc5 100644 --- a/test/cmdlineTests/standard_immutable_references/output.json +++ b/test/cmdlineTests/standard_immutable_references/output.json @@ -1,2 +1,2 @@ -{"contracts":{"a.sol":{"A":{"evm":{"deployedBytecode":{"immutableReferences":{"3":[{"length":32,"start":77}]},"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"36:96:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74:56;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;108:7;126:1;119:8;;74:56;:::o"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! +{"contracts":{"a.sol":{"A":{"evm":{"deployedBytecode":{"immutableReferences":{"3":[{"length":32,"start":77}]},"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"36:96:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74:56;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;108:7;126:1;119:8;;74:56;:::o"}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"}],"sources":{"a.sol":{"id":0}}} diff --git a/test/cmdlineTests/standard_secondary_source_location/output.json b/test/cmdlineTests/standard_secondary_source_location/output.json index d9f56b80d..b32b00028 100644 --- a/test/cmdlineTests/standard_secondary_source_location/output.json +++ b/test/cmdlineTests/standard_secondary_source_location/output.json @@ -1,4 +1,4 @@ -{"errors":[{"component":"general","formattedMessage":"A:2:112: DeclarationError: Base constructor arguments given twice. +{"errors":[{"component":"general","errorCode":"3364","formattedMessage":"A:2:112: DeclarationError: Base constructor arguments given twice. pragma solidity >=0.0; contract A { constructor(uint) public {} } contract B is A(2) { } contract C is A(3) {} contract D is B, C {} ^-------------------^ A:2:81: First constructor call is here: diff --git a/test/cmdlineTests/storage_layout_bytes/output.json b/test/cmdlineTests/storage_layout_bytes/output.json index 4414b07d5..613189a2a 100644 --- a/test/cmdlineTests/storage_layout_bytes/output.json +++ b/test/cmdlineTests/storage_layout_bytes/output.json @@ -1,2 +1,2 @@ -{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"s1","offset":0,"slot":"0","type":"t_bytes_storage"},{"astId":5,"contract":"fileA:A","label":"s2","offset":0,"slot":"1","type":"t_bytes_storage"}],"types":{"t_bytes_storage":{"encoding":"bytes","label":"bytes","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"s1","offset":0,"slot":"0","type":"t_bytes_storage"},{"astId":5,"contract":"fileA:A","label":"s2","offset":0,"slot":"1","type":"t_bytes_storage"}],"types":{"t_bytes_storage":{"encoding":"bytes","label":"bytes","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_dyn_array/output.json b/test/cmdlineTests/storage_layout_dyn_array/output.json index 0581b35a1..8be650aa5 100644 --- a/test/cmdlineTests/storage_layout_dyn_array/output.json +++ b/test/cmdlineTests/storage_layout_dyn_array/output.json @@ -1,2 +1,2 @@ -{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"array1","offset":0,"slot":"0","type":"t_array(t_uint256)dyn_storage"},{"astId":6,"contract":"fileA:A","label":"array2","offset":0,"slot":"1","type":"t_array(t_bool)dyn_storage"}],"types":{"t_array(t_bool)dyn_storage":{"base":"t_bool","encoding":"dynamic_array","label":"bool[]","numberOfBytes":"32"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"array1","offset":0,"slot":"0","type":"t_array(t_uint256)dyn_storage"},{"astId":6,"contract":"fileA:A","label":"array2","offset":0,"slot":"1","type":"t_array(t_bool)dyn_storage"}],"types":{"t_array(t_bool)dyn_storage":{"base":"t_bool","encoding":"dynamic_array","label":"bool[]","numberOfBytes":"32"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_many/output.json b/test/cmdlineTests/storage_layout_many/output.json index 8e14940a9..a413e1027 100644 --- a/test/cmdlineTests/storage_layout_many/output.json +++ b/test/cmdlineTests/storage_layout_many/output.json @@ -1,2 +1,2 @@ -{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"6","type":"t_address"},{"astId":26,"contract":"fileA:A","label":"map","offset":0,"slot":"7","type":"t_mapping(t_uint256,t_mapping(t_address,t_bool))"},{"astId":29,"contract":"fileA:A","label":"array","offset":0,"slot":"8","type":"t_array(t_uint256)dyn_storage"},{"astId":31,"contract":"fileA:A","label":"s1","offset":0,"slot":"9","type":"t_string_storage"},{"astId":33,"contract":"fileA:A","label":"b1","offset":0,"slot":"10","type":"t_bytes_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_bytes_storage":{"encoding":"bytes","label":"bytes","numberOfBytes":"32"},"t_mapping(t_address,t_bool)":{"encoding":"mapping","key":"t_address","label":"mapping(address => bool)","numberOfBytes":"32","value":"t_bool"},"t_mapping(t_uint256,t_mapping(t_address,t_bool))":{"encoding":"mapping","key":"t_uint256","label":"mapping(uint256 => mapping(address => bool))","numberOfBytes":"32","value":"t_mapping(t_address,t_bool)"},"t_string_storage":{"encoding":"bytes","label":"string","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint128"},{"astId":4,"contract":"fileA:A","label":"b","offset":16,"slot":"0","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"1","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"3","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"128"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"6","type":"t_address"},{"astId":26,"contract":"fileA:A","label":"map","offset":0,"slot":"7","type":"t_mapping(t_uint256,t_mapping(t_address,t_bool))"},{"astId":29,"contract":"fileA:A","label":"array","offset":0,"slot":"8","type":"t_array(t_uint256)dyn_storage"},{"astId":31,"contract":"fileA:A","label":"s1","offset":0,"slot":"9","type":"t_string_storage"},{"astId":33,"contract":"fileA:A","label":"b1","offset":0,"slot":"10","type":"t_bytes_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_bytes_storage":{"encoding":"bytes","label":"bytes","numberOfBytes":"32"},"t_mapping(t_address,t_bool)":{"encoding":"mapping","key":"t_address","label":"mapping(address => bool)","numberOfBytes":"32","value":"t_bool"},"t_mapping(t_uint256,t_mapping(t_address,t_bool))":{"encoding":"mapping","key":"t_uint256","label":"mapping(uint256 => mapping(address => bool))","numberOfBytes":"32","value":"t_mapping(t_address,t_bool)"},"t_string_storage":{"encoding":"bytes","label":"string","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint128"},{"astId":4,"contract":"fileA:A","label":"b","offset":16,"slot":"0","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"1","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"3","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"128"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_mapping/output.json b/test/cmdlineTests/storage_layout_mapping/output.json index c380197ca..e3a4944fd 100644 --- a/test/cmdlineTests/storage_layout_mapping/output.json +++ b/test/cmdlineTests/storage_layout_mapping/output.json @@ -1,2 +1,2 @@ -{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":10,"contract":"fileA:A","label":"map","offset":0,"slot":"2","type":"t_mapping(t_uint256,t_mapping(t_address,t_bool))"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_mapping(t_address,t_bool)":{"encoding":"mapping","key":"t_address","label":"mapping(address => bool)","numberOfBytes":"32","value":"t_bool"},"t_mapping(t_uint256,t_mapping(t_address,t_bool))":{"encoding":"mapping","key":"t_uint256","label":"mapping(uint256 => mapping(address => bool))","numberOfBytes":"32","value":"t_mapping(t_address,t_bool)"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":10,"contract":"fileA:A","label":"map","offset":0,"slot":"2","type":"t_mapping(t_uint256,t_mapping(t_address,t_bool))"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_mapping(t_address,t_bool)":{"encoding":"mapping","key":"t_address","label":"mapping(address => bool)","numberOfBytes":"32","value":"t_bool"},"t_mapping(t_uint256,t_mapping(t_address,t_bool))":{"encoding":"mapping","key":"t_uint256","label":"mapping(uint256 => mapping(address => bool))","numberOfBytes":"32","value":"t_mapping(t_address,t_bool)"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_smoke/output.json b/test/cmdlineTests/storage_layout_smoke/output.json index fb8c544c6..c5830bb00 100644 --- a/test/cmdlineTests/storage_layout_smoke/output.json +++ b/test/cmdlineTests/storage_layout_smoke/output.json @@ -1,2 +1,2 @@ -{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[],"types":null}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[],"types":null}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_smoke_two_contracts/output.json b/test/cmdlineTests/storage_layout_smoke_two_contracts/output.json index abbace7a9..8ec54ae26 100644 --- a/test/cmdlineTests/storage_layout_smoke_two_contracts/output.json +++ b/test/cmdlineTests/storage_layout_smoke_two_contracts/output.json @@ -1,2 +1,2 @@ -{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[],"types":null}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[],"types":null}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0},"fileB":{"id":1}}} diff --git a/test/cmdlineTests/storage_layout_string/output.json b/test/cmdlineTests/storage_layout_string/output.json index 6ce9e236d..59312174f 100644 --- a/test/cmdlineTests/storage_layout_string/output.json +++ b/test/cmdlineTests/storage_layout_string/output.json @@ -1,2 +1,2 @@ -{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"s1","offset":0,"slot":"0","type":"t_string_storage"},{"astId":5,"contract":"fileA:A","label":"s2","offset":0,"slot":"1","type":"t_string_storage"}],"types":{"t_string_storage":{"encoding":"bytes","label":"string","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"s1","offset":0,"slot":"0","type":"t_string_storage"},{"astId":5,"contract":"fileA:A","label":"s2","offset":0,"slot":"1","type":"t_string_storage"}],"types":{"t_string_storage":{"encoding":"bytes","label":"string","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_struct/output.json b/test/cmdlineTests/storage_layout_struct/output.json index 6437d599a..e8c2d6fdc 100644 --- a/test/cmdlineTests/storage_layout_struct/output.json +++ b/test/cmdlineTests/storage_layout_struct/output.json @@ -1,2 +1,2 @@ -{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"7","type":"t_address"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"b","offset":0,"slot":"1","type":"t_uint256"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"2","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"4","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"160"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"7","type":"t_address"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"b","offset":0,"slot":"1","type":"t_uint256"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"2","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"4","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"160"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_struct_packed/output.json b/test/cmdlineTests/storage_layout_struct_packed/output.json index 44adfefda..7ac8c11eb 100644 --- a/test/cmdlineTests/storage_layout_struct_packed/output.json +++ b/test/cmdlineTests/storage_layout_struct_packed/output.json @@ -1,2 +1,2 @@ -{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"6","type":"t_address"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint128"},{"astId":4,"contract":"fileA:A","label":"b","offset":16,"slot":"0","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"1","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"3","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"128"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"6","type":"t_address"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint128"},{"astId":4,"contract":"fileA:A","label":"b","offset":16,"slot":"0","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"1","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"3","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"128"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_value_types/output.json b/test/cmdlineTests/storage_layout_value_types/output.json index 8b9d2437f..2d10422a5 100644 --- a/test/cmdlineTests/storage_layout_value_types/output.json +++ b/test/cmdlineTests/storage_layout_value_types/output.json @@ -1,2 +1,2 @@ -{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":6,"contract":"fileA:A","label":"addr","offset":0,"slot":"2","type":"t_address"},{"astId":10,"contract":"fileA:A","label":"array","offset":0,"slot":"3","type":"t_array(t_uint256)2_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":6,"contract":"fileA:A","label":"addr","offset":0,"slot":"2","type":"t_address"},{"astId":10,"contract":"fileA:A","label":"array","offset":0,"slot":"3","type":"t_array(t_uint256)2_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/cmdlineTests/storage_layout_value_types_packed/output.json b/test/cmdlineTests/storage_layout_value_types_packed/output.json index c7d956361..634cb9305 100644 --- a/test/cmdlineTests/storage_layout_value_types_packed/output.json +++ b/test/cmdlineTests/storage_layout_value_types_packed/output.json @@ -1,2 +1,2 @@ -{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint64"},{"astId":4,"contract":"fileA:A","label":"y","offset":8,"slot":"0","type":"t_uint128"},{"astId":6,"contract":"fileA:A","label":"z","offset":0,"slot":"1","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"addr","offset":0,"slot":"2","type":"t_address"},{"astId":12,"contract":"fileA:A","label":"array","offset":0,"slot":"3","type":"t_array(t_uint256)2_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"},"t_uint64":{"encoding":"inplace","label":"uint64","numberOfBytes":"8"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! +{"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint64"},{"astId":4,"contract":"fileA:A","label":"y","offset":8,"slot":"0","type":"t_uint128"},{"astId":6,"contract":"fileA:A","label":"z","offset":0,"slot":"1","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"addr","offset":0,"slot":"2","type":"t_address"},{"astId":12,"contract":"fileA:A","label":"array","offset":0,"slot":"3","type":"t_array(t_uint256)2_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"},"t_uint64":{"encoding":"inplace","label":"uint64","numberOfBytes":"8"}}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"fileA: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"fileA","start":-1},"type":"Warning"}],"sources":{"fileA":{"id":0}}} diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index 3b7b1d128..f8ae1d873 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -466,7 +466,7 @@ BOOST_AUTO_TEST_CASE(compilation_error) { BOOST_CHECK_EQUAL( util::jsonCompactPrint(error), - "{\"component\":\"general\",\"formattedMessage\":\"fileA:1:23: ParserError: Expected identifier but got '}'\\n" + "{\"component\":\"general\",\"errorCode\":\"2314\",\"formattedMessage\":\"fileA:1:23: ParserError: Expected identifier but got '}'\\n" "contract A { function }\\n ^\\n\",\"message\":\"Expected identifier but got '}'\"," "\"severity\":\"error\",\"sourceLocation\":{\"end\":23,\"file\":\"fileA\",\"start\":22},\"type\":\"ParserError\"}" ); From 51e64fe0b1c9e1b750f61e86104a2c063f37b6eb Mon Sep 17 00:00:00 2001 From: a3d4 Date: Thu, 4 Jun 2020 03:19:47 +0200 Subject: [PATCH 04/24] Add error IDs to console output --- Changelog.md | 2 +- liblangutil/SourceReferenceExtractor.cpp | 10 ++++++- liblangutil/SourceReferenceExtractor.h | 12 ++++----- liblangutil/SourceReferenceFormatter.cpp | 5 +--- liblangutil/SourceReferenceFormatterHuman.cpp | 2 ++ liblangutil/SourceReferenceFormatterHuman.h | 18 +++++-------- solc/CommandLineInterface.cpp | 12 +++++++-- solc/CommandLineInterface.h | 2 ++ test/cmdlineTests.sh | 1 + test/cmdlineTests/error_codes/args | 1 + test/cmdlineTests/error_codes/err | 26 +++++++++++++++++++ test/cmdlineTests/error_codes/exit | 1 + test/cmdlineTests/error_codes/input.sol | 8 ++++++ test/libsolidity/ASTJSONTest.cpp | 2 +- test/libsolidity/GasTest.cpp | 2 +- tools/solidityUpgrade/SourceUpgrade.cpp | 2 +- tools/solidityUpgrade/UpgradeChange.cpp | 2 +- 17 files changed, 77 insertions(+), 31 deletions(-) create mode 100644 test/cmdlineTests/error_codes/args create mode 100644 test/cmdlineTests/error_codes/err create mode 100644 test/cmdlineTests/error_codes/exit create mode 100644 test/cmdlineTests/error_codes/input.sol diff --git a/Changelog.md b/Changelog.md index 417dacef6..bfe5b0d01 100644 --- a/Changelog.md +++ b/Changelog.md @@ -5,7 +5,7 @@ Language Features: Compiler Features: * Yul: Raise warning for switch statements that only have a default and no other cases. - * Add error codes to JSON output. + * Output compilation error codes. Bugfixes: diff --git a/liblangutil/SourceReferenceExtractor.cpp b/liblangutil/SourceReferenceExtractor.cpp index 0a6ff0421..89f84011d 100644 --- a/liblangutil/SourceReferenceExtractor.cpp +++ b/liblangutil/SourceReferenceExtractor.cpp @@ -38,7 +38,15 @@ SourceReferenceExtractor::Message SourceReferenceExtractor::extract(util::Except for (auto const& info: secondaryLocation->infos) secondary.emplace_back(extract(&info.second, info.first)); - return Message{std::move(primary), _category, std::move(secondary)}; + return Message{std::move(primary), _category, std::move(secondary), nullopt}; +} + +SourceReferenceExtractor::Message SourceReferenceExtractor::extract(Error const& _error) +{ + string category = (_error.type() == Error::Type::Warning) ? "Warning" : "Error"; + Message message = extract(_error, category); + message.errorId = _error.errorId(); + return message; } SourceReference SourceReferenceExtractor::extract(SourceLocation const* _location, std::string message) diff --git a/liblangutil/SourceReferenceExtractor.h b/liblangutil/SourceReferenceExtractor.h index 6aa0ab34a..b9dababb9 100644 --- a/liblangutil/SourceReferenceExtractor.h +++ b/liblangutil/SourceReferenceExtractor.h @@ -16,16 +16,14 @@ */ #pragma once +#include + #include +#include #include #include #include -namespace solidity::util -{ -struct Exception; -} - namespace solidity::langutil { @@ -58,8 +56,6 @@ struct SourceReference } }; -struct SourceLocation; - namespace SourceReferenceExtractor { struct Message @@ -67,9 +63,11 @@ namespace SourceReferenceExtractor SourceReference primary; std::string category; // "Error", "Warning", ... std::vector secondary; + std::optional errorId; }; Message extract(util::Exception const& _exception, std::string _category); + Message extract(Error const& _error); SourceReference extract(SourceLocation const* _location, std::string message = ""); } diff --git a/liblangutil/SourceReferenceFormatter.cpp b/liblangutil/SourceReferenceFormatter.cpp index 965755a10..e10f251d5 100644 --- a/liblangutil/SourceReferenceFormatter.cpp +++ b/liblangutil/SourceReferenceFormatter.cpp @@ -80,10 +80,7 @@ void SourceReferenceFormatter::printExceptionInformation(util::Exception const& void SourceReferenceFormatter::printErrorInformation(Error const& _error) { - printExceptionInformation( - _error, - (_error.type() == Error::Type::Warning) ? "Warning" : "Error" - ); + printExceptionInformation(SourceReferenceExtractor::extract(_error)); } void SourceReferenceFormatter::printExceptionInformation(SourceReferenceExtractor::Message const& _msg) diff --git a/liblangutil/SourceReferenceFormatterHuman.cpp b/liblangutil/SourceReferenceFormatterHuman.cpp index 3560955c7..998ca7bf5 100644 --- a/liblangutil/SourceReferenceFormatterHuman.cpp +++ b/liblangutil/SourceReferenceFormatterHuman.cpp @@ -151,6 +151,8 @@ void SourceReferenceFormatterHuman::printExceptionInformation(SourceReferenceExt { // exception header line errorColored() << _msg.category; + if (m_withErrorIds && _msg.errorId.has_value()) + errorColored() << " (" << _msg.errorId.value().error << ")"; messageColored() << ": " << _msg.primary.message << '\n'; printSourceLocation(_msg.primary); diff --git a/liblangutil/SourceReferenceFormatterHuman.h b/liblangutil/SourceReferenceFormatterHuman.h index 060adc00e..b468f3756 100644 --- a/liblangutil/SourceReferenceFormatterHuman.h +++ b/liblangutil/SourceReferenceFormatterHuman.h @@ -29,22 +29,14 @@ #include #include -namespace solidity::util -{ -struct Exception; // forward -} - namespace solidity::langutil { -struct SourceLocation; -struct SourceReference; - class SourceReferenceFormatterHuman: public SourceReferenceFormatter { public: - SourceReferenceFormatterHuman(std::ostream& _stream, bool colored): - SourceReferenceFormatter{_stream}, m_colored{colored} + SourceReferenceFormatterHuman(std::ostream& _stream, bool _colored, bool _withErrorIds): + SourceReferenceFormatter{_stream}, m_colored{_colored}, m_withErrorIds(_withErrorIds) {} void printSourceLocation(SourceReference const& _ref) override; @@ -54,12 +46,13 @@ public: static std::string formatExceptionInformation( util::Exception const& _exception, std::string const& _name, - bool colored = false + bool _colored = false, + bool _withErrorIds = false ) { std::ostringstream errorOutput; - SourceReferenceFormatterHuman formatter(errorOutput, colored); + SourceReferenceFormatterHuman formatter(errorOutput, _colored, _withErrorIds); formatter.printExceptionInformation(_exception, _name); return errorOutput.str(); } @@ -75,6 +68,7 @@ private: private: bool m_colored; + bool m_withErrorIds; }; } diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index e84ce6dd3..8b6117a2d 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -177,6 +177,7 @@ static string const g_strVersion = "version"; static string const g_strIgnoreMissingFiles = "ignore-missing"; static string const g_strColor = "color"; static string const g_strNoColor = "no-color"; +static string const g_strErrorIds = "error-codes"; static string const g_strOldReporter = "old-reporter"; static string const g_argAbi = g_strAbi; @@ -222,6 +223,7 @@ static string const g_stdinFileName = g_stdinFileNameStr; static string const g_argIgnoreMissingFiles = g_strIgnoreMissingFiles; static string const g_argColor = g_strColor; static string const g_argNoColor = g_strNoColor; +static string const g_argErrorIds = g_strErrorIds; static string const g_argOldReporter = g_strOldReporter; /// Possible arguments to for --combined-json @@ -876,6 +878,10 @@ General Information)").c_str(), g_argNoColor.c_str(), "Explicitly disable colored output, disabling terminal auto-detection." ) + ( + g_argErrorIds.c_str(), + "Output error codes." + ) ( g_argOldReporter.c_str(), "Enables old diagnostics reporter (legacy option, will be removed)." @@ -989,6 +995,8 @@ General Information)").c_str(), m_coloredOutput = !m_args.count(g_argNoColor) && (isatty(STDERR_FILENO) || m_args.count(g_argColor)); + m_withErrorIds = m_args.count(g_argErrorIds); + if (m_args.count(g_argHelp) || (isatty(fileno(stdin)) && _argc == 1)) { sout() << desc; @@ -1294,7 +1302,7 @@ bool CommandLineInterface::processInput() if (m_args.count(g_argOldReporter)) formatter = make_unique(serr(false)); else - formatter = make_unique(serr(false), m_coloredOutput); + formatter = make_unique(serr(false), m_coloredOutput, m_withErrorIds); try { @@ -1732,7 +1740,7 @@ bool CommandLineInterface::assemble( if (m_args.count(g_argOldReporter)) formatter = make_unique(serr(false)); else - formatter = make_unique(serr(false), m_coloredOutput); + formatter = make_unique(serr(false), m_coloredOutput, m_withErrorIds); for (auto const& error: stack.errors()) { diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index 00b9181ec..2c871a670 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -131,6 +131,8 @@ private: CompilerStack::MetadataHash m_metadataHash = CompilerStack::MetadataHash::IPFS; /// Whether or not to colorize diagnostics output. bool m_coloredOutput = true; + /// Whether or not to output error IDs. + bool m_withErrorIds = false; }; } diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index 07e249492..448ba5a6e 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -121,6 +121,7 @@ function test_solc_behaviour() rm "$stdout_path.bak" else sed -i.bak -e '/^Warning: This is a pre-release compiler version, please do not use it in production./d' "$stderr_path" + sed -i.bak -e '/^Warning (3805): This is a pre-release compiler version, please do not use it in production./d' "$stderr_path" sed -i.bak -e 's/\(^[ ]*auxdata: \)0x[0-9a-f]*$/\1AUXDATA REMOVED/' "$stdout_path" sed -i.bak -e 's/ Consider adding "pragma .*$//' "$stderr_path" # Remove trailing empty lines. Needs a line break to make OSX sed happy. diff --git a/test/cmdlineTests/error_codes/args b/test/cmdlineTests/error_codes/args new file mode 100644 index 000000000..330f811c7 --- /dev/null +++ b/test/cmdlineTests/error_codes/args @@ -0,0 +1 @@ +--error-codes diff --git a/test/cmdlineTests/error_codes/err b/test/cmdlineTests/error_codes/err new file mode 100644 index 000000000..1d983a7fd --- /dev/null +++ b/test/cmdlineTests/error_codes/err @@ -0,0 +1,26 @@ +Error (4937): No visibility specified. Did you intend to add "public"? + --> error_codes/input.sol:4:5: + | +4 | function f() { + | ^ (Relevant source part starts here and spans across multiple lines). + +Warning (3420): Source file does not specify required compiler version! +--> error_codes/input.sol + +Error (4247): Expression has to be an lvalue. + --> error_codes/input.sol:5:9: + | +5 | 2=0; + | ^ + +Error (7407): Type int_const 0 is not implicitly convertible to expected type int_const 2. + --> error_codes/input.sol:5:11: + | +5 | 2=0; + | ^ + +Error (2614): Indexed expression has to be a type, mapping or array (is literal_string "") + --> error_codes/input.sol:6:9: + | +6 | ""[2]; + | ^^ diff --git a/test/cmdlineTests/error_codes/exit b/test/cmdlineTests/error_codes/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/error_codes/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/error_codes/input.sol b/test/cmdlineTests/error_codes/input.sol new file mode 100644 index 000000000..78aceb41f --- /dev/null +++ b/test/cmdlineTests/error_codes/input.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-3.0 + +contract C { + function f() { + 2=0; + ""[2]; + } +} diff --git a/test/libsolidity/ASTJSONTest.cpp b/test/libsolidity/ASTJSONTest.cpp index 3cc8b3ab3..974e0f486 100644 --- a/test/libsolidity/ASTJSONTest.cpp +++ b/test/libsolidity/ASTJSONTest.cpp @@ -134,7 +134,7 @@ TestCase::TestResult ASTJSONTest::run(ostream& _stream, string const& _linePrefi c.analyze(); else { - SourceReferenceFormatterHuman formatter(_stream, _formatted); + SourceReferenceFormatterHuman formatter(_stream, _formatted, false); for (auto const& error: c.errors()) formatter.printErrorInformation(*error); return TestResult::FatalError; diff --git a/test/libsolidity/GasTest.cpp b/test/libsolidity/GasTest.cpp index 893a20715..d76979c9c 100644 --- a/test/libsolidity/GasTest.cpp +++ b/test/libsolidity/GasTest.cpp @@ -118,7 +118,7 @@ TestCase::TestResult GasTest::run(ostream& _stream, string const& _linePrefix, b if (!compiler().parseAndAnalyze() || !compiler().compile()) { - SourceReferenceFormatterHuman formatter(_stream, _formatted); + SourceReferenceFormatterHuman formatter(_stream, _formatted, false); for (auto const& error: compiler().errors()) formatter.printErrorInformation(*error); return TestResult::FatalError; diff --git a/tools/solidityUpgrade/SourceUpgrade.cpp b/tools/solidityUpgrade/SourceUpgrade.cpp index 8c05ecc9f..7005fd336 100644 --- a/tools/solidityUpgrade/SourceUpgrade.cpp +++ b/tools/solidityUpgrade/SourceUpgrade.cpp @@ -390,7 +390,7 @@ void SourceUpgrade::applyChange( void SourceUpgrade::printErrors() const { - auto formatter = make_unique(cout, true); + auto formatter = make_unique(cout, true, false); for (auto const& error: m_compiler->errors()) if (error->type() != langutil::Error::Type::Warning) diff --git a/tools/solidityUpgrade/UpgradeChange.cpp b/tools/solidityUpgrade/UpgradeChange.cpp index ff7d6d68f..a897a4e13 100644 --- a/tools/solidityUpgrade/UpgradeChange.cpp +++ b/tools/solidityUpgrade/UpgradeChange.cpp @@ -36,7 +36,7 @@ void UpgradeChange::apply() void UpgradeChange::log(bool const _shorten) const { stringstream os; - SourceReferenceFormatterHuman formatter{os, true}; + SourceReferenceFormatterHuman formatter{os, true, false}; string start = to_string(m_location.start); string end = to_string(m_location.end); From 3d115a28fd5c8cec43d773c7cbad5f9398e0ebbb Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 10 Jun 2020 11:24:35 +0200 Subject: [PATCH 05/24] Fix documentation example. --- docs/types/reference-types.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/types/reference-types.rst b/docs/types/reference-types.rst index 6283eaa0e..5bd242f06 100644 --- a/docs/types/reference-types.rst +++ b/docs/types/reference-types.rst @@ -430,7 +430,13 @@ Array slices are useful to ABI-decode secondary data passed in function paramete /// Forward call to "setOwner(address)" that is implemented by client /// after doing basic validation on the address argument. function forward(bytes calldata _payload) external { - bytes4 sig = abi.decode(_payload[:4], (bytes4)); + // Since ABI decoding requires padded data, we cannot + // use abi.decode(_payload[:4], (bytes4)). + bytes4 sig = + _payload[0] | + (bytes4(_payload[1]) >> 8) | + (bytes4(_payload[2]) >> 16) | + (bytes4(_payload[3]) >> 24); if (sig == bytes4(keccak256("setOwner(address)"))) { address owner = abi.decode(_payload[4:], (address)); require(owner != address(0), "Address of owner cannot be zero."); From e73fe1727708c656e13d4d944e0e8ccd12991e0d Mon Sep 17 00:00:00 2001 From: Djordje Mijovic Date: Fri, 5 Jun 2020 10:37:00 +0200 Subject: [PATCH 06/24] Fixing ICE on calling externally a function that returns calldata pointers Co-authored-by: chriseth --- Changelog.md | 4 +--- libsolidity/ast/TypeProvider.h | 12 +++++++++-- libsolidity/ast/Types.cpp | 20 +++++++++++++------ .../calldata/calldata_bytes_external.sol | 12 +++++++++++ 4 files changed, 37 insertions(+), 11 deletions(-) create mode 100644 test/libsolidity/semanticTests/calldata/calldata_bytes_external.sol diff --git a/Changelog.md b/Changelog.md index 5da6cb372..83801c65c 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,15 +2,13 @@ Language Features: - Compiler Features: * Yul: Raise warning for switch statements that only have a default and no other cases. - Bugfixes: * SMTChecker: Fix internal error when encoding tuples of tuples. * SMTChecker: Fix aliasing soundness after pushing to an array pointer. - + * Type system: Fix internal compiler error on calling externally a function that returns variables with calldata location. ### 0.6.9 (2020-06-04) diff --git a/libsolidity/ast/TypeProvider.h b/libsolidity/ast/TypeProvider.h index 38f2642eb..a86542d16 100644 --- a/libsolidity/ast/TypeProvider.h +++ b/libsolidity/ast/TypeProvider.h @@ -112,14 +112,22 @@ public: /// @returns a copy of @a _type having the same location as this (and is not a pointer type) /// if _type is a reference type and an unmodified copy of _type otherwise. /// This function is mostly useful to modify inner types appropriately. - static Type const* withLocationIfReference(DataLocation _location, Type const* _type) + static Type const* withLocationIfReference(DataLocation _location, Type const* _type, bool _isPointer = false) { if (auto refType = dynamic_cast(_type)) - return withLocation(refType, _location, false); + return withLocation(refType, _location, _isPointer); return _type; } + static bool isReferenceWithLocation(Type const* _type, DataLocation _location) + { + if (auto const* refType = dynamic_cast(_type)) + if (refType->location() == _location) + return true; + return false; + } + /// @returns the internally-facing or externally-facing type of a function or the type of a function declaration. static FunctionType const* function(FunctionDefinition const& _function, FunctionType::Kind _kind = FunctionType::Kind::Declaration); diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 66681ea10..8114be800 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -3445,13 +3445,21 @@ FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary, TypePointers parameterTypes; for (auto const& t: m_parameterTypes) - { - auto refType = dynamic_cast(t); - if (refType && refType->location() == DataLocation::CallData) - parameterTypes.push_back(TypeProvider::withLocation(refType, DataLocation::Memory, true)); + if (TypeProvider::isReferenceWithLocation(t, DataLocation::CallData)) + parameterTypes.push_back( + TypeProvider::withLocationIfReference(DataLocation::Memory, t, true) + ); else parameterTypes.push_back(t); - } + + TypePointers returnParameterTypes; + for (auto const& returnParamType: m_returnParameterTypes) + if (TypeProvider::isReferenceWithLocation(returnParamType, DataLocation::CallData)) + returnParameterTypes.push_back( + TypeProvider::withLocationIfReference(DataLocation::Memory, returnParamType, true) + ); + else + returnParameterTypes.push_back(returnParamType); Kind kind = m_kind; if (_inLibrary) @@ -3465,7 +3473,7 @@ FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary, return TypeProvider::function( parameterTypes, - m_returnParameterTypes, + returnParameterTypes, m_parameterNames, m_returnParameterNames, kind, diff --git a/test/libsolidity/semanticTests/calldata/calldata_bytes_external.sol b/test/libsolidity/semanticTests/calldata/calldata_bytes_external.sol new file mode 100644 index 000000000..9917e736a --- /dev/null +++ b/test/libsolidity/semanticTests/calldata/calldata_bytes_external.sol @@ -0,0 +1,12 @@ +contract CalldataTest { + function test(bytes calldata x) public returns (bytes calldata) { + return x; + } + function tester(bytes calldata x) public returns (byte) { + return this.test(x)[2]; + } +} +// ==== +// EVMVersion: >=byzantium +// ---- +// tester(bytes): 0x20, 0x08, "abcdefgh" -> "c" From baabe65a84efd86e4975291a05a57a8be0313f1c Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 10 Jun 2020 16:46:02 +0200 Subject: [PATCH 07/24] Fix bound functions with calldata parameters. --- Changelog.md | 3 ++ docs/bugs.json | 8 ++++ docs/bugs_by_version.json | 4 +- libsolidity/ast/Types.cpp | 38 ++++++++++++++----- libsolidity/ast/Types.h | 7 +++- .../libraries/bound_returning_calldata.sol | 17 +++++++++ .../bound_returning_calldata_external.sol | 20 ++++++++++ .../libraries/bound_to_calldata.sol | 17 +++++++++ .../libraries/bound_to_calldata_external.sol | 20 ++++++++++ .../syntaxTests/bound/bound_calldata.sol | 9 +++++ 10 files changed, 131 insertions(+), 12 deletions(-) create mode 100644 test/libsolidity/semanticTests/libraries/bound_returning_calldata.sol create mode 100644 test/libsolidity/semanticTests/libraries/bound_returning_calldata_external.sol create mode 100644 test/libsolidity/semanticTests/libraries/bound_to_calldata.sol create mode 100644 test/libsolidity/semanticTests/libraries/bound_to_calldata_external.sol create mode 100644 test/libsolidity/syntaxTests/bound/bound_calldata.sol diff --git a/Changelog.md b/Changelog.md index 7f0f505f0..a344d516d 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,8 @@ ### 0.6.10 (unreleased) +Important Bugfixes: + * Fixed a bug related to internal library functions with ``calldata`` parameters called via ``using for``. + Language Features: Compiler Features: diff --git a/docs/bugs.json b/docs/bugs.json index 90f211c1f..3a29ad352 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -1,4 +1,12 @@ [ + { + "name": "UsingForCalldata", + "summary": "Function calls to internal library functions with calldata parameters called via ``using for`` can result in invalid data being read.", + "description": "Function calls to internal library functions using the ``using for`` mechanism copied all calldata parameters to memory first and passed them on like that, regardless of whether it was an internal or an external call. Due to that, the called function would receive a memory pointer that is interpreted as a calldata pointer.", + "introduced": "0.6.9", + "fixed": "0.6.10", + "severity": "very low" + }, { "name": "MissingEscapingInFormatting", "summary": "String literals containing double backslash characters passed directly to external or encoding function calls can lead to a different string being used when ABIEncoderV2 is enabled.", diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index 2d81e8783..37d4419e7 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -1165,7 +1165,9 @@ "released": "2020-05-14" }, "0.6.9": { - "bugs": [], + "bugs": [ + "UsingForCalldata" + ], "released": "2020-06-04" } } \ No newline at end of file diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 8114be800..828ff7815 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -371,7 +371,8 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition seenFunctions.insert(function); if (function->parameters().empty()) continue; - FunctionTypePointer fun = FunctionType(*function, FunctionType::Kind::External).asExternallyCallableFunction(true, true); + FunctionTypePointer fun = + dynamic_cast(*function->typeViaContractName()).asBoundFunction(); if (_type.isImplicitlyConvertibleTo(*fun->selfType())) members.emplace_back(function->name(), fun, function); } @@ -3438,11 +3439,32 @@ TypePointer FunctionType::copyAndSetCallOptions(bool _setGas, bool _setValue, bo ); } -FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary, bool _bound) const +FunctionTypePointer FunctionType::asBoundFunction() const { - if (_bound) - solAssert(!m_parameterTypes.empty(), ""); + solAssert(!m_parameterTypes.empty(), ""); + FunctionDefinition const* fun = dynamic_cast(m_declaration); + solAssert(fun && fun->libraryFunction(), ""); + solAssert(!m_gasSet, ""); + solAssert(!m_valueSet, ""); + solAssert(!m_saltSet, ""); + return TypeProvider::function( + m_parameterTypes, + m_returnParameterTypes, + m_parameterNames, + m_returnParameterNames, + m_kind, + m_arbitraryParameters, + m_stateMutability, + m_declaration, + m_gasSet, + m_valueSet, + m_saltSet, + true + ); +} +FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary) const +{ TypePointers parameterTypes; for (auto const& t: m_parameterTypes) if (TypeProvider::isReferenceWithLocation(t, DataLocation::CallData)) @@ -3465,10 +3487,8 @@ FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary, if (_inLibrary) { solAssert(!!m_declaration, "Declaration has to be available."); - if (!m_declaration->isPublic()) - kind = Kind::Internal; // will be inlined - else - kind = Kind::DelegateCall; + solAssert(m_declaration->isPublic(), ""); + kind = Kind::DelegateCall; } return TypeProvider::function( @@ -3483,7 +3503,7 @@ FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary, m_gasSet, m_valueSet, m_saltSet, - _bound + m_bound ); } diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 609f2e9ed..1b37dc485 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -1302,13 +1302,16 @@ public: /// of the parameters to false. TypePointer copyAndSetCallOptions(bool _setGas, bool _setValue, bool _setSalt) const; + /// @returns a copy of this function type with the `bound` flag set to true. + /// Should only be called on library functions. + FunctionTypePointer asBoundFunction() const; + /// @returns a copy of this function type where the location of reference types is changed /// from CallData to Memory. This is the type that would be used when the function is /// called externally, as opposed to the parameter types that are available inside the function body. /// Also supports variants to be used for library or bound calls. /// @param _inLibrary if true, uses DelegateCall as location. - /// @param _bound if true, the function type is set to be bound. - FunctionTypePointer asExternallyCallableFunction(bool _inLibrary, bool _bound = false) const; + FunctionTypePointer asExternallyCallableFunction(bool _inLibrary) const; protected: std::vector> makeStackItems() const override; diff --git a/test/libsolidity/semanticTests/libraries/bound_returning_calldata.sol b/test/libsolidity/semanticTests/libraries/bound_returning_calldata.sol new file mode 100644 index 000000000..7451e9dc4 --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/bound_returning_calldata.sol @@ -0,0 +1,17 @@ +library D { + function f(bytes calldata _x) internal pure returns (bytes calldata) { + return _x; + } + function g(bytes calldata _x) internal pure returns (bytes memory) { + return _x; + } +} + +contract C { + using D for bytes; + function f(bytes calldata _x) public pure returns (byte, byte) { + return (_x.f()[0], _x.g()[0]); + } +} +// ---- +// f(bytes): 0x20, 4, "abcd" -> 0x6100000000000000000000000000000000000000000000000000000000000000, 0x6100000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/libraries/bound_returning_calldata_external.sol b/test/libsolidity/semanticTests/libraries/bound_returning_calldata_external.sol new file mode 100644 index 000000000..3114f8510 --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/bound_returning_calldata_external.sol @@ -0,0 +1,20 @@ +library D { + function f(bytes calldata _x) public pure returns (bytes calldata) { + return _x; + } + function g(bytes calldata _x) public pure returns (bytes memory) { + return _x; + } +} + +contract C { + using D for bytes; + function f(bytes calldata _x) public pure returns (byte, byte) { + return (_x.f()[0], _x.g()[0]); + } +} +// ==== +// EVMVersion: >homestead +// ---- +// library: D +// f(bytes): 0x20, 4, "abcd" -> 0x6100000000000000000000000000000000000000000000000000000000000000, 0x6100000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/libraries/bound_to_calldata.sol b/test/libsolidity/semanticTests/libraries/bound_to_calldata.sol new file mode 100644 index 000000000..0e9bb811b --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/bound_to_calldata.sol @@ -0,0 +1,17 @@ +library D { + function f(bytes calldata _x) internal pure returns (byte) { + return _x[0]; + } + function g(bytes memory _x) internal pure returns (byte) { + return _x[0]; + } +} + +contract C { + using D for bytes; + function f(bytes calldata _x) public pure returns (byte, byte) { + return (_x.f(), _x.g()); + } +} +// ---- +// f(bytes): 0x20, 4, "abcd" -> 0x6100000000000000000000000000000000000000000000000000000000000000, 0x6100000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/libraries/bound_to_calldata_external.sol b/test/libsolidity/semanticTests/libraries/bound_to_calldata_external.sol new file mode 100644 index 000000000..2f8c7c7f3 --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/bound_to_calldata_external.sol @@ -0,0 +1,20 @@ +library D { + function f(bytes calldata _x) public pure returns (byte) { + return _x[0]; + } + function g(bytes memory _x) public pure returns (byte) { + return _x[0]; + } +} + +contract C { + using D for bytes; + function f(bytes calldata _x) public pure returns (byte, byte) { + return (_x.f(), _x.g()); + } +} +// ==== +// EVMVersion: >homestead +// ---- +// library: D +// f(bytes): 0x20, 4, "abcd" -> 0x6100000000000000000000000000000000000000000000000000000000000000, 0x6100000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/syntaxTests/bound/bound_calldata.sol b/test/libsolidity/syntaxTests/bound/bound_calldata.sol new file mode 100644 index 000000000..f6fcf82cb --- /dev/null +++ b/test/libsolidity/syntaxTests/bound/bound_calldata.sol @@ -0,0 +1,9 @@ +library D { function f(bytes calldata) internal pure {} } +contract C { + using D for bytes; + function f(bytes memory _x) public pure { + _x.f(); + } +} +// ---- +// TypeError: (136-140): Member "f" not found or not visible after argument-dependent lookup in bytes memory. From 90b66a736250a1af0a897f0c5c67cecbdd4b74f6 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 10 Jun 2020 17:27:59 +0200 Subject: [PATCH 08/24] Fix struct member access for memory and implement for calldata. --- libsolidity/ast/Types.cpp | 15 +++++++ libsolidity/ast/Types.h | 2 + .../codegen/ir/IRGeneratorForStatements.cpp | 22 ++++++++++- .../viaYul/struct_member_access.sol | 39 +++++++++++++++++++ 4 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 test/libsolidity/semanticTests/viaYul/struct_member_access.sol diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 8114be800..dfddaef8e 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -2457,6 +2457,21 @@ set StructType::membersMissingInMemory() const return missing; } +vector> StructType::makeStackItems() const +{ + switch (m_location) + { + case DataLocation::CallData: + return {std::make_tuple("offset", TypeProvider::uint256())}; + case DataLocation::Memory: + return {std::make_tuple("mpos", TypeProvider::uint256())}; + case DataLocation::Storage: + return {std::make_tuple("slot", TypeProvider::uint256())}; + } + solAssert(false, ""); +} + + TypePointer EnumType::encodingType() const { return TypeProvider::uint(8 * storageBytes()); diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 609f2e9ed..4ae780b63 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -980,6 +980,8 @@ public: void clearCache() const override; +protected: + std::vector> makeStackItems() const override; private: StructDefinition const& m_struct; // Caches for interfaceType(bool) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index a62251ab1..53e23d849 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -1477,7 +1477,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) pair const& offsets = structType.storageOffsetsOfMember(member); string slot = m_context.newYulVariable(); m_code << "let " << slot << " := " << - ("add(" + expression.name() + ", " + offsets.first.str() + ")\n"); + ("add(" + expression.part("slot").name() + ", " + offsets.first.str() + ")\n"); setLValue(_memberAccess, IRLValue{ type(_memberAccess), IRLValue::Storage{slot, offsets.second} @@ -1497,7 +1497,25 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) } case DataLocation::CallData: { - solUnimplementedAssert(false, ""); + string baseRef = expression.part("offset").name(); + string offset = m_context.newYulVariable(); + m_code << "let " << offset << " := " << "add(" << baseRef << ", " << to_string(structType.calldataOffsetOfMember(member)) << ")\n"; + if (_memberAccess.annotation().type->isDynamicallyEncoded()) + define(_memberAccess) << + m_utils.accessCalldataTailFunction(*_memberAccess.annotation().type) << + "(" << + baseRef << + ", " << + offset << + ")" << + std::endl; + else + define(_memberAccess) << + m_utils.readFromCalldata(*_memberAccess.annotation().type) << + "(" << + offset << + ")" << + std::endl; break; } default: diff --git a/test/libsolidity/semanticTests/viaYul/struct_member_access.sol b/test/libsolidity/semanticTests/viaYul/struct_member_access.sol new file mode 100644 index 000000000..60733d414 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/struct_member_access.sol @@ -0,0 +1,39 @@ +pragma experimental ABIEncoderV2; + +contract C { + struct S { + uint a; + uint[] b; + uint c; + } + + S s; + constructor() public { + s.a = 42; + s.b.push(1); + s.b.push(2); + s.b.push(3); + s.c = 21; + } + + function f(S memory m) public pure returns (uint, uint[] memory, uint) { + return (m.a, m.b, m.c); + } + function g(S calldata c) external pure returns (uint, uint, uint, uint, uint, uint) { + return (c.a, c.b.length, c.c, c.b[0], c.b[1], c.b[2]); + } + function g2(S calldata c1, S calldata c2) external pure returns (uint, uint, uint, uint, uint, uint) { + return (c1.a, c1.c, c2.a, c2.b.length, c2.c, c2.b[0]); + } + function h() external view returns (uint, uint, uint, uint, uint, uint) { + return (s.a, s.b.length, s.c, s.b[0], s.b[1], s.b[2]); + } +} +// ==== +// EVMVersion: >homestead +// compileViaYul: also +// ---- +// f((uint256,uint256[],uint256)): 0x20, 42, 0x60, 21, 3, 1, 2, 3 -> 42, 0x60, 21, 3, 1, 2, 3 +// g((uint256,uint256[],uint256)): 0x20, 42, 0x60, 21, 3, 1, 2, 3 -> 42, 3, 21, 1, 2, 3 +// g2((uint256,uint256[],uint256),(uint256,uint256[],uint256)): 0x40, 0x0120, 42, 0x60, 21, 2, 1, 2, 3, 7, 0x80, 9, 0, 1, 17 -> 42, 21, 7, 1, 9, 17 +// h() -> 42, 3, 21, 1, 2, 3 From 840ff40263e6463962afbbdec12a6b1a20f81a18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 11 Jun 2020 00:54:12 +0200 Subject: [PATCH 09/24] Define wasm::Type enum and use it for import parameters and result --- libyul/backends/wasm/BinaryTransform.cpp | 17 +++++++++-------- libyul/backends/wasm/BinaryTransform.h | 4 ++-- libyul/backends/wasm/TextTransform.cpp | 16 ++++++++++++++-- libyul/backends/wasm/TextTransform.h | 2 ++ libyul/backends/wasm/WasmAST.h | 10 ++++++++-- libyul/backends/wasm/WasmCodeTransform.cpp | 22 ++++++++++++++++------ libyul/backends/wasm/WasmCodeTransform.h | 2 ++ 7 files changed, 53 insertions(+), 20 deletions(-) diff --git a/libyul/backends/wasm/BinaryTransform.cpp b/libyul/backends/wasm/BinaryTransform.cpp index ce97225e0..4bc43f121 100644 --- a/libyul/backends/wasm/BinaryTransform.cpp +++ b/libyul/backends/wasm/BinaryTransform.cpp @@ -25,6 +25,7 @@ #include #include +#include using namespace std; using namespace solidity; @@ -475,7 +476,7 @@ BinaryTransform::Type BinaryTransform::typeOf(FunctionImport const& _import) { return { encodeTypes(_import.paramTypes), - encodeTypes(_import.returnType ? vector(1, *_import.returnType) : vector()) + encodeTypes(_import.returnType ? vector(1, *_import.returnType) : vector()) }; } @@ -483,26 +484,26 @@ BinaryTransform::Type BinaryTransform::typeOf(FunctionDefinition const& _funDef) { return { - encodeTypes(vector(_funDef.parameterNames.size(), "i64")), - encodeTypes(vector(_funDef.returns ? 1 : 0, "i64")) + encodeTypes(vector(_funDef.parameterNames.size(), wasm::Type::i64)), + encodeTypes(vector(_funDef.returns ? 1 : 0, wasm::Type::i64)) }; } -uint8_t BinaryTransform::encodeType(string const& _typeName) +uint8_t BinaryTransform::encodeType(wasm::Type _type) { - if (_typeName == "i32") + if (_type == wasm::Type::i32) return uint8_t(ValueType::I32); - else if (_typeName == "i64") + else if (_type == wasm::Type::i64) return uint8_t(ValueType::I64); else yulAssert(false, ""); return 0; } -vector BinaryTransform::encodeTypes(vector const& _typeNames) +vector BinaryTransform::encodeTypes(vector const& _types) { vector result; - for (auto const& t: _typeNames) + for (wasm::Type t: _types) result.emplace_back(encodeType(t)); return result; } diff --git a/libyul/backends/wasm/BinaryTransform.h b/libyul/backends/wasm/BinaryTransform.h index f4444b2fd..1f4ecf663 100644 --- a/libyul/backends/wasm/BinaryTransform.h +++ b/libyul/backends/wasm/BinaryTransform.h @@ -71,8 +71,8 @@ private: static Type typeOf(wasm::FunctionImport const& _import); static Type typeOf(wasm::FunctionDefinition const& _funDef); - static uint8_t encodeType(std::string const& _typeName); - static std::vector encodeTypes(std::vector const& _typeNames); + static uint8_t encodeType(wasm::Type _type); + static std::vector encodeTypes(std::vector const& _types); static std::map> typeToFunctionMap( std::vector const& _imports, diff --git a/libyul/backends/wasm/TextTransform.cpp b/libyul/backends/wasm/TextTransform.cpp index fd8eaf746..a14c8069b 100644 --- a/libyul/backends/wasm/TextTransform.cpp +++ b/libyul/backends/wasm/TextTransform.cpp @@ -20,6 +20,8 @@ #include +#include + #include #include @@ -44,9 +46,9 @@ string TextTransform::run(wasm::Module const& _module) { ret += " (import \"" + imp.module + "\" \"" + imp.externalName + "\" (func $" + imp.internalName; if (!imp.paramTypes.empty()) - ret += " (param" + joinHumanReadablePrefixed(imp.paramTypes, " ", " ") + ")"; + ret += " (param" + joinHumanReadablePrefixed(imp.paramTypes | boost::adaptors::transformed(encodeType), " ", " ") + ")"; if (imp.returnType) - ret += " (result " + *imp.returnType + ")"; + ret += " (result " + encodeType(*imp.returnType) + ")"; ret += "))\n"; } @@ -193,3 +195,13 @@ string TextTransform::joinTransformed(vector const& _expressio } return ret; } + +string TextTransform::encodeType(wasm::Type _type) +{ + if (_type == wasm::Type::i32) + return "i32"; + else if (_type == wasm::Type::i64) + return "i64"; + else + yulAssert(false, "Invalid wasm type"); +} diff --git a/libyul/backends/wasm/TextTransform.h b/libyul/backends/wasm/TextTransform.h index ebbca4e9e..b8b21f7f2 100644 --- a/libyul/backends/wasm/TextTransform.h +++ b/libyul/backends/wasm/TextTransform.h @@ -63,6 +63,8 @@ private: std::vector const& _expressions, char _separator = ' ' ); + + static std::string encodeType(wasm::Type _type); }; } diff --git a/libyul/backends/wasm/WasmAST.h b/libyul/backends/wasm/WasmAST.h index 7ba7066cb..e3a3368ea 100644 --- a/libyul/backends/wasm/WasmAST.h +++ b/libyul/backends/wasm/WasmAST.h @@ -30,6 +30,12 @@ namespace solidity::yul::wasm { +enum class Type +{ + i32, + i64, +}; + struct Literal; struct StringLiteral; struct LocalVariable; @@ -76,8 +82,8 @@ struct FunctionImport { std::string module; std::string externalName; std::string internalName; - std::vector paramTypes; - std::optional returnType; + std::vector paramTypes; + std::optional returnType; }; struct FunctionDefinition diff --git a/libyul/backends/wasm/WasmCodeTransform.cpp b/libyul/backends/wasm/WasmCodeTransform.cpp index f23f51eee..0e3a17f00 100644 --- a/libyul/backends/wasm/WasmCodeTransform.cpp +++ b/libyul/backends/wasm/WasmCodeTransform.cpp @@ -127,10 +127,10 @@ wasm::Expression WasmCodeTransform::operator()(FunctionCall const& _call) builtin->name.str().substr(4), builtin->name.str(), {}, - builtin->returns.empty() ? nullopt : make_optional(builtin->returns.front().str()) + builtin->returns.empty() ? nullopt : make_optional(translatedType(builtin->returns.front())) }; for (auto const& param: builtin->parameters) - imp.paramTypes.emplace_back(param.str()); + imp.paramTypes.emplace_back(translatedType(param)); m_functionsToImport[builtin->name] = std::move(imp); } typeConversionNeeded = true; @@ -361,14 +361,14 @@ wasm::Expression WasmCodeTransform::injectTypeConversionIfNeeded(wasm::FunctionC { wasm::FunctionImport const& import = m_functionsToImport.at(YulString{_call.functionName}); for (size_t i = 0; i < _call.arguments.size(); ++i) - if (import.paramTypes.at(i) == "i32") + if (import.paramTypes.at(i) == wasm::Type::i32) _call.arguments[i] = wasm::BuiltinCall{"i32.wrap_i64", make_vector(std::move(_call.arguments[i]))}; else - yulAssert(import.paramTypes.at(i) == "i64", "Unknown type " + import.paramTypes.at(i)); + yulAssert(import.paramTypes.at(i) == wasm::Type::i64, "Invalid Wasm type"); - if (import.returnType && *import.returnType != "i64") + if (import.returnType && *import.returnType != wasm::Type::i64) { - yulAssert(*import.returnType == "i32", "Invalid type " + *import.returnType); + yulAssert(*import.returnType == wasm::Type::i32, "Invalid Wasm type"); return wasm::BuiltinCall{"i64.extend_i32_u", make_vector(std::move(_call))}; } return {std::move(_call)}; @@ -403,3 +403,13 @@ void WasmCodeTransform::allocateGlobals(size_t _amount) m_nameDispenser.newName("global_"_yulstring).str() }); } + +wasm::Type WasmCodeTransform::translatedType(yul::Type _yulType) +{ + if (_yulType == "i32"_yulstring) + return wasm::Type::i32; + else if (_yulType == "i64"_yulstring) + return wasm::Type::i64; + else + yulAssert(false, "This Yul type does not have a corresponding type in Wasm."); +} diff --git a/libyul/backends/wasm/WasmCodeTransform.h b/libyul/backends/wasm/WasmCodeTransform.h index 26000e385..5680269f4 100644 --- a/libyul/backends/wasm/WasmCodeTransform.h +++ b/libyul/backends/wasm/WasmCodeTransform.h @@ -89,6 +89,8 @@ private: /// Makes sure that there are at least @a _amount global variables. void allocateGlobals(size_t _amount); + static wasm::Type translatedType(yul::Type _yulType); + Dialect const& m_dialect; NameDispenser m_nameDispenser; From 6a82d32ef6f494edd9682f2a4495f066ac64d9af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 28 May 2020 21:20:19 +0200 Subject: [PATCH 10/24] Add the ability to store variable types in wasm AST --- libyul/backends/wasm/BinaryTransform.cpp | 11 ++++++----- libyul/backends/wasm/TextTransform.cpp | 9 +++++---- libyul/backends/wasm/WasmAST.h | 13 ++++++++----- libyul/backends/wasm/WasmCodeTransform.cpp | 18 ++++++++++-------- 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/libyul/backends/wasm/BinaryTransform.cpp b/libyul/backends/wasm/BinaryTransform.cpp index 4bc43f121..875d93dbf 100644 --- a/libyul/backends/wasm/BinaryTransform.cpp +++ b/libyul/backends/wasm/BinaryTransform.cpp @@ -298,7 +298,8 @@ bytes BinaryTransform::run(Module const& _module) bytes BinaryTransform::operator()(Literal const& _literal) { - return toBytes(Opcode::I64Const) + lebEncodeSigned(_literal.value); + yulAssert(holds_alternative(_literal.value), ""); + return toBytes(Opcode::I64Const) + lebEncodeSigned(get(_literal.value)); } bytes BinaryTransform::operator()(StringLiteral const&) @@ -457,8 +458,8 @@ bytes BinaryTransform::operator()(FunctionDefinition const& _function) m_locals.clear(); size_t varIdx = 0; - for (size_t i = 0; i < _function.parameterNames.size(); ++i) - m_locals[_function.parameterNames[i]] = varIdx++; + for (size_t i = 0; i < _function.parameters.size(); ++i) + m_locals[_function.parameters[i].name] = varIdx++; for (size_t i = 0; i < _function.locals.size(); ++i) m_locals[_function.locals[i].variableName] = varIdx++; @@ -484,8 +485,8 @@ BinaryTransform::Type BinaryTransform::typeOf(FunctionDefinition const& _funDef) { return { - encodeTypes(vector(_funDef.parameterNames.size(), wasm::Type::i64)), - encodeTypes(vector(_funDef.returns ? 1 : 0, wasm::Type::i64)) + encodeTypes(vector(_funDef.parameters.size(), wasm::Type::i64)), + encodeTypes(vector(_funDef.returnType.has_value() ? 1 : 0, wasm::Type::i64)) }; } diff --git a/libyul/backends/wasm/TextTransform.cpp b/libyul/backends/wasm/TextTransform.cpp index a14c8069b..84f2ce972 100644 --- a/libyul/backends/wasm/TextTransform.cpp +++ b/libyul/backends/wasm/TextTransform.cpp @@ -67,7 +67,8 @@ string TextTransform::run(wasm::Module const& _module) string TextTransform::operator()(wasm::Literal const& _literal) { - return "(i64.const " + to_string(_literal.value) + ")"; + yulAssert(holds_alternative(_literal.value), ""); + return "(i64.const " + to_string(get(_literal.value)) + ")"; } string TextTransform::operator()(wasm::StringLiteral const& _literal) @@ -164,9 +165,9 @@ string TextTransform::indented(string const& _in) string TextTransform::transform(wasm::FunctionDefinition const& _function) { string ret = "(func $" + _function.name + "\n"; - for (auto const& param: _function.parameterNames) - ret += " (param $" + param + " i64)\n"; - if (_function.returns) + for (auto const& param: _function.parameters) + ret += " (param $" + param.name + " i64)\n"; + if (_function.returnType.has_value()) ret += " (result i64)\n"; for (auto const& local: _function.locals) ret += " (local $" + local.variableName + " i64)\n"; diff --git a/libyul/backends/wasm/WasmAST.h b/libyul/backends/wasm/WasmAST.h index e3a3368ea..b22b0db84 100644 --- a/libyul/backends/wasm/WasmAST.h +++ b/libyul/backends/wasm/WasmAST.h @@ -36,6 +36,9 @@ enum class Type i64, }; +struct TypedName { std::string name; Type type; }; +using TypedNameList = std::vector; + struct Literal; struct StringLiteral; struct LocalVariable; @@ -56,7 +59,7 @@ using Expression = std::variant< Block, If, Loop, Branch, BranchIf, Return >; -struct Literal { uint64_t value; }; +struct Literal { std::variant value; }; struct StringLiteral { std::string value; }; struct LocalVariable { std::string name; }; struct GlobalVariable { std::string name; }; @@ -76,8 +79,8 @@ struct Branch { Label label; }; struct Return {}; struct BranchIf { Label label; std::unique_ptr condition; }; -struct VariableDeclaration { std::string variableName; }; -struct GlobalVariableDeclaration { std::string variableName; }; +struct VariableDeclaration { std::string variableName; Type type; }; +struct GlobalVariableDeclaration { std::string variableName; Type type; }; struct FunctionImport { std::string module; std::string externalName; @@ -89,8 +92,8 @@ struct FunctionImport { struct FunctionDefinition { std::string name; - std::vector parameterNames; - bool returns; + std::vector parameters; + std::optional returnType; std::vector locals; std::vector body; }; diff --git a/libyul/backends/wasm/WasmCodeTransform.cpp b/libyul/backends/wasm/WasmCodeTransform.cpp index 0e3a17f00..8f987824c 100644 --- a/libyul/backends/wasm/WasmCodeTransform.cpp +++ b/libyul/backends/wasm/WasmCodeTransform.cpp @@ -88,7 +88,7 @@ wasm::Expression WasmCodeTransform::operator()(VariableDeclaration const& _varDe for (auto const& var: _varDecl.variables) { variableNames.emplace_back(var.name.str()); - m_localVariables.emplace_back(wasm::VariableDeclaration{variableNames.back()}); + m_localVariables.emplace_back(wasm::VariableDeclaration{variableNames.back(), wasm::Type::i64}); } if (_varDecl.value) @@ -184,7 +184,7 @@ wasm::Expression WasmCodeTransform::operator()(Literal const& _literal) { u256 value = valueOfLiteral(_literal); yulAssert(value <= numeric_limits::max(), "Literal too large: " + value.str()); - return wasm::Literal{uint64_t(value)}; + return wasm::Literal{static_cast(value)}; } wasm::Expression WasmCodeTransform::operator()(If const& _if) @@ -193,7 +193,7 @@ wasm::Expression WasmCodeTransform::operator()(If const& _if) vector args; args.emplace_back(visitReturnByValue(*_if.condition)); - args.emplace_back(wasm::Literal{0}); + args.emplace_back(wasm::Literal{static_cast(0)}); return wasm::If{ make_unique(wasm::BuiltinCall{"i64.ne", std::move(args)}), visit(_if.body.statements), @@ -205,7 +205,7 @@ wasm::Expression WasmCodeTransform::operator()(Switch const& _switch) { wasm::Block block; string condition = m_nameDispenser.newName("condition"_yulstring).str(); - m_localVariables.emplace_back(wasm::VariableDeclaration{condition}); + m_localVariables.emplace_back(wasm::VariableDeclaration{condition, wasm::Type::i64}); block.statements.emplace_back(wasm::LocalAssignment{condition, visit(*_switch.expression)}); vector* currentBlock = &block.statements; @@ -325,10 +325,11 @@ wasm::FunctionDefinition WasmCodeTransform::translateFunction(yul::FunctionDefin wasm::FunctionDefinition fun; fun.name = _fun.name.str(); for (auto const& param: _fun.parameters) - fun.parameterNames.emplace_back(param.name.str()); + fun.parameters.push_back({param.name.str(), wasm::Type::i64}); for (auto const& retParam: _fun.returnVariables) - fun.locals.emplace_back(wasm::VariableDeclaration{retParam.name.str()}); - fun.returns = !_fun.returnVariables.empty(); + fun.locals.emplace_back(wasm::VariableDeclaration{retParam.name.str(), wasm::Type::i64}); + if (!_fun.returnVariables.empty()) + fun.returnType = wasm::Type::i64; yulAssert(m_localVariables.empty(), ""); yulAssert(m_functionBodyLabel.empty(), ""); @@ -400,7 +401,8 @@ void WasmCodeTransform::allocateGlobals(size_t _amount) { while (m_globalVariables.size() < _amount) m_globalVariables.emplace_back(wasm::GlobalVariableDeclaration{ - m_nameDispenser.newName("global_"_yulstring).str() + m_nameDispenser.newName("global_"_yulstring).str(), + wasm::Type::i64 }); } From e67f5072df6440cef895bf7dcd2c49267895658a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 28 May 2020 21:40:44 +0200 Subject: [PATCH 11/24] Add support for generating code with i32 variables in text and binary wasm --- libyul/backends/wasm/BinaryTransform.cpp | 98 ++++++++++++++----- libyul/backends/wasm/BinaryTransform.h | 1 + libyul/backends/wasm/TextTransform.cpp | 15 +-- .../args | 1 + .../err | 1 + .../input.yul | 17 ++++ .../output | 73 ++++++++++++++ 7 files changed, 177 insertions(+), 29 deletions(-) create mode 100644 test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/args create mode 100644 test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/err create mode 100644 test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/input.yul create mode 100644 test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/output diff --git a/libyul/backends/wasm/BinaryTransform.cpp b/libyul/backends/wasm/BinaryTransform.cpp index 875d93dbf..b305b9c55 100644 --- a/libyul/backends/wasm/BinaryTransform.cpp +++ b/libyul/backends/wasm/BinaryTransform.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -83,6 +84,16 @@ bytes toBytes(ValueType _vt) return toBytes(uint8_t(_vt)); } +ValueType toValueType(wasm::Type _type) +{ + if (_type == wasm::Type::i32) + return ValueType::I32; + else if (_type == wasm::Type::i64) + return ValueType::I64; + else + yulAssert(false, "Invalid wasm variable type"); +} + enum class Export: uint8_t { Function = 0x0, @@ -132,6 +143,16 @@ bytes toBytes(Opcode _o) return toBytes(uint8_t(_o)); } +Opcode constOpcodeFor(ValueType _type) +{ + if (_type == ValueType::I32) + return Opcode::I32Const; + else if (_type == ValueType::I64) + return Opcode::I64Const; + else + yulAssert(false, "Values of this type cannot be used with const opcode"); +} + static map const builtins = { {"i32.load", 0x28}, {"i64.load", 0x29}, @@ -250,6 +271,34 @@ bytes makeSection(Section _section, bytes _data) return toBytes(_section) + prefixSize(move(_data)); } +/// This is a kind of run-length-encoding of local types. +vector> groupLocalVariables(vector _localVariables) +{ + vector> localEntries; + + size_t entrySize = 0; + ValueType entryType = ValueType::I32; // Any type would work here + for (VariableDeclaration const& localVariable: _localVariables) + { + ValueType variableType = toValueType(localVariable.type); + + if (variableType != entryType) + { + if (entrySize > 0) + localEntries.emplace_back(entrySize, entryType); + + entryType = variableType; + entrySize = 0; + } + + ++entrySize; + } + if (entrySize > 0) + localEntries.emplace_back(entrySize, entryType); + + return localEntries; +} + } bytes BinaryTransform::run(Module const& _module) @@ -298,8 +347,10 @@ bytes BinaryTransform::run(Module const& _module) bytes BinaryTransform::operator()(Literal const& _literal) { - yulAssert(holds_alternative(_literal.value), ""); - return toBytes(Opcode::I64Const) + lebEncodeSigned(get(_literal.value)); + return std::visit(GenericVisitor{ + [&](uint32_t _value) -> bytes { return toBytes(Opcode::I32Const) + lebEncodeSigned(static_cast(_value)); }, + [&](uint64_t _value) -> bytes { return toBytes(Opcode::I64Const) + lebEncodeSigned(static_cast(_value)); }, + }, _literal.value); } bytes BinaryTransform::operator()(StringLiteral const&) @@ -445,15 +496,12 @@ bytes BinaryTransform::operator()(FunctionDefinition const& _function) { bytes ret; - // This is a kind of run-length-encoding of local types. Has to be adapted once - // we have locals of different types. - if (_function.locals.size() == 0) - ret += lebEncode(0); // number of locals groups - else + vector> localEntries = groupLocalVariables(_function.locals); + ret += lebEncode(localEntries.size()); + for (pair const& entry: localEntries) { - ret += lebEncode(1); // number of locals groups - ret += lebEncode(_function.locals.size()); - ret += toBytes(ValueType::I64); + ret += lebEncode(entry.first); + ret += toBytes(entry.second); } m_locals.clear(); @@ -483,22 +531,15 @@ BinaryTransform::Type BinaryTransform::typeOf(FunctionImport const& _import) BinaryTransform::Type BinaryTransform::typeOf(FunctionDefinition const& _funDef) { - return { - encodeTypes(vector(_funDef.parameters.size(), wasm::Type::i64)), - encodeTypes(vector(_funDef.returnType.has_value() ? 1 : 0, wasm::Type::i64)) + encodeTypes(_funDef.parameters), + encodeTypes(_funDef.returnType ? vector(1, *_funDef.returnType) : vector()) }; } uint8_t BinaryTransform::encodeType(wasm::Type _type) { - if (_type == wasm::Type::i32) - return uint8_t(ValueType::I32); - else if (_type == wasm::Type::i64) - return uint8_t(ValueType::I64); - else - yulAssert(false, ""); - return 0; + return uint8_t(toValueType(_type)); } vector BinaryTransform::encodeTypes(vector const& _types) @@ -509,6 +550,14 @@ vector BinaryTransform::encodeTypes(vector const& _types) return result; } +vector BinaryTransform::encodeTypes(wasm::TypedNameList const& _typedNameList) +{ + vector result; + for (TypedName const& typedName: _typedNameList) + result.emplace_back(encodeType(typedName.type)); + return result; +} + map> BinaryTransform::typeToFunctionMap( vector const& _imports, vector const& _functions @@ -614,13 +663,16 @@ bytes BinaryTransform::memorySection() bytes BinaryTransform::globalSection(vector const& _globals) { bytes result = lebEncode(_globals.size()); - for (size_t i = 0; i < _globals.size(); ++i) + for (wasm::GlobalVariableDeclaration const& global: _globals) + { + ValueType globalType = toValueType(global.type); result += - toBytes(ValueType::I64) + + toBytes(globalType) + lebEncode(static_cast(Mutability::Var)) + - toBytes(Opcode::I64Const) + + toBytes(constOpcodeFor(globalType)) + lebEncodeSigned(0) + toBytes(Opcode::End); + } return makeSection(Section::GLOBAL, move(result)); } diff --git a/libyul/backends/wasm/BinaryTransform.h b/libyul/backends/wasm/BinaryTransform.h index 1f4ecf663..c505fe2dc 100644 --- a/libyul/backends/wasm/BinaryTransform.h +++ b/libyul/backends/wasm/BinaryTransform.h @@ -73,6 +73,7 @@ private: static uint8_t encodeType(wasm::Type _type); static std::vector encodeTypes(std::vector const& _types); + static std::vector encodeTypes(wasm::TypedNameList const& _typedNameList); static std::map> typeToFunctionMap( std::vector const& _imports, diff --git a/libyul/backends/wasm/TextTransform.cpp b/libyul/backends/wasm/TextTransform.cpp index 84f2ce972..b7f1e81ea 100644 --- a/libyul/backends/wasm/TextTransform.cpp +++ b/libyul/backends/wasm/TextTransform.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -58,7 +59,7 @@ string TextTransform::run(wasm::Module const& _module) ret += " (export \"main\" (func $main))\n"; for (auto const& g: _module.globals) - ret += " (global $" + g.variableName + " (mut i64) (i64.const 0))\n"; + ret += " (global $" + g.variableName + " (mut " + encodeType(g.type) + ") (" + encodeType(g.type) + ".const 0))\n"; ret += "\n"; for (auto const& f: _module.functions) ret += transform(f) + "\n"; @@ -67,8 +68,10 @@ string TextTransform::run(wasm::Module const& _module) string TextTransform::operator()(wasm::Literal const& _literal) { - yulAssert(holds_alternative(_literal.value), ""); - return "(i64.const " + to_string(get(_literal.value)) + ")"; + return std::visit(GenericVisitor{ + [&](uint32_t _value) -> string { return "(i32.const " + to_string(_value) + ")"; }, + [&](uint64_t _value) -> string { return "(i64.const " + to_string(_value) + ")"; }, + }, _literal.value); } string TextTransform::operator()(wasm::StringLiteral const& _literal) @@ -166,11 +169,11 @@ string TextTransform::transform(wasm::FunctionDefinition const& _function) { string ret = "(func $" + _function.name + "\n"; for (auto const& param: _function.parameters) - ret += " (param $" + param.name + " i64)\n"; + ret += " (param $" + param.name + " " + encodeType(param.type) + ")\n"; if (_function.returnType.has_value()) - ret += " (result i64)\n"; + ret += " (result " + encodeType(_function.returnType.value()) + ")\n"; for (auto const& local: _function.locals) - ret += " (local $" + local.variableName + " i64)\n"; + ret += " (local $" + local.variableName + " " + encodeType(local.type) + ")\n"; ret += indented(joinTransformed(_function.body, '\n')); if (ret.back() != '\n') ret += '\n'; diff --git a/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/args b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/args new file mode 100644 index 000000000..04cd5f05b --- /dev/null +++ b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/args @@ -0,0 +1 @@ +--yul --yul-dialect ewasm --machine ewasm diff --git a/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/err b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/err new file mode 100644 index 000000000..014a1178f --- /dev/null +++ b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/err @@ -0,0 +1 @@ +Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/input.yul b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/input.yul new file mode 100644 index 000000000..2b1a6d960 --- /dev/null +++ b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/input.yul @@ -0,0 +1,17 @@ +object "object" { + code { + function main() + { + let m:i64, n:i32, p:i32, q:i64 := multireturn(1:i32, 2:i64, 3:i64, 4:i32) + } + + function multireturn(a:i32, b:i64, c:i64, d:i32) -> x:i64, y:i32, z:i32, w:i64 + { + x := b + w := c + + y := a + z := d + } + } +} diff --git a/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/output b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/output new file mode 100644 index 000000000..a99808601 --- /dev/null +++ b/test/cmdlineTests/wasm_to_wasm_function_returning_multiple_values/output @@ -0,0 +1,73 @@ + +======= wasm_to_wasm_function_returning_multiple_values/input.yul (Ewasm) ======= + +Pretty printed source: +object "object" { + code { + function main() + { + let m, n:i32, p:i32, q := multireturn(1:i32, 2, 3, 4:i32) + } + function multireturn(a:i32, b, c, d:i32) -> x, y:i32, z:i32, w + { + x := b + w := c + y := a + z := d + } + } +} + + +Binary representation: +0061736d01000000010c0260000060047e7e7e7e017e020100030302000105030100010610037e0142000b7e0142000b7e0142000b071102066d656d6f72790200046d61696e00000a4a022201047e024002404201420242034204100121002300210123012102230221030b0b0b2501047e0240200121042002210720002105200321060b20052400200624012007240220040b + +Text representation: +(module + (memory $memory (export "memory") 1) + (export "main" (func $main)) + (global $global_ (mut i64) (i64.const 0)) + (global $global__1 (mut i64) (i64.const 0)) + (global $global__2 (mut i64) (i64.const 0)) + +(func $main + (local $m i64) + (local $n i64) + (local $p i64) + (local $q i64) + (block $label_ + (block + (local.set $m (call $multireturn (i64.const 1) (i64.const 2) (i64.const 3) (i64.const 4))) + (local.set $n (global.get $global_)) + (local.set $p (global.get $global__1)) + (local.set $q (global.get $global__2)) + + ) + + ) +) + +(func $multireturn + (param $a i64) + (param $b i64) + (param $c i64) + (param $d i64) + (result i64) + (local $x i64) + (local $y i64) + (local $z i64) + (local $w i64) + (block $label__3 + (local.set $x (local.get $b)) + (local.set $w (local.get $c)) + (local.set $y (local.get $a)) + (local.set $z (local.get $d)) + + ) + (global.set $global_ (local.get $y)) + (global.set $global__1 (local.get $z)) + (global.set $global__2 (local.get $w)) + (local.get $x) +) + +) From c8759b8031a95a7d2ba0ef338d5d7864b6b1a762 Mon Sep 17 00:00:00 2001 From: Djordje Mijovic Date: Fri, 5 Jun 2020 13:36:03 +0200 Subject: [PATCH 12/24] Fixing conversion warnings in CommonData.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kamil Śliwak --- libsolutil/CommonData.cpp | 12 ++++++------ libsolutil/FixedHash.h | 38 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/libsolutil/CommonData.cpp b/libsolutil/CommonData.cpp index 72071acde..2896804ca 100644 --- a/libsolutil/CommonData.cpp +++ b/libsolutil/CommonData.cpp @@ -106,7 +106,7 @@ bytes solidity::util::fromHex(std::string const& _s, WhenError _throw) { int h = fromHex(_s[s++], _throw); if (h != -1) - ret.push_back(h); + ret.push_back(static_cast(h)); else return bytes(); } @@ -115,7 +115,7 @@ bytes solidity::util::fromHex(std::string const& _s, WhenError _throw) int h = fromHex(_s[i], _throw); int l = fromHex(_s[i + 1], _throw); if (h != -1 && l != -1) - ret.push_back((uint8_t)(h * 16 + l)); + ret.push_back(static_cast(h * 16 + l)); else return bytes(); } @@ -148,14 +148,14 @@ string solidity::util::getChecksummedAddress(string const& _addr) h256 hash = keccak256(boost::algorithm::to_lower_copy(s, std::locale::classic())); string ret = "0x"; - for (size_t i = 0; i < 40; ++i) + for (unsigned i = 0; i < 40; ++i) { char addressCharacter = s[i]; - unsigned nibble = (unsigned(hash[i / 2]) >> (4 * (1 - (i % 2)))) & 0xf; + uint8_t nibble = hash[i / 2u] >> (4u * (1u - (i % 2u))) & 0xf; if (nibble >= 8) - ret += toupper(addressCharacter); + ret += static_cast(toupper(addressCharacter)); else - ret += tolower(addressCharacter); + ret += static_cast(tolower(addressCharacter)); } return ret; } diff --git a/libsolutil/FixedHash.h b/libsolutil/FixedHash.h index 4fa5a3072..7fbb8eec9 100644 --- a/libsolutil/FixedHash.h +++ b/libsolutil/FixedHash.h @@ -64,10 +64,44 @@ public: FixedHash(Arith const& _arith) { toBigEndian(_arith, m_data); } /// Explicitly construct, copying from a byte array. - explicit FixedHash(bytes const& _b, ConstructFromHashType _t = FailIfDifferent) { if (_b.size() == N) memcpy(m_data.data(), _b.data(), std::min(_b.size(), N)); else { m_data.fill(0); if (_t != FailIfDifferent) { auto c = std::min(_b.size(), N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _b[_t == AlignRight ? _b.size() - 1 - i : i]; } } } + explicit FixedHash(bytes const& _array, ConstructFromHashType _sizeMismatchBehavior = FailIfDifferent) + { + if (_array.size() == N) + memcpy(m_data.data(), _array.data(), _array.size()); + else + { + m_data.fill(0); + if (_sizeMismatchBehavior != FailIfDifferent) + { + auto bytesToCopy = std::min(_array.size(), N); + for (size_t i = 0; i < bytesToCopy; ++i) + if (_sizeMismatchBehavior == AlignRight) + m_data[N - 1 - i] = _array[_array.size() - 1 - i]; + else + m_data[i] = _array[i]; + } + } + } /// Explicitly construct, copying from a byte array. - explicit FixedHash(bytesConstRef _b, ConstructFromHashType _t = FailIfDifferent) { if (_b.size() == N) memcpy(m_data.data(), _b.data(), std::min(_b.size(), N)); else { m_data.fill(0); if (_t != FailIfDifferent) { auto c = std::min(_b.size(), N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _b[_t == AlignRight ? _b.size() - 1 - i : i]; } } } + explicit FixedHash(bytesConstRef _b, ConstructFromHashType _t = FailIfDifferent) + { + if (_b.size() == N) + memcpy(m_data.data(), _b.data(), std::min(_b.size(), N)); + else + { + m_data.fill(0); + if (_t != FailIfDifferent) + { + auto c = std::min(_b.size(), N); + for (size_t i = 0; i < c; ++i) + if (_t == AlignRight) + m_data[N - 1 - i] = _b[_b.size() - 1 - i]; + else + m_data[i] = _b[i]; + } + } + } /// Explicitly construct, copying from a string. explicit FixedHash(std::string const& _s, ConstructFromStringType _t = FromHex, ConstructFromHashType _ht = FailIfDifferent): FixedHash(_t == FromHex ? fromHex(_s, WhenError::Throw) : solidity::util::asBytes(_s), _ht) {} From 18a196c21d89aa21eed9197a6711f1030566babd Mon Sep 17 00:00:00 2001 From: Djordje Mijovic Date: Fri, 5 Jun 2020 14:13:35 +0200 Subject: [PATCH 13/24] Fixing Keccak256 conversion warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kamil Śliwak --- libsolutil/Keccak256.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/libsolutil/Keccak256.cpp b/libsolutil/Keccak256.cpp index d9e9363f6..2a7a241c7 100644 --- a/libsolutil/Keccak256.cpp +++ b/libsolutil/Keccak256.cpp @@ -69,25 +69,25 @@ static uint64_t const RC[24] = \ #define REPEAT6(e) e e e e e e #define REPEAT24(e) REPEAT6(e e e e) #define REPEAT5(e) e e e e e -#define FOR5(v, s, e) \ +#define FOR5(type, v, s, e) \ v = 0; \ - REPEAT5(e; v += s;) + REPEAT5(e; v = static_cast(v + s);) /*** Keccak-f[1600] ***/ static inline void keccakf(void* state) { - uint64_t* a = (uint64_t*)state; + auto* a = static_cast(state); uint64_t b[5] = {0}; for (int i = 0; i < 24; i++) { uint8_t x, y; // Theta - FOR5(x, 1, + FOR5(uint8_t, x, 1, b[x] = 0; - FOR5(y, 5, + FOR5(uint8_t, y, 5, b[x] ^= a[x + y]; )) - FOR5(x, 1, - FOR5(y, 5, + FOR5(uint8_t, x, 1, + FOR5(uint8_t, y, 5, a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); )) // Rho and pi uint64_t t = a[1]; @@ -97,11 +97,12 @@ static inline void keccakf(void* state) { t = b[0]; x++; ) // Chi - FOR5(y, + FOR5(uint8_t, + y, 5, - FOR5(x, 1, + FOR5(uint8_t, x, 1, b[x] = a[y + x];) - FOR5(x, 1, + FOR5(uint8_t, x, 1, a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); )) // Iota a[0] ^= RC[i]; From 731b2efc9732cb7a57bb3aa94e291370c653535b Mon Sep 17 00:00:00 2001 From: Djordje Mijovic Date: Fri, 5 Jun 2020 14:30:57 +0200 Subject: [PATCH 14/24] Fixing liblangutil conversion warnings --- liblangutil/CharStream.cpp | 2 +- liblangutil/Scanner.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/liblangutil/CharStream.cpp b/liblangutil/CharStream.cpp index 6f2d47c48..12e4f642c 100644 --- a/liblangutil/CharStream.cpp +++ b/liblangutil/CharStream.cpp @@ -107,7 +107,7 @@ tuple CharStream::translatePositionToLineColumn(int _position) const using size_type = string::size_type; using diff_type = string::difference_type; size_type searchPosition = min(m_source.size(), size_type(_position)); - int lineNumber = count(m_source.begin(), m_source.begin() + diff_type(searchPosition), '\n'); + int lineNumber = static_cast(count(m_source.begin(), m_source.begin() + diff_type(searchPosition), '\n')); size_type lineStart; if (searchPosition == 0) lineStart = 0; diff --git a/liblangutil/Scanner.cpp b/liblangutil/Scanner.cpp index e703b5376..db0636fb9 100644 --- a/liblangutil/Scanner.cpp +++ b/liblangutil/Scanner.cpp @@ -179,7 +179,7 @@ bool Scanner::scanHexByte(char& o_scannedByte) rollback(i); return false; } - x = x * 16 + d; + x = static_cast(x * 16 + d); advance(); } o_scannedByte = x; @@ -197,7 +197,7 @@ std::optional Scanner::scanUnicode() rollback(i); return {}; } - x = x * 16 + static_cast(d); + x = x * 16 + static_cast(d); advance(); } return x; From 9e92fbccee818da1774eea8b313a63badfdc8595 Mon Sep 17 00:00:00 2001 From: Djordje Mijovic Date: Fri, 5 Jun 2020 14:33:20 +0200 Subject: [PATCH 15/24] Refactoring bytesRequired to accept and return size_t --- libevmasm/AssemblyItem.cpp | 4 ++-- libevmasm/AssemblyItem.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libevmasm/AssemblyItem.cpp b/libevmasm/AssemblyItem.cpp index c2e9056fe..b78c0e60c 100644 --- a/libevmasm/AssemblyItem.cpp +++ b/libevmasm/AssemblyItem.cpp @@ -59,7 +59,7 @@ void AssemblyItem::setPushTagSubIdAndTag(size_t _subId, size_t _tag) setData(data); } -unsigned AssemblyItem::bytesRequired(unsigned _addressLength) const +size_t AssemblyItem::bytesRequired(size_t _addressLength) const { switch (m_type) { @@ -69,7 +69,7 @@ unsigned AssemblyItem::bytesRequired(unsigned _addressLength) const case PushString: return 1 + 32; case Push: - return 1 + max(1, util::bytesRequired(data())); + return 1 + max(1, util::bytesRequired(data())); case PushSubSize: case PushProgramSize: return 1 + 4; // worst case: a 16MB program diff --git a/libevmasm/AssemblyItem.h b/libevmasm/AssemblyItem.h index 6c5e01942..4b0b7ca72 100644 --- a/libevmasm/AssemblyItem.h +++ b/libevmasm/AssemblyItem.h @@ -133,7 +133,7 @@ public: /// @returns an upper bound for the number of bytes required by this item, assuming that /// the value of a jump tag takes @a _addressLength bytes. - unsigned bytesRequired(unsigned _addressLength) const; + size_t bytesRequired(size_t _addressLength) const; size_t arguments() const; size_t returnValues() const; size_t deposit() const { return returnValues() - arguments(); } From 73cd009b8914bad0a6dfda84339be1d41b429c42 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Thu, 11 Jun 2020 12:10:33 +0200 Subject: [PATCH 16/24] Fix struct allocation in Sol->Yul. --- libsolidity/codegen/YulUtilFunctions.cpp | 3 +-- .../viaYul/memory_struct_allow.sol | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 test/libsolidity/semanticTests/viaYul/memory_struct_allow.sol diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 87142099e..f7d9711a2 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -1652,8 +1652,7 @@ string YulUtilFunctions::allocateAndInitializeMemoryStructFunction(StructType co return m_functionCollector.createFunction(functionName, [&]() { Whiskers templ(R"( function () -> memPtr { - let allocSize := () - memPtr := (allocSize) + memPtr := () let offset := memPtr <#member> mstore(offset, ()) diff --git a/test/libsolidity/semanticTests/viaYul/memory_struct_allow.sol b/test/libsolidity/semanticTests/viaYul/memory_struct_allow.sol new file mode 100644 index 000000000..b1af4fab8 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/memory_struct_allow.sol @@ -0,0 +1,21 @@ +contract C { + struct S { + uint256 a; + uint256 b; + } + + function f() public pure returns (uint256 a, uint256 b){ + assembly { + // Make free memory dirty to check that the struct allocation cleans it up again. + let freeMem := mload(0x40) + mstore(freeMem, 42) + mstore(add(freeMem, 32), 42) + } + S memory s; + return (s.a, s.b); + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> 0, 0 From 6763234410a25f81f2cb693b478cd72ec29d0e21 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Thu, 11 Jun 2020 12:57:53 +0200 Subject: [PATCH 17/24] More details in bug list. --- docs/bugs.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/bugs.json b/docs/bugs.json index 3a29ad352..34325f45b 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -2,7 +2,7 @@ { "name": "UsingForCalldata", "summary": "Function calls to internal library functions with calldata parameters called via ``using for`` can result in invalid data being read.", - "description": "Function calls to internal library functions using the ``using for`` mechanism copied all calldata parameters to memory first and passed them on like that, regardless of whether it was an internal or an external call. Due to that, the called function would receive a memory pointer that is interpreted as a calldata pointer.", + "description": "Function calls to internal library functions using the ``using for`` mechanism copied all calldata parameters to memory first and passed them on like that, regardless of whether it was an internal or an external call. Due to that, the called function would receive a memory pointer that is interpreted as a calldata pointer. Since dynamically sized arrays are passed using two stack slots for calldata, but only one for memory, this can lead to stack corruption. An affected library call will consider the JUMPDEST to which it is supposed to return as part of its arguments and will instead jump out to whatever was on the stack before the call.", "introduced": "0.6.9", "fixed": "0.6.10", "severity": "very low" From 549c90612c66c42f6b29a8afa40f6f71ac65e410 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 11 Jun 2020 12:55:30 +0200 Subject: [PATCH 18/24] Fix using for with explicit reference types. --- Changelog.md | 1 + libsolidity/ast/Types.cpp | 16 +++++++++--- .../libraries/using_for_storage_structs.sol | 25 +++++++++++++++++++ 3 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 test/libsolidity/semanticTests/libraries/using_for_storage_structs.sol diff --git a/Changelog.md b/Changelog.md index a344d516d..55238ed12 100644 --- a/Changelog.md +++ b/Changelog.md @@ -13,6 +13,7 @@ Bugfixes: * SMTChecker: Fix internal error when encoding tuples of tuples. * SMTChecker: Fix aliasing soundness after pushing to an array pointer. * Type system: Fix internal compiler error on calling externally a function that returns variables with calldata location. + * Type system: Fix bug where a bound function was not found if ``using for`` is applied to explicit reference types. ### 0.6.9 (2020-06-04) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 828ff7815..86d7f08fb 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -356,10 +356,18 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition for (ContractDefinition const* contract: _scope.annotation().linearizedBaseContracts) for (UsingForDirective const* ufd: contract->usingForDirectives()) { - if (ufd->typeName() && _type != *TypeProvider::withLocationIfReference( - typeLocation, - ufd->typeName()->annotation().type - )) + // Convert both types to pointers for comparison to see if the `using for` + // directive applies. + // Further down, we check more detailed for each function if `_type` is + // convertible to the function parameter type. + if (ufd->typeName() && + *TypeProvider::withLocationIfReference(typeLocation, &_type, true) != + *TypeProvider::withLocationIfReference( + typeLocation, + ufd->typeName()->annotation().type, + true + ) + ) continue; auto const& library = dynamic_cast( *ufd->libraryName().annotation().referencedDeclaration diff --git a/test/libsolidity/semanticTests/libraries/using_for_storage_structs.sol b/test/libsolidity/semanticTests/libraries/using_for_storage_structs.sol new file mode 100644 index 000000000..cd45726b6 --- /dev/null +++ b/test/libsolidity/semanticTests/libraries/using_for_storage_structs.sol @@ -0,0 +1,25 @@ +struct Struct { uint x; } + +library L { + function f(Struct storage _x) internal view returns (uint256) { + return _x.x; + } +} + +contract C { + using L for Struct; + + Struct s; + + function h(Struct storage _s) internal view returns (uint) { + // _s is pointer + return _s.f(); + } + function g() public returns (uint, uint) { + s.x = 7; + // s is reference + return (s.f(), h(s)); + } +} +// ---- +// g() -> 7, 7 From 3c43216a752fa6928498530d83e135da9b1fae78 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 11 Jun 2020 14:03:53 +0200 Subject: [PATCH 19/24] Set release date for 0.6.10. --- Changelog.md | 8 +++++--- docs/bugs_by_version.json | 4 ++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Changelog.md b/Changelog.md index 55238ed12..e52c63293 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,13 +1,14 @@ -### 0.6.10 (unreleased) +### 0.6.10 (2020-06-11) Important Bugfixes: * Fixed a bug related to internal library functions with ``calldata`` parameters called via ``using for``. -Language Features: Compiler Features: + * Commandline Interface: Re-group help screen. + * Output compilation error codes in standard-json and when using ``--error-codes``. * Yul: Raise warning for switch statements that only have a default and no other cases. - * Output compilation error codes. + Bugfixes: * SMTChecker: Fix internal error when encoding tuples of tuples. @@ -15,6 +16,7 @@ Bugfixes: * Type system: Fix internal compiler error on calling externally a function that returns variables with calldata location. * Type system: Fix bug where a bound function was not found if ``using for`` is applied to explicit reference types. + ### 0.6.9 (2020-06-04) Language Features: diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index 37d4419e7..8472ed5e4 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -1105,6 +1105,10 @@ ], "released": "2020-01-02" }, + "0.6.10": { + "bugs": [], + "released": "2020-06-11" + }, "0.6.2": { "bugs": [ "MissingEscapingInFormatting", From c4464b6dcd24dd0b1b5dd61d568036e0f5aee626 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Thu, 11 Jun 2020 20:15:35 +0200 Subject: [PATCH 20/24] Update travis config to move to next docker image revision. --- .travis.yml | 2 +- scripts/build_emscripten.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 36d3943df..43bd5b9b9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -110,7 +110,7 @@ matrix: before_install: - nvm install 8 - nvm use 8 - - docker pull ethereum/solidity-buildpack-deps:emsdk-1.39.15-1 + - docker pull ethereum/solidity-buildpack-deps:emsdk-1.39.15-2 env: - SOLC_EMSCRIPTEN=On - SOLC_INSTALL_DEPS_TRAVIS=Off diff --git a/scripts/build_emscripten.sh b/scripts/build_emscripten.sh index 3d6e17210..7a052aa77 100755 --- a/scripts/build_emscripten.sh +++ b/scripts/build_emscripten.sh @@ -34,5 +34,5 @@ else BUILD_DIR="$1" fi -docker run -v $(pwd):/root/project -w /root/project ethereum/solidity-buildpack-deps:emsdk-1.39.15-1 \ +docker run -v $(pwd):/root/project -w /root/project ethereum/solidity-buildpack-deps:emsdk-1.39.15-2 \ ./scripts/travis-emscripten/build_emscripten.sh $BUILD_DIR From 65937ab5c810a35113a84b7307af2c44fc81ef84 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 11 Jun 2020 19:44:14 +0200 Subject: [PATCH 21/24] Set version to 0.6.11. --- CMakeLists.txt | 2 +- Changelog.md | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e7100f141..3374ff09d 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.10") +set(PROJECT_VERSION "0.6.11") # 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 e52c63293..a4b440529 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,16 @@ +### 0.6.11 (unreleased) + +Language Features: + + +Compiler Features: + + +Bugfixes: + + + + ### 0.6.10 (2020-06-11) Important Bugfixes: From 33e7b24df05f53ba964d9dc4f315e989400f20eb Mon Sep 17 00:00:00 2001 From: Djordje Mijovic Date: Tue, 2 Jun 2020 15:34:28 +0200 Subject: [PATCH 22/24] Adding fixes for signedness conversion warnings in libyul MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kamil Śliwak --- libyul/AsmAnalysis.cpp | 4 +- libyul/Utilities.cpp | 2 +- libyul/YulString.h | 4 +- libyul/backends/evm/AsmCodeGen.cpp | 6 +- libyul/backends/evm/EVMAssembly.cpp | 6 +- libyul/backends/evm/EVMCodeTransform.cpp | 69 ++++++++++++---------- libyul/backends/evm/EVMCodeTransform.h | 4 +- libyul/backends/evm/EVMDialect.cpp | 4 +- libyul/backends/evm/EVMMetrics.cpp | 6 +- libyul/backends/wasm/BinaryTransform.cpp | 4 +- libyul/backends/wasm/WordSizeTransform.cpp | 22 +++---- libyul/optimiser/DeadCodeEliminator.cpp | 5 +- libyul/optimiser/ExpressionJoiner.cpp | 2 +- libyul/optimiser/Semantics.cpp | 2 +- libyul/optimiser/StackCompressor.cpp | 6 +- 15 files changed, 78 insertions(+), 68 deletions(-) diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index eee3beacb..07db82095 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -137,7 +137,7 @@ vector AsmAnalyzer::operator()(Identifier const& _identifier) { bool insideFunction = m_currentScope->insideFunction(); size_t stackSize = m_resolver(_identifier, yul::IdentifierContext::RValue, insideFunction); - if (stackSize != size_t(-1)) + if (stackSize != numeric_limits::max()) { found = true; yulAssert(stackSize == 1, "Invalid stack size of external reference."); @@ -479,7 +479,7 @@ void AsmAnalyzer::checkAssignment(Identifier const& _variable, YulString _valueT { bool insideFunction = m_currentScope->insideFunction(); size_t variableSize = m_resolver(_variable, yul::IdentifierContext::LValue, insideFunction); - if (variableSize != size_t(-1)) + if (variableSize != numeric_limits::max()) { found = true; variableType = &m_dialect.defaultType; diff --git a/libyul/Utilities.cpp b/libyul/Utilities.cpp index a797258eb..59e0adce3 100644 --- a/libyul/Utilities.cpp +++ b/libyul/Utilities.cpp @@ -45,7 +45,7 @@ string solidity::yul::reindent(string const& _code) auto const static countBraces = [](string const& _s) noexcept -> int { auto const i = _s.find("//"); - auto const e = i == _s.npos ? end(_s) : next(begin(_s), i); + auto const e = i == _s.npos ? end(_s) : next(begin(_s), static_cast(i)); auto const opening = count_if(begin(_s), e, [](auto ch) { return ch == '{' || ch == '('; }); auto const closing = count_if(begin(_s), e, [](auto ch) { return ch == '}' || ch == ')'; }); return opening - closing; diff --git a/libyul/YulString.h b/libyul/YulString.h index 9166cff3d..0abe1f38d 100644 --- a/libyul/YulString.h +++ b/libyul/YulString.h @@ -71,10 +71,10 @@ public: { // FNV hash - can be replaced by a better one, e.g. xxhash64 std::uint64_t hash = emptyHash(); - for (auto c: v) + for (char c: v) { hash *= 1099511628211u; - hash ^= c; + hash ^= static_cast(c); } return hash; diff --git a/libyul/backends/evm/AsmCodeGen.cpp b/libyul/backends/evm/AsmCodeGen.cpp index eefff5b18..6775214e8 100644 --- a/libyul/backends/evm/AsmCodeGen.cpp +++ b/libyul/backends/evm/AsmCodeGen.cpp @@ -143,14 +143,14 @@ pair, AbstractAssembly::SubID> EthAssemblyAdapter:: { shared_ptr assembly{make_shared()}; auto sub = m_assembly.newSub(assembly); - return {make_shared(*assembly), size_t(sub.data())}; + return {make_shared(*assembly), static_cast(sub.data())}; } void EthAssemblyAdapter::appendDataOffset(AbstractAssembly::SubID _sub) { auto it = m_dataHashBySubId.find(_sub); if (it == m_dataHashBySubId.end()) - m_assembly.pushSubroutineOffset(size_t(_sub)); + m_assembly.pushSubroutineOffset(_sub); else m_assembly << evmasm::AssemblyItem(evmasm::PushData, it->second); } @@ -159,7 +159,7 @@ void EthAssemblyAdapter::appendDataSize(AbstractAssembly::SubID _sub) { auto it = m_dataHashBySubId.find(_sub); if (it == m_dataHashBySubId.end()) - m_assembly.pushSubroutineSize(size_t(_sub)); + m_assembly.pushSubroutineSize(static_cast(_sub)); else m_assembly << u256(m_assembly.data(h256(it->second)).size()); } diff --git a/libyul/backends/evm/EVMAssembly.cpp b/libyul/backends/evm/EVMAssembly.cpp index 47f7509a3..c13a16083 100644 --- a/libyul/backends/evm/EVMAssembly.cpp +++ b/libyul/backends/evm/EVMAssembly.cpp @@ -74,7 +74,7 @@ void EVMAssembly::appendLabelReference(LabelID _labelId) EVMAssembly::LabelID EVMAssembly::newLabelId() { - m_labelPositions[m_nextLabelId] = size_t(-1); + m_labelPositions[m_nextLabelId] = numeric_limits::max(); return m_nextLabelId++; } @@ -165,7 +165,7 @@ evmasm::LinkerObject EVMAssembly::finalize() size_t referencePos = ref.first; yulAssert(m_labelPositions.count(ref.second), ""); size_t labelPos = m_labelPositions.at(ref.second); - yulAssert(labelPos != size_t(-1), "Undefined but allocated label used."); + yulAssert(labelPos != numeric_limits::max(), "Undefined but allocated label used."); updateReference(referencePos, labelReferenceSize, u256(labelPos)); } @@ -177,7 +177,7 @@ evmasm::LinkerObject EVMAssembly::finalize() void EVMAssembly::setLabelToCurrentPosition(LabelID _labelId) { yulAssert(m_labelPositions.count(_labelId), "Label not found."); - yulAssert(m_labelPositions[_labelId] == size_t(-1), "Label already set."); + yulAssert(m_labelPositions[_labelId] == numeric_limits::max(), "Label already set."); m_labelPositions[_labelId] = m_bytecode.size(); } diff --git a/libyul/backends/evm/EVMCodeTransform.cpp b/libyul/backends/evm/EVMCodeTransform.cpp index a4e19998f..f57fd35f3 100644 --- a/libyul/backends/evm/EVMCodeTransform.cpp +++ b/libyul/backends/evm/EVMCodeTransform.cpp @@ -175,28 +175,29 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl) { yulAssert(m_scope, ""); - int const numVariables = _varDecl.variables.size(); - int heightAtStart = m_assembly.stackHeight(); + size_t const numVariables = _varDecl.variables.size(); + auto heightAtStart = static_cast(m_assembly.stackHeight()); if (_varDecl.value) { std::visit(*this, *_varDecl.value); - expectDeposit(numVariables, heightAtStart); + expectDeposit(static_cast(numVariables), static_cast(heightAtStart)); } else { m_assembly.setSourceLocation(_varDecl.location); - int variablesLeft = numVariables; + size_t 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) + for (size_t varIndex = 0; varIndex < numVariables; ++varIndex) { - YulString varName = _varDecl.variables[varIndex].name; + size_t varIndexReverse = numVariables - 1 - varIndex; + YulString varName = _varDecl.variables[varIndexReverse].name; auto& var = std::get(m_scope->identifiers.at(varName)); - m_context->variableStackHeights[&var] = heightAtStart + varIndex; + m_context->variableStackHeights[&var] = heightAtStart + varIndexReverse; if (!m_allowStackOpt) continue; @@ -214,10 +215,10 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl) atTopOfStack = false; else { - int slot = *m_unusedStackSlots.begin(); + auto slot = static_cast(*m_unusedStackSlots.begin()); m_unusedStackSlots.erase(m_unusedStackSlots.begin()); m_context->variableStackHeights[&var] = slot; - if (int heightDiff = variableHeightDiff(var, varName, true)) + if (size_t heightDiff = variableHeightDiff(var, varName, true)) m_assembly.appendInstruction(evmasm::swapInstruction(heightDiff - 1)); m_assembly.appendInstruction(evmasm::Instruction::POP); } @@ -240,7 +241,7 @@ void CodeTransform::operator()(Assignment const& _assignment) { int height = m_assembly.stackHeight(); std::visit(*this, *_assignment.value); - expectDeposit(_assignment.variableNames.size(), height); + expectDeposit(static_cast(_assignment.variableNames.size()), height); m_assembly.setSourceLocation(_assignment.location); generateMultiAssignment(_assignment.variableNames); @@ -263,7 +264,7 @@ void CodeTransform::operator()(FunctionCall const& _call) else { m_assembly.setSourceLocation(_call.location); - EVMAssembly::LabelID returnLabel(-1); // only used for evm 1.0 + EVMAssembly::LabelID returnLabel(numeric_limits::max()); // only used for evm 1.0 if (!m_evm15) { returnLabel = m_assembly.newLabelId(); @@ -281,10 +282,17 @@ void CodeTransform::operator()(FunctionCall const& _call) visitExpression(arg); m_assembly.setSourceLocation(_call.location); if (m_evm15) - m_assembly.appendJumpsub(functionEntryID(_call.functionName.name, *function), function->arguments.size(), function->returns.size()); + m_assembly.appendJumpsub( + functionEntryID(_call.functionName.name, *function), + static_cast(function->arguments.size()), + static_cast(function->returns.size()) + ); else { - m_assembly.appendJumpTo(functionEntryID(_call.functionName.name, *function), function->returns.size() - function->arguments.size() - 1); + m_assembly.appendJumpTo( + functionEntryID(_call.functionName.name, *function), + static_cast(function->returns.size() - function->arguments.size()) - 1 + ); m_assembly.appendLabel(returnLabel); } } @@ -300,7 +308,7 @@ void CodeTransform::operator()(Identifier const& _identifier) { // TODO: opportunity for optimization: Do not DUP if this is the last reference // to the top most element of the stack - if (int heightDiff = variableHeightDiff(_var, _identifier.name, false)) + if (size_t heightDiff = variableHeightDiff(_var, _identifier.name, false)) m_assembly.appendInstruction(evmasm::dupInstruction(heightDiff)); else // Store something to balance the stack @@ -407,7 +415,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function) int const stackHeightBefore = m_assembly.stackHeight(); if (m_evm15) - m_assembly.appendBeginsub(functionEntryID(_function.name, function), _function.parameters.size()); + m_assembly.appendBeginsub(functionEntryID(_function.name, function), static_cast(_function.parameters.size())); else m_assembly.appendLabel(functionEntryID(_function.name, function)); @@ -465,15 +473,15 @@ void CodeTransform::operator()(FunctionDefinition const& _function) // modified parallel to the actual stack. vector stackLayout; if (!m_evm15) - stackLayout.push_back(_function.returnVariables.size()); // Move return label to the top + stackLayout.push_back(static_cast(_function.returnVariables.size())); // Move return label to the top stackLayout += vector(_function.parameters.size(), -1); // discard all arguments for (size_t i = 0; i < _function.returnVariables.size(); ++i) - stackLayout.push_back(i); // Move return values down, but keep order. + stackLayout.push_back(static_cast(i)); // Move return values down, but keep order. if (stackLayout.size() > 17) { - StackTooDeepError error(_function.name, YulString{}, stackLayout.size() - 17); + StackTooDeepError error(_function.name, YulString{}, static_cast(stackLayout.size()) - 17); error << errinfo_comment( "The function " + _function.name.str() + @@ -481,11 +489,11 @@ void CodeTransform::operator()(FunctionDefinition const& _function) to_string(stackLayout.size() - 17) + " parameters or return variables too many to fit the stack size." ); - stackError(std::move(error), m_assembly.stackHeight() - _function.parameters.size()); + stackError(std::move(error), m_assembly.stackHeight() - static_cast(_function.parameters.size())); } else { - while (!stackLayout.empty() && stackLayout.back() != int(stackLayout.size() - 1)) + while (!stackLayout.empty() && stackLayout.back() != static_cast(stackLayout.size() - 1)) if (stackLayout.back() < 0) { m_assembly.appendInstruction(evmasm::Instruction::POP); @@ -493,17 +501,17 @@ void CodeTransform::operator()(FunctionDefinition const& _function) } else { - m_assembly.appendInstruction(evmasm::swapInstruction(stackLayout.size() - stackLayout.back() - 1)); - swap(stackLayout[stackLayout.back()], stackLayout.back()); + m_assembly.appendInstruction(evmasm::swapInstruction(stackLayout.size() - static_cast(stackLayout.back()) - 1)); + swap(stackLayout[static_cast(stackLayout.back())], stackLayout.back()); } - for (int i = 0; size_t(i) < stackLayout.size(); ++i) - yulAssert(i == stackLayout[i], "Error reshuffling stack."); + for (size_t i = 0; i < stackLayout.size(); ++i) + yulAssert(i == static_cast(stackLayout[i]), "Error reshuffling stack."); } } if (m_evm15) - m_assembly.appendReturnsub(_function.returnVariables.size(), stackHeightBefore); + m_assembly.appendReturnsub(static_cast(_function.returnVariables.size()), stackHeightBefore); else - m_assembly.appendJump(stackHeightBefore - _function.returnVariables.size()); + m_assembly.appendJump(stackHeightBefore - static_cast(_function.returnVariables.size())); m_assembly.setStackHeight(stackHeightBefore); } @@ -683,7 +691,7 @@ void CodeTransform::generateAssignment(Identifier const& _variableName) if (auto var = m_scope->lookup(_variableName.name)) { Scope::Variable const& _var = std::get(*var); - if (int heightDiff = variableHeightDiff(_var, _variableName.name, true)) + if (size_t heightDiff = variableHeightDiff(_var, _variableName.name, true)) m_assembly.appendInstruction(evmasm::swapInstruction(heightDiff - 1)); m_assembly.appendInstruction(evmasm::Instruction::POP); decreaseReference(_variableName.name, _var); @@ -698,12 +706,12 @@ void CodeTransform::generateAssignment(Identifier const& _variableName) } } -int CodeTransform::variableHeightDiff(Scope::Variable const& _var, YulString _varName, bool _forSwap) +size_t CodeTransform::variableHeightDiff(Scope::Variable const& _var, YulString _varName, bool _forSwap) { yulAssert(m_context->variableStackHeights.count(&_var), ""); - int heightDiff = m_assembly.stackHeight() - m_context->variableStackHeights[&_var]; + size_t heightDiff = static_cast(m_assembly.stackHeight()) - m_context->variableStackHeights[&_var]; yulAssert(heightDiff > (_forSwap ? 1 : 0), "Negative stack difference for variable."); - int limit = _forSwap ? 17 : 16; + size_t limit = _forSwap ? 17 : 16; if (heightDiff > limit) { m_stackErrors.emplace_back(_varName, heightDiff - limit); @@ -723,4 +731,3 @@ void CodeTransform::expectDeposit(int _deposit, int _oldHeight) const { yulAssert(m_assembly.stackHeight() == _oldHeight + _deposit, "Invalid stack deposit."); } - diff --git a/libyul/backends/evm/EVMCodeTransform.h b/libyul/backends/evm/EVMCodeTransform.h index 6447aa7b1..3c9506b47 100644 --- a/libyul/backends/evm/EVMCodeTransform.h +++ b/libyul/backends/evm/EVMCodeTransform.h @@ -54,7 +54,7 @@ struct StackTooDeepError: virtual YulException struct CodeTransformContext { std::map functionEntryIDs; - std::map variableStackHeights; + std::map variableStackHeights; std::map variableReferences; struct JumpInfo @@ -200,7 +200,7 @@ private: /// Determines the stack height difference to the given variables. Throws /// if it is not yet in scope or the height difference is too large. Returns /// the (positive) stack height difference otherwise. - int variableHeightDiff(Scope::Variable const& _var, YulString _name, bool _forSwap); + size_t variableHeightDiff(Scope::Variable const& _var, YulString _name, bool _forSwap); void expectDeposit(int _deposit, int _oldHeight) const; diff --git a/libyul/backends/evm/EVMDialect.cpp b/libyul/backends/evm/EVMDialect.cpp index b5b5eda6e..6875df234 100644 --- a/libyul/backends/evm/EVMDialect.cpp +++ b/libyul/backends/evm/EVMDialect.cpp @@ -63,8 +63,8 @@ pair createEVMFunction( evmasm::InstructionInfo info = evmasm::instructionInfo(_instruction); BuiltinFunctionForEVM f; f.name = YulString{_name}; - f.parameters.resize(info.args); - f.returns.resize(info.ret); + f.parameters.resize(static_cast(info.args)); + f.returns.resize(static_cast(info.ret)); f.sideEffects = EVMDialect::sideEffectsOfInstruction(_instruction); f.controlFlowSideEffects.terminates = evmasm::SemanticInformation::terminatesControlFlow(_instruction); f.controlFlowSideEffects.reverts = evmasm::SemanticInformation::reverts(_instruction); diff --git a/libyul/backends/evm/EVMMetrics.cpp b/libyul/backends/evm/EVMMetrics.cpp index 4d1103578..f3508afb3 100644 --- a/libyul/backends/evm/EVMMetrics.cpp +++ b/libyul/backends/evm/EVMMetrics.cpp @@ -91,7 +91,11 @@ void GasMeterVisitor::operator()(Literal const& _lit) m_runGas += evmasm::GasMeter::runGas(evmasm::Instruction::PUSH1); m_dataGas += singleByteDataGas() + - size_t(evmasm::GasMeter::dataGas(toCompactBigEndian(valueOfLiteral(_lit), 1), m_isCreation, m_dialect.evmVersion())); + static_cast(evmasm::GasMeter::dataGas( + toCompactBigEndian(valueOfLiteral(_lit), 1), + m_isCreation, + m_dialect.evmVersion() + )); } void GasMeterVisitor::operator()(Identifier const&) diff --git a/libyul/backends/wasm/BinaryTransform.cpp b/libyul/backends/wasm/BinaryTransform.cpp index b305b9c55..82de96b51 100644 --- a/libyul/backends/wasm/BinaryTransform.cpp +++ b/libyul/backends/wasm/BinaryTransform.cpp @@ -376,12 +376,12 @@ bytes BinaryTransform::operator()(BuiltinCall const& _call) if (_call.functionName == "dataoffset") { string name = get(_call.arguments.at(0)).value; - return toBytes(Opcode::I64Const) + lebEncodeSigned(m_subModulePosAndSize.at(name).first); + return toBytes(Opcode::I64Const) + lebEncodeSigned(static_cast(m_subModulePosAndSize.at(name).first)); } else if (_call.functionName == "datasize") { string name = get(_call.arguments.at(0)).value; - return toBytes(Opcode::I64Const) + lebEncodeSigned(m_subModulePosAndSize.at(name).second); + return toBytes(Opcode::I64Const) + lebEncodeSigned(static_cast(m_subModulePosAndSize.at(name).second)); } bytes args = visit(_call.arguments); diff --git a/libyul/backends/wasm/WordSizeTransform.cpp b/libyul/backends/wasm/WordSizeTransform.cpp index edcc08923..473f7324f 100644 --- a/libyul/backends/wasm/WordSizeTransform.cpp +++ b/libyul/backends/wasm/WordSizeTransform.cpp @@ -112,7 +112,7 @@ void WordSizeTransform::operator()(Block& _block) yulAssert(varDecl.variables.size() == 1, ""); auto newLhs = generateU64IdentifierNames(varDecl.variables[0].name); vector ret; - for (int i = 0; i < 3; i++) + for (size_t i = 0; i < 3; i++) ret.emplace_back(VariableDeclaration{ varDecl.location, {TypedName{varDecl.location, newLhs[i], m_targetDialect.defaultType}}, @@ -143,7 +143,7 @@ void WordSizeTransform::operator()(Block& _block) auto newRhs = expandValue(*varDecl.value); auto newLhs = generateU64IdentifierNames(varDecl.variables[0].name); vector ret; - for (int i = 0; i < 4; i++) + for (size_t i = 0; i < 4; i++) ret.emplace_back(VariableDeclaration{ varDecl.location, {TypedName{varDecl.location, newLhs[i], m_targetDialect.defaultType}}, @@ -172,7 +172,7 @@ void WordSizeTransform::operator()(Block& _block) yulAssert(assignment.variableNames.size() == 1, ""); auto newLhs = generateU64IdentifierNames(assignment.variableNames[0].name); vector ret; - for (int i = 0; i < 3; i++) + for (size_t i = 0; i < 3; i++) ret.emplace_back(Assignment{ assignment.location, {Identifier{assignment.location, newLhs[i]}}, @@ -203,7 +203,7 @@ void WordSizeTransform::operator()(Block& _block) auto newRhs = expandValue(*assignment.value); YulString lhsName = assignment.variableNames[0].name; vector ret; - for (int i = 0; i < 4; i++) + for (size_t i = 0; i < 4; i++) ret.emplace_back(Assignment{ assignment.location, {Identifier{assignment.location, m_variableMapping.at(lhsName)[i]}}, @@ -382,7 +382,7 @@ std::vector WordSizeTransform::handleSwitch(Switch& _switch) array WordSizeTransform::generateU64IdentifierNames(YulString const& _s) { yulAssert(m_variableMapping.find(_s) == m_variableMapping.end(), ""); - for (int i = 0; i < 4; i++) + for (size_t i = 0; i < 4; i++) m_variableMapping[_s][i] = m_nameDispenser.newName(YulString{_s.str() + "_" + to_string(i)}); return m_variableMapping[_s]; } @@ -392,19 +392,20 @@ array, 4> WordSizeTransform::expandValue(Expression const array, 4> ret; if (holds_alternative(_e)) { - Identifier const& id = std::get(_e); - for (int i = 0; i < 4; i++) + auto const& id = std::get(_e); + for (size_t i = 0; i < 4; i++) ret[i] = make_unique(Identifier{id.location, m_variableMapping.at(id.name)[i]}); } else if (holds_alternative(_e)) { - Literal const& lit = std::get(_e); + auto const& lit = std::get(_e); u256 val = valueOfLiteral(lit); - for (int i = 3; i >= 0; i--) + for (size_t exprIndex = 0; exprIndex < 4; ++exprIndex) { + size_t exprIndexReverse = 3 - exprIndex; u256 currentVal = val & std::numeric_limits::max(); val >>= 64; - ret[i] = make_unique( + ret[exprIndexReverse] = make_unique( Literal{ lit.location, LiteralKind::Number, @@ -426,4 +427,3 @@ vector WordSizeTransform::expandValueToVector(Expression const& _e) ret.emplace_back(std::move(*val)); return ret; } - diff --git a/libyul/optimiser/DeadCodeEliminator.cpp b/libyul/optimiser/DeadCodeEliminator.cpp index 890161bf0..2416af514 100644 --- a/libyul/optimiser/DeadCodeEliminator.cpp +++ b/libyul/optimiser/DeadCodeEliminator.cpp @@ -51,10 +51,10 @@ void DeadCodeEliminator::operator()(Block& _block) tie(controlFlowChange, index) = TerminationFinder{m_dialect}.firstUnconditionalControlFlowChange(_block.statements); // Erase everything after the terminating statement that is not a function definition. - if (controlFlowChange != TerminationFinder::ControlFlow::FlowOut && index != size_t(-1)) + if (controlFlowChange != TerminationFinder::ControlFlow::FlowOut && index != std::numeric_limits::max()) _block.statements.erase( remove_if( - _block.statements.begin() + index + 1, + _block.statements.begin() + static_cast(index) + 1, _block.statements.end(), [] (Statement const& _s) { return !holds_alternative(_s); } ), @@ -63,4 +63,3 @@ void DeadCodeEliminator::operator()(Block& _block) ASTModifier::operator()(_block); } - diff --git a/libyul/optimiser/ExpressionJoiner.cpp b/libyul/optimiser/ExpressionJoiner.cpp index ba38fa86e..45c23dcc3 100644 --- a/libyul/optimiser/ExpressionJoiner.cpp +++ b/libyul/optimiser/ExpressionJoiner.cpp @@ -119,7 +119,7 @@ void ExpressionJoiner::decrementLatestStatementPointer() void ExpressionJoiner::resetLatestStatementPointer() { m_currentBlock = nullptr; - m_latestStatementInBlock = size_t(-1); + m_latestStatementInBlock = numeric_limits::max(); } Statement* ExpressionJoiner::latestStatement() diff --git a/libyul/optimiser/Semantics.cpp b/libyul/optimiser/Semantics.cpp index a6f41b844..f9d831b7a 100644 --- a/libyul/optimiser/Semantics.cpp +++ b/libyul/optimiser/Semantics.cpp @@ -180,7 +180,7 @@ pair TerminationFinder::firstUncondition if (controlFlow != ControlFlow::FlowOut) return {controlFlow, i}; } - return {ControlFlow::FlowOut, size_t(-1)}; + return {ControlFlow::FlowOut, numeric_limits::max()}; } TerminationFinder::ControlFlow TerminationFinder::controlFlowKind(Statement const& _statement) diff --git a/libyul/optimiser/StackCompressor.cpp b/libyul/optimiser/StackCompressor.cpp index cfb2fef82..d011c64b8 100644 --- a/libyul/optimiser/StackCompressor.cpp +++ b/libyul/optimiser/StackCompressor.cpp @@ -178,14 +178,14 @@ bool StackCompressor::run( eliminateVariables( _dialect, std::get(_object.code->statements.at(0)), - stackSurplus.at({}), + static_cast(stackSurplus.at({})), allowMSizeOptimzation ); } for (size_t i = 1; i < _object.code->statements.size(); ++i) { - FunctionDefinition& fun = std::get(_object.code->statements[i]); + auto& fun = std::get(_object.code->statements[i]); if (!stackSurplus.count(fun.name)) continue; @@ -193,7 +193,7 @@ bool StackCompressor::run( eliminateVariables( _dialect, fun, - stackSurplus.at(fun.name), + static_cast(stackSurplus.at(fun.name)), allowMSizeOptimzation ); } From 3c4e2863908cc158edf083aa570d3940430b98ca Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Tue, 9 Jun 2020 13:07:40 +0200 Subject: [PATCH 23/24] [SMTChecker] Replace wrap mod by slack vars --- libsolidity/formal/EncodingContext.cpp | 11 +++ libsolidity/formal/EncodingContext.h | 7 ++ libsolidity/formal/SMTEncoder.cpp | 69 +++++++++++++------ .../functions_recursive_indirect.sol | 1 - .../loops/for_1_false_positive.sol | 2 - ..._loop_array_assignment_storage_storage.sol | 2 - 6 files changed, 66 insertions(+), 26 deletions(-) diff --git a/libsolidity/formal/EncodingContext.cpp b/libsolidity/formal/EncodingContext.cpp index 51dd37a3d..57686ace4 100644 --- a/libsolidity/formal/EncodingContext.cpp +++ b/libsolidity/formal/EncodingContext.cpp @@ -32,12 +32,23 @@ EncodingContext::EncodingContext(): void EncodingContext::reset() { resetAllVariables(); + resetSlackId(); m_expressions.clear(); m_globalContext.clear(); m_state.reset(); m_assertions.clear(); } +void EncodingContext::resetSlackId() +{ + m_nextSlackId = 0; +} + +unsigned EncodingContext::newSlackId() +{ + return m_nextSlackId++; +} + void EncodingContext::clear() { m_variables.clear(); diff --git a/libsolidity/formal/EncodingContext.h b/libsolidity/formal/EncodingContext.h index 79f9567a5..fcfd5e149 100644 --- a/libsolidity/formal/EncodingContext.h +++ b/libsolidity/formal/EncodingContext.h @@ -40,6 +40,10 @@ public: /// alive because of state variables and inlined function calls. /// To be used in the beginning of a root function visit. void reset(); + /// Resets the fresh id for slack variables. + void resetSlackId(); + /// Returns the current fresh slack id and increments it. + unsigned newSlackId(); /// Clears the entire context, erasing everything. /// To be used before a model checking engine starts. void clear(); @@ -168,6 +172,9 @@ private: /// Whether to conjoin assertions in the assertion stack. bool m_accumulateAssertions = true; //@} + + /// Fresh ids for slack variables to be created deterministically. + unsigned m_nextSlackId = 0; }; } diff --git a/libsolidity/formal/SMTEncoder.cpp b/libsolidity/formal/SMTEncoder.cpp index 82cd75578..6faaaf600 100644 --- a/libsolidity/formal/SMTEncoder.cpp +++ b/libsolidity/formal/SMTEncoder.cpp @@ -1204,7 +1204,7 @@ pair SMTEncoder::arithmeticOperation( smtutil::Expression const& _left, smtutil::Expression const& _right, TypePointer const& _commonType, - Expression const& + Expression const& _operation ) { static set validOperators{ @@ -1227,39 +1227,66 @@ pair SMTEncoder::arithmeticOperation( else intType = TypeProvider::uint256(); - smtutil::Expression valueNoMod( - _op == Token::Add ? _left + _right : - _op == Token::Sub ? _left - _right : - _op == Token::Div ? division(_left, _right, *intType) : - _op == Token::Mul ? _left * _right : - /*_op == Token::Mod*/ _left % _right - ); + auto valueUnbounded = [&]() -> smtutil::Expression { + switch (_op) + { + case Token::Add: return _left + _right; + case Token::Sub: return _left - _right; + case Token::Mul: return _left * _right; + case Token::Div: return division(_left, _right, *intType); + case Token::Mod: return _left % _right; + default: solAssert(false, ""); + } + }(); if (_op == Token::Div || _op == Token::Mod) + { m_context.addAssertion(_right != 0); + // mod and unsigned division never underflow/overflow + if (_op == Token::Mod || !intType->isSigned()) + return {valueUnbounded, valueUnbounded}; + + // The only case where division overflows is + // - type is signed + // - LHS is type.min + // - RHS is -1 + // the result is then -(type.min), which wraps back to type.min + smtutil::Expression maxLeft = _left == smt::minValue(*intType); + smtutil::Expression minusOneRight = _right == -1; + smtutil::Expression wrap = smtutil::Expression::ite(maxLeft && minusOneRight, smt::minValue(*intType), valueUnbounded); + return {wrap, valueUnbounded}; + } + auto symbMin = smt::minValue(*intType); auto symbMax = smt::maxValue(*intType); smtutil::Expression intValueRange = (0 - symbMin) + symbMax + 1; + string suffix = to_string(_operation.id()) + "_" + to_string(m_context.newSlackId()); + smt::SymbolicIntVariable k(intType, intType, "k_" + suffix, m_context); + smt::SymbolicIntVariable m(intType, intType, "m_" + suffix, m_context); + + // To wrap around valueUnbounded in case of overflow or underflow, we replace it with a k, given: + // 1. k + m * intValueRange = valueUnbounded + // 2. k is in range of the desired integer type + auto wrap = k.currentValue(); + m_context.addAssertion(valueUnbounded == (k.currentValue() + intValueRange * m.currentValue())); + m_context.addAssertion(k.currentValue() >= symbMin); + m_context.addAssertion(k.currentValue() <= symbMax); + + // TODO this could be refined: + // for unsigned types it's enough to check only the upper bound. auto value = smtutil::Expression::ite( - valueNoMod > symbMax, - valueNoMod % intValueRange, + valueUnbounded > symbMax, + wrap, smtutil::Expression::ite( - valueNoMod < symbMin, - valueNoMod % intValueRange, - valueNoMod + valueUnbounded < symbMin, + wrap, + valueUnbounded ) ); - if (intType->isSigned()) - value = smtutil::Expression::ite( - value > symbMax, - value - intValueRange, - value - ); - - return {value, valueNoMod}; + return {value, valueUnbounded}; } void SMTEncoder::compareOperation(BinaryOperation const& _op) diff --git a/test/libsolidity/smtCheckerTests/functions/functions_recursive_indirect.sol b/test/libsolidity/smtCheckerTests/functions/functions_recursive_indirect.sol index 5d3292992..7cb7b22b1 100644 --- a/test/libsolidity/smtCheckerTests/functions/functions_recursive_indirect.sol +++ b/test/libsolidity/smtCheckerTests/functions/functions_recursive_indirect.sol @@ -22,4 +22,3 @@ contract C } } // ---- -// Warning: (130-144): Error trying to invoke SMT solver. diff --git a/test/libsolidity/smtCheckerTests/loops/for_1_false_positive.sol b/test/libsolidity/smtCheckerTests/loops/for_1_false_positive.sol index 11cd22d11..c37df70c4 100644 --- a/test/libsolidity/smtCheckerTests/loops/for_1_false_positive.sol +++ b/test/libsolidity/smtCheckerTests/loops/for_1_false_positive.sol @@ -14,6 +14,4 @@ contract C } } // ---- -// Warning: (296-309): Error trying to invoke SMT solver. // Warning: (176-181): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning: (296-309): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_storage_storage.sol b/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_storage_storage.sol index 5c664f214..a90053024 100644 --- a/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_storage_storage.sol +++ b/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_storage_storage.sol @@ -19,7 +19,5 @@ contract LoopFor2 { } } // ---- -// Warning: (317-337): Error trying to invoke SMT solver. -// Warning: (317-337): Assertion violation happens here // Warning: (341-360): Assertion violation happens here // Warning: (364-383): Assertion violation happens here From d54e7f50ed137fd3e928c86ff196a9b98a6e4650 Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Tue, 9 Jun 2020 17:30:17 +0200 Subject: [PATCH 24/24] Natspec: Output "type" and "version" in documenation --- Changelog.md | 1 + libsolidity/interface/Natspec.cpp | 6 ++++++ libsolidity/interface/Natspec.h | 2 ++ test/libsolidity/SolidityNatspecJSON.cpp | 5 +++++ test/libsolidity/StandardCompiler.cpp | 4 ++-- 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Changelog.md b/Changelog.md index a4b440529..2510afc2e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,6 +4,7 @@ Language Features: Compiler Features: + * NatSpec: Add fields "kind" and "version" to the JSON output. Bugfixes: diff --git a/libsolidity/interface/Natspec.cpp b/libsolidity/interface/Natspec.cpp index 25dcd794e..9fadd4121 100644 --- a/libsolidity/interface/Natspec.cpp +++ b/libsolidity/interface/Natspec.cpp @@ -37,6 +37,9 @@ Json::Value Natspec::userDocumentation(ContractDefinition const& _contractDef) Json::Value doc; Json::Value methods(Json::objectValue); + doc["version"] = Json::Value(c_natspecVersion); + doc["kind"] = Json::Value("user"); + auto constructorDefinition(_contractDef.constructor()); if (constructorDefinition) { @@ -87,6 +90,9 @@ Json::Value Natspec::devDocumentation(ContractDefinition const& _contractDef) Json::Value doc; Json::Value methods(Json::objectValue); + doc["version"] = Json::Value(c_natspecVersion); + doc["kind"] = Json::Value("dev"); + auto author = extractDoc(_contractDef.annotation().docTags, "author"); if (!author.empty()) doc["author"] = author; diff --git a/libsolidity/interface/Natspec.h b/libsolidity/interface/Natspec.h index fc13519e4..8d414e71a 100644 --- a/libsolidity/interface/Natspec.h +++ b/libsolidity/interface/Natspec.h @@ -40,6 +40,8 @@ struct DocTag; class Natspec { public: + static unsigned int constexpr c_natspecVersion = 1; + /// Get the User documentation of the contract /// @param _contractDef The contract definition /// @return A JSON representation of the contract's user documentation diff --git a/test/libsolidity/SolidityNatspecJSON.cpp b/test/libsolidity/SolidityNatspecJSON.cpp index fa1d2614d..06a4fc4fb 100644 --- a/test/libsolidity/SolidityNatspecJSON.cpp +++ b/test/libsolidity/SolidityNatspecJSON.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -56,6 +57,10 @@ public: generatedDocumentation = m_compilerStack.natspecDev(_contractName); Json::Value expectedDocumentation; util::jsonParseStrict(_expectedDocumentationString, expectedDocumentation); + + expectedDocumentation["version"] = Json::Value(Natspec::c_natspecVersion); + expectedDocumentation["kind"] = Json::Value(_userDocumentation ? "user" : "dev"); + BOOST_CHECK_MESSAGE( expectedDocumentation == generatedDocumentation, "Expected:\n" << expectedDocumentation.toStyledString() << diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index f8ae1d873..e4f77b581 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -354,9 +354,9 @@ BOOST_AUTO_TEST_CASE(basic_compilation) BOOST_CHECK(contract["abi"].isArray()); BOOST_CHECK_EQUAL(util::jsonCompactPrint(contract["abi"]), "[]"); BOOST_CHECK(contract["devdoc"].isObject()); - BOOST_CHECK_EQUAL(util::jsonCompactPrint(contract["devdoc"]), "{\"methods\":{}}"); + BOOST_CHECK_EQUAL(util::jsonCompactPrint(contract["devdoc"]), R"({"kind":"dev","methods":{},"version":1})"); BOOST_CHECK(contract["userdoc"].isObject()); - BOOST_CHECK_EQUAL(util::jsonCompactPrint(contract["userdoc"]), "{\"methods\":{}}"); + BOOST_CHECK_EQUAL(util::jsonCompactPrint(contract["userdoc"]), R"({"kind":"user","methods":{},"version":1})"); BOOST_CHECK(contract["evm"].isObject()); /// @TODO check evm.methodIdentifiers, legacyAssembly, bytecode, deployedBytecode BOOST_CHECK(contract["evm"]["bytecode"].isObject());