From 17fc0f54b5dbf6b49e0500e3fca7b681316071f6 Mon Sep 17 00:00:00 2001 From: chriseth Date: Sat, 30 Dec 2017 13:44:09 +0100 Subject: Use FunctionTypePointer (adds ``const``). --- libsolidity/ast/AST.cpp | 7 ++++--- libsolidity/ast/AST.h | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'libsolidity') diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index d8ad009d..80f5d642 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -297,7 +297,7 @@ ContractDefinition::ContractKind FunctionDefinition::inContractKind() const return contractDef->contractKind(); } -shared_ptr FunctionDefinition::functionType(bool _internal) const +FunctionTypePointer FunctionDefinition::functionType(bool _internal) const { if (_internal) { @@ -338,6 +338,7 @@ shared_ptr FunctionDefinition::functionType(bool _internal) const TypePointer FunctionDefinition::type() const { + solAssert(visibility() != Declaration::Visibility::External, ""); return make_shared(*this); } @@ -379,7 +380,7 @@ TypePointer EventDefinition::type() const return make_shared(*this); } -std::shared_ptr EventDefinition::functionType(bool _internal) const +FunctionTypePointer EventDefinition::functionType(bool _internal) const { if (_internal) return make_shared(*this); @@ -484,7 +485,7 @@ TypePointer VariableDeclaration::type() const return annotation().type; } -shared_ptr VariableDeclaration::functionType(bool _internal) const +FunctionTypePointer VariableDeclaration::functionType(bool _internal) const { if (_internal) return {}; diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index ae253f0c..b648e08b 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -218,7 +218,7 @@ public: /// @param _internal false indicates external interface is concerned, true indicates internal interface is concerned. /// @returns null when it is not accessible as a function. - virtual std::shared_ptr functionType(bool /*_internal*/) const { return {}; } + virtual FunctionTypePointer functionType(bool /*_internal*/) const { return {}; } protected: virtual Visibility defaultVisibility() const { return Visibility::Public; } @@ -634,7 +634,7 @@ public: /// @param _internal false indicates external interface is concerned, true indicates internal interface is concerned. /// @returns null when it is not accessible as a function. - virtual std::shared_ptr functionType(bool /*_internal*/) const override; + virtual FunctionTypePointer functionType(bool /*_internal*/) const override; virtual FunctionDefinitionAnnotation& annotation() const override; @@ -703,7 +703,7 @@ public: /// @param _internal false indicates external interface is concerned, true indicates internal interface is concerned. /// @returns null when it is not accessible as a function. - virtual std::shared_ptr functionType(bool /*_internal*/) const override; + virtual FunctionTypePointer functionType(bool /*_internal*/) const override; virtual VariableDeclarationAnnotation& annotation() const override; @@ -805,7 +805,7 @@ public: bool isAnonymous() const { return m_anonymous; } virtual TypePointer type() const override; - virtual std::shared_ptr functionType(bool /*_internal*/) const override; + virtual FunctionTypePointer functionType(bool /*_internal*/) const override; virtual EventDefinitionAnnotation& annotation() const override; -- cgit v1.2.3 From f00bb4359375cd03e9ff6373b5efa41a37ce2876 Mon Sep 17 00:00:00 2001 From: chriseth Date: Sat, 30 Dec 2017 13:46:53 +0100 Subject: Allow function overloads involving MagicVariableDeclarations. --- libsolidity/analysis/DeclarationContainer.cpp | 8 +++++++- libsolidity/analysis/NameAndTypeResolver.cpp | 5 +++-- libsolidity/analysis/TypeChecker.cpp | 7 +++---- libsolidity/ast/AST.h | 5 +++++ 4 files changed, 18 insertions(+), 7 deletions(-) (limited to 'libsolidity') diff --git a/libsolidity/analysis/DeclarationContainer.cpp b/libsolidity/analysis/DeclarationContainer.cpp index c7ba78d6..786272e4 100644 --- a/libsolidity/analysis/DeclarationContainer.cpp +++ b/libsolidity/analysis/DeclarationContainer.cpp @@ -45,7 +45,8 @@ Declaration const* DeclarationContainer::conflictingDeclaration( if ( dynamic_cast(&_declaration) || - dynamic_cast(&_declaration) + dynamic_cast(&_declaration) || + dynamic_cast(&_declaration) ) { // check that all other declarations with the same name are functions or a public state variable or events. @@ -68,6 +69,11 @@ Declaration const* DeclarationContainer::conflictingDeclaration( !dynamic_cast(declaration) ) return declaration; + if ( + dynamic_cast(&_declaration) && + !dynamic_cast(declaration) + ) + return declaration; // Or, continue. } } diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index 2f675135..5f9e0e99 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -202,8 +202,9 @@ vector NameAndTypeResolver::cleanedDeclarations( solAssert( dynamic_cast(declaration) || dynamic_cast(declaration) || - dynamic_cast(declaration), - "Found overloading involving something not a function or a variable." + dynamic_cast(declaration) || + dynamic_cast(declaration), + "Found overloading involving something not a function, event or a (magic) variable." ); FunctionTypePointer functionType { declaration->functionType(false) }; diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 8b57fc15..4b1ef55b 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -2124,10 +2124,9 @@ bool TypeChecker::visit(Identifier const& _identifier) for (Declaration const* declaration: annotation.overloadedDeclarations) { - TypePointer function = declaration->type(); - solAssert(!!function, "Requested type not present."); - auto const* functionType = dynamic_cast(function.get()); - if (functionType && functionType->canTakeArguments(*annotation.argumentTypes)) + FunctionTypePointer functionType = declaration->functionType(true); + solAssert(!!functionType, "Requested type not present."); + if (functionType->canTakeArguments(*annotation.argumentTypes)) candidates.push_back(declaration); } if (candidates.empty()) diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index b648e08b..a53987bf 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -831,6 +831,11 @@ public: solAssert(false, "MagicVariableDeclaration used inside real AST."); } + virtual FunctionTypePointer functionType(bool) const override + { + solAssert(m_type->category() == Type::Category::Function, ""); + return std::dynamic_pointer_cast(m_type); + } virtual TypePointer type() const override { return m_type; } private: -- cgit v1.2.3 From 8ab7dc036aafd5781118fc16f05df5b0a8a5550e Mon Sep 17 00:00:00 2001 From: chriseth Date: Sat, 30 Dec 2017 13:47:15 +0100 Subject: Register overload for ``revert()`` that can receive a reason string. --- libsolidity/analysis/GlobalContext.cpp | 1 + libsolidity/analysis/NameAndTypeResolver.cpp | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'libsolidity') diff --git a/libsolidity/analysis/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp index 6a858d36..822674af 100644 --- a/libsolidity/analysis/GlobalContext.cpp +++ b/libsolidity/analysis/GlobalContext.cpp @@ -52,6 +52,7 @@ m_magicVariables(vector>{ make_shared("now", make_shared(256)), make_shared("require", make_shared(strings{"bool"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)), make_shared("revert", make_shared(strings(), strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)), + make_shared("revert", make_shared(strings{"string memory"}, strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)), make_shared("ripemd160", make_shared(strings(), strings{"bytes20"}, FunctionType::Kind::RIPEMD160, true, StateMutability::Pure)), make_shared("selfdestruct", make_shared(strings{"address"}, strings{}, FunctionType::Kind::Selfdestruct)), make_shared("sha256", make_shared(strings(), strings{"bytes32"}, FunctionType::Kind::SHA256, true, StateMutability::Pure)), diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index 5f9e0e99..0a356f04 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -47,7 +47,9 @@ NameAndTypeResolver::NameAndTypeResolver( if (!m_scopes[nullptr]) m_scopes[nullptr].reset(new DeclarationContainer()); for (Declaration const* declaration: _globals) - m_scopes[nullptr]->registerDeclaration(*declaration); + { + solAssert(m_scopes[nullptr]->registerDeclaration(*declaration), "Unable to register global declaration."); + } } bool NameAndTypeResolver::registerDeclarations(SourceUnit& _sourceUnit, ASTNode const* _currentScope) -- cgit v1.2.3 From 012ab37fe3984a692dcdda6ef516e4588a8721b3 Mon Sep 17 00:00:00 2001 From: chriseth Date: Sat, 30 Dec 2017 13:47:51 +0100 Subject: Code generator for revert with reason string. --- libsolidity/codegen/ExpressionCompiler.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'libsolidity') diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 57d49ac6..dc9fae21 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -680,8 +680,25 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) m_context << Instruction::SELFDESTRUCT; break; case FunctionType::Kind::Revert: - m_context.appendRevert(); + { + if (!arguments.empty()) + { + solAssert(arguments.size() == 1, ""); + solAssert(function.parameterTypes().size() == 1, ""); + m_context << u256(0); + arguments.front()->accept(*this); + utils().fetchFreeMemoryPointer(); + utils().abiEncode( + {make_shared(256), arguments.front()->annotation().type}, + {make_shared(256), make_shared(DataLocation::Memory, true)} + ); + utils().toSizeAfterFreeMemoryPointer(); + m_context << Instruction::REVERT; + } + else + m_context.appendRevert(); break; + } case FunctionType::Kind::SHA3: { TypePointers argumentTypes; -- cgit v1.2.3 From ae1d040285d97c2be0eb9d3e94a983975459f879 Mon Sep 17 00:00:00 2001 From: chriseth Date: Sat, 30 Dec 2017 14:35:45 +0100 Subject: Allow error string for ``require``. --- libsolidity/analysis/GlobalContext.cpp | 1 + libsolidity/codegen/ExpressionCompiler.cpp | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) (limited to 'libsolidity') diff --git a/libsolidity/analysis/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp index 822674af..c58d99fb 100644 --- a/libsolidity/analysis/GlobalContext.cpp +++ b/libsolidity/analysis/GlobalContext.cpp @@ -51,6 +51,7 @@ m_magicVariables(vector>{ make_shared("mulmod", make_shared(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::MulMod, false, StateMutability::Pure)), make_shared("now", make_shared(256)), make_shared("require", make_shared(strings{"bool"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)), + make_shared("require", make_shared(strings{"bool", "string memory"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)), make_shared("revert", make_shared(strings(), strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)), make_shared("revert", make_shared(strings{"string memory"}, strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)), make_shared("ripemd160", make_shared(strings(), strings{"bytes20"}, FunctionType::Kind::RIPEMD160, true, StateMutability::Pure)), diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index dc9fae21..cb92b030 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -917,16 +917,42 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) { arguments.front()->accept(*this); utils().convertType(*arguments.front()->annotation().type, *function.parameterTypes().front(), false); + if (arguments.size() > 1) + { + // Users probably expect the second argument to be evaluated + // even if the condition is false, as would be the case for an actual + // function call. + solAssert(arguments.size() == 2, ""); + solAssert(function.kind() == FunctionType::Kind::Require, ""); + arguments.at(1)->accept(*this); + utils().moveIntoStack(1, arguments.at(1)->annotation().type->sizeOnStack()); + } + // Stack: // jump if condition was met m_context << Instruction::ISZERO << Instruction::ISZERO; auto success = m_context.appendConditionalJump(); if (function.kind() == FunctionType::Kind::Assert) // condition was not met, flag an error m_context.appendInvalid(); + else if (arguments.size() > 1) + { + m_context << u256(0); + utils().moveIntoStack(arguments.at(1)->annotation().type->sizeOnStack(), 1); + utils().fetchFreeMemoryPointer(); + utils().abiEncode( + {make_shared(256), arguments.at(1)->annotation().type}, + {make_shared(256), make_shared(DataLocation::Memory, true)} + ); + utils().toSizeAfterFreeMemoryPointer(); + m_context << Instruction::REVERT; + m_context.adjustStackOffset(arguments.at(1)->annotation().type->sizeOnStack()); + } else m_context.appendRevert(); // the success branch m_context << success; + if (arguments.size() > 1) + utils().popStackElement(*arguments.at(1)->annotation().type); break; } case FunctionType::Kind::GasLeft: -- cgit v1.2.3 From 7a9ee69e986cf58c8b2a6cabec2c59b0eb2fbb57 Mon Sep 17 00:00:00 2001 From: chriseth Date: Sat, 30 Dec 2017 20:13:41 +0100 Subject: Bubble up error messages. --- libsolidity/codegen/CompilerContext.cpp | 20 ++++++++++++++------ libsolidity/codegen/CompilerContext.h | 5 +++-- libsolidity/codegen/CompilerUtils.cpp | 1 + libsolidity/codegen/ContractCompiler.cpp | 2 ++ libsolidity/codegen/ExpressionCompiler.cpp | 9 ++++++--- 5 files changed, 26 insertions(+), 11 deletions(-) (limited to 'libsolidity') diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 47333046..2cd256f3 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -262,12 +262,20 @@ CompilerContext& CompilerContext::appendRevert() return *this << u256(0) << u256(0) << Instruction::REVERT; } -CompilerContext& CompilerContext::appendConditionalRevert() -{ - *this << Instruction::ISZERO; - eth::AssemblyItem afterTag = appendConditionalJump(); - appendRevert(); - *this << afterTag; +CompilerContext& CompilerContext::appendConditionalRevert(bool _forwardReturnData) +{ + if (_forwardReturnData) + appendInlineAssembly(R"({ + if condition { + returndatacopy(0, 0, returndatasize()) + revert(0, returndatasize()) + } + })", {"condition"}); + else + appendInlineAssembly(R"({ + if condition { revert(0, 0) } + })", {"condition"}); + *this << Instruction::POP; return *this; } diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index 7b663277..c6f2f3be 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -156,8 +156,9 @@ public: CompilerContext& appendConditionalInvalid(); /// Appends a REVERT(0, 0) call CompilerContext& appendRevert(); - /// Appends a conditional REVERT(0, 0) call - CompilerContext& appendConditionalRevert(); + /// Appends a conditional REVERT-call, either forwarding the RETURNDATA or providing the + /// empty string. Consumes the condition. + CompilerContext& appendConditionalRevert(bool _forwardReturnData = false); /// Appends a JUMP to a specific tag CompilerContext& appendJumpTo(eth::AssemblyItem const& _tag) { m_asm->appendJump(_tag); return *this; } /// Appends pushing of a new tag and @returns the new tag. diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 79aef7b0..34337d7d 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -691,6 +691,7 @@ void CompilerUtils::convertType( solAssert(enumType.numberOfMembers() > 0, "empty enum should have caused a parser error."); m_context << u256(enumType.numberOfMembers() - 1) << Instruction::DUP2 << Instruction::GT; if (_asPartOfArgumentDecoding) + // TODO: error message? m_context.appendConditionalRevert(); else m_context.appendConditionalInvalid(); diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 5cb37103..0889ac7c 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -128,6 +128,7 @@ void ContractCompiler::appendCallValueCheck() { // Throw if function is not payable but call contained ether. m_context << Instruction::CALLVALUE; + // TODO: error message? m_context.appendConditionalRevert(); } @@ -327,6 +328,7 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac m_context << Instruction::STOP; } else + // TODO: error message here? m_context.appendRevert(); for (auto const& it: interfaceFunctions) diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index cb92b030..3f521f2d 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -608,7 +608,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) m_context << Instruction::CREATE; // Check if zero (out of stack or not enough balance). m_context << Instruction::DUP1 << Instruction::ISZERO; - m_context.appendConditionalRevert(); + // TODO: Can we bubble up here? There might be different reasons for failure, I think. + m_context.appendConditionalRevert(true); if (function.valueSet()) m_context << swapInstruction(1) << Instruction::POP; break; @@ -670,8 +671,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) if (function.kind() == FunctionType::Kind::Transfer) { // Check if zero (out of stack or not enough balance). + // TODO: bubble up here, but might also be different error. m_context << Instruction::ISZERO; - m_context.appendConditionalRevert(); + m_context.appendConditionalRevert(true); } break; case FunctionType::Kind::Selfdestruct: @@ -1823,6 +1825,7 @@ void ExpressionCompiler::appendExternalFunctionCall( if (funKind == FunctionType::Kind::External || funKind == FunctionType::Kind::CallCode || funKind == FunctionType::Kind::DelegateCall) { m_context << Instruction::DUP1 << Instruction::EXTCODESIZE << Instruction::ISZERO; + // TODO: error message? m_context.appendConditionalRevert(); existenceChecked = true; } @@ -1865,7 +1868,7 @@ void ExpressionCompiler::appendExternalFunctionCall( { //Propagate error condition (if CALL pushes 0 on stack). m_context << Instruction::ISZERO; - m_context.appendConditionalRevert(); + m_context.appendConditionalRevert(true); } utils().popStackSlots(remainsSize); -- cgit v1.2.3 From fcb7a2721636a9a2f05659610fc05fa8513f745d Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 2 Mar 2018 17:26:16 +0100 Subject: Only forward returndata if EVM version supports it. --- libsolidity/codegen/CompilerContext.cpp | 2 +- libsolidity/codegen/CompilerContext.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'libsolidity') diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 2cd256f3..a35eea73 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -264,7 +264,7 @@ CompilerContext& CompilerContext::appendRevert() CompilerContext& CompilerContext::appendConditionalRevert(bool _forwardReturnData) { - if (_forwardReturnData) + if (_forwardReturnData && m_evmVersion.supportsReturndata()) appendInlineAssembly(R"({ if condition { returndatacopy(0, 0, returndatasize()) diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index c6f2f3be..098472f7 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -158,6 +158,8 @@ public: CompilerContext& appendRevert(); /// Appends a conditional REVERT-call, either forwarding the RETURNDATA or providing the /// empty string. Consumes the condition. + /// If the current EVM version does not support RETURNDATA, uses REVERT but does not forward + /// the data. CompilerContext& appendConditionalRevert(bool _forwardReturnData = false); /// Appends a JUMP to a specific tag CompilerContext& appendJumpTo(eth::AssemblyItem const& _tag) { m_asm->appendJump(_tag); return *this; } -- cgit v1.2.3 From 4faa839813ce76fc87f99b002aad6cadd2b784e1 Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 6 Apr 2018 15:14:55 +0200 Subject: Use error signature for revert data. --- libsolidity/codegen/CompilerUtils.cpp | 14 ++++++++++++++ libsolidity/codegen/CompilerUtils.h | 7 +++++++ libsolidity/codegen/ExpressionCompiler.cpp | 23 +++-------------------- 3 files changed, 24 insertions(+), 20 deletions(-) (limited to 'libsolidity') diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 34337d7d..b4550153 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -78,6 +78,20 @@ void CompilerUtils::toSizeAfterFreeMemoryPointer() m_context << Instruction::SWAP1; } +void CompilerUtils::revertWithStringData(Type const& _argumentType) +{ + solAssert(_argumentType.isImplicitlyConvertibleTo(*Type::fromElementaryTypeName("string memory")), ""); + fetchFreeMemoryPointer(); + m_context << (u256(FixedHash<4>::Arith(FixedHash<4>(dev::keccak256("Error(string)")))) << (256 - 32)); + m_context << Instruction::DUP2 << Instruction::MSTORE; + m_context << u256(4) << Instruction::ADD; + // Stack: + abiEncode({_argumentType.shared_from_this()}, {make_shared(DataLocation::Memory, true)}); + toSizeAfterFreeMemoryPointer(); + m_context << Instruction::REVERT; + m_context.adjustStackOffset(_argumentType.sizeOnStack()); +} + unsigned CompilerUtils::loadFromMemory( unsigned _offset, Type const& _type, diff --git a/libsolidity/codegen/CompilerUtils.h b/libsolidity/codegen/CompilerUtils.h index a32c5c6e..476a7559 100644 --- a/libsolidity/codegen/CompilerUtils.h +++ b/libsolidity/codegen/CompilerUtils.h @@ -54,6 +54,13 @@ public: /// Stack post: void toSizeAfterFreeMemoryPointer(); + /// Appends code that performs a revert, providing the given string data. + /// Will also append an error signature corresponding to Error(string). + /// @param _argumentType the type of the string argument, will be converted to memory string. + /// Stack pre: string data + /// Stack post: + void revertWithStringData(Type const& _argumentType); + /// Loads data from memory to the stack. /// @param _offset offset in memory (or calldata) /// @param _type data type to load diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 3f521f2d..b67e7b68 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -685,17 +685,11 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) { if (!arguments.empty()) { + // function-sel(Error(string)) + encoding solAssert(arguments.size() == 1, ""); solAssert(function.parameterTypes().size() == 1, ""); - m_context << u256(0); arguments.front()->accept(*this); - utils().fetchFreeMemoryPointer(); - utils().abiEncode( - {make_shared(256), arguments.front()->annotation().type}, - {make_shared(256), make_shared(DataLocation::Memory, true)} - ); - utils().toSizeAfterFreeMemoryPointer(); - m_context << Instruction::REVERT; + utils().revertWithStringData(*arguments.front()->annotation().type); } else m_context.appendRevert(); @@ -937,18 +931,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) // condition was not met, flag an error m_context.appendInvalid(); else if (arguments.size() > 1) - { - m_context << u256(0); - utils().moveIntoStack(arguments.at(1)->annotation().type->sizeOnStack(), 1); - utils().fetchFreeMemoryPointer(); - utils().abiEncode( - {make_shared(256), arguments.at(1)->annotation().type}, - {make_shared(256), make_shared(DataLocation::Memory, true)} - ); - utils().toSizeAfterFreeMemoryPointer(); - m_context << Instruction::REVERT; - m_context.adjustStackOffset(arguments.at(1)->annotation().type->sizeOnStack()); - } + utils().revertWithStringData(*arguments.at(1)->annotation().type); else m_context.appendRevert(); // the success branch -- cgit v1.2.3