diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index 0951aa250b..8ef43c0900 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -275,6 +275,13 @@ struct FunctionCallAnnotation: ExpressionAnnotation FunctionCallKind kind = FunctionCallKind::Unset; /// If true, this is the external call of a try statement. bool tryCall = false; + + // HACK! + // We track the success tag here for the `TryStatement` lowering. This is to avoid the redundant status check and + // the conditional jump. Such patterns can confuse the zksolc translator. + // + // uint32_t since Assembly::new[Push]Tag() asserts that the tag is 32 bits. + std::optional tryCallSuccessTag; }; } diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index 76f9a0625a..886896a962 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -341,11 +341,6 @@ class CompilerContext RevertStrings revertStrings() const { return m_revertStrings; } - // HACK! - // We track the success tag here for the `TryStatement` lowering. This is to avoid the redundant status check and - // the conditional jump. Such patterns can confuse the zksolc translator. - evmasm::AssemblyItem currTryCallSuccessTag{evmasm::AssemblyItemType::UndefinedItem}; - private: /// Searches the inheritance hierarchy towards the base starting from @a _searchStart and returns /// the first function definition that is overwritten by _function. diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 7e4aed1301..db7c0f5c58 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -897,7 +897,10 @@ bool ContractCompiler::visit(TryStatement const& _tryStatement) StackHeightChecker checker(m_context); CompilerContext::LocationSetter locationSetter(m_context, _tryStatement); - compileExpression(_tryStatement.externalCall()); + auto* externalCall = dynamic_cast(&_tryStatement.externalCall()); + solAssert(externalCall && externalCall->annotation().tryCall, ""); + compileExpression(*externalCall); + int const returnSize = static_cast(_tryStatement.externalCall().annotation().type->sizeOnStack()); // Stack: [ return values] @@ -910,8 +913,11 @@ bool ContractCompiler::visit(TryStatement const& _tryStatement) evmasm::AssemblyItem endTag = m_context.appendJumpToNew(); - solAssert(m_context.currTryCallSuccessTag.type() == AssemblyItemType::Tag, ""); - m_context << m_context.currTryCallSuccessTag; + auto& successTag = externalCall->annotation().tryCallSuccessTag; + solAssert(successTag, ""); + m_context << AssemblyItem(AssemblyItemType::Tag, *successTag); + successTag.reset(); + m_context.adjustStackOffset(returnSize); { // Success case. diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index ff280d2377..111ad048a9 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -688,7 +688,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) case FunctionType::Kind::External: case FunctionType::Kind::DelegateCall: _functionCall.expression().accept(*this); - appendExternalFunctionCall(function, arguments, _functionCall.annotation().tryCall); + appendExternalFunctionCall( + function, arguments, _functionCall.annotation().tryCall, &_functionCall.annotation()); break; case FunctionType::Kind::BareCallCode: solAssert(false, "Callcode has been removed."); @@ -748,7 +749,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) // If this is a try call, return "
1" in the success case and // "0" in the error case. AssemblyItem errorCase = m_context.appendConditionalJump(); - m_context.currTryCallSuccessTag = m_context.appendJumpToNew(); + _functionCall.annotation().tryCallSuccessTag + = m_context.appendJumpToNew().data().convert_to(); m_context.adjustStackOffset(1); m_context << errorCase; } @@ -2210,7 +2212,8 @@ void ExpressionCompiler::appendShiftOperatorCode(Token _operator, Type const& _v void ExpressionCompiler::appendExternalFunctionCall( FunctionType const& _functionType, vector> const& _arguments, - bool _tryCall + bool _tryCall, + FunctionCallAnnotation* _annotation ) { solAssert( @@ -2507,8 +2510,9 @@ void ExpressionCompiler::appendExternalFunctionCall( if (_tryCall) { + solAssert(_annotation, ""); // Success branch will reach this, failure branch will directly jump to endTag. - m_context.currTryCallSuccessTag = m_context.appendJumpToNew(); + _annotation->tryCallSuccessTag = m_context.appendJumpToNew().data().convert_to(); m_context.adjustStackOffset(1); m_context << endTag; } diff --git a/libsolidity/codegen/ExpressionCompiler.h b/libsolidity/codegen/ExpressionCompiler.h index 80ed9cf8b6..d4fefdc896 100644 --- a/libsolidity/codegen/ExpressionCompiler.h +++ b/libsolidity/codegen/ExpressionCompiler.h @@ -108,7 +108,8 @@ class ExpressionCompiler: private ASTConstVisitor void appendExternalFunctionCall( FunctionType const& _functionType, std::vector> const& _arguments, - bool _tryCall + bool _tryCall, + FunctionCallAnnotation* _annotation = nullptr ); /// Appends code that evaluates a single expression and moves the result to memory. The memory offset is /// expected to be on the stack and is updated by this call.