diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index cc25612544..d35463ce6e 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -331,6 +331,13 @@ struct FunctionCallAnnotation: ExpressionAnnotation util::SetOnce kind; /// 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 b271c1342c..e8499c031b 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -349,11 +349,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: /// Updates source location set in the assembly. void updateSourceLocation(); diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 992b95414f..5d761b2d78 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -1019,7 +1019,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] @@ -1032,8 +1035,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 ca728783c7..ed00f06c02 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -761,7 +761,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."); @@ -821,7 +822,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; } @@ -2615,7 +2617,8 @@ void ExpressionCompiler::appendExpOperatorCode(Type const& _valueType, Type cons void ExpressionCompiler::appendExternalFunctionCall( FunctionType const& _functionType, vector> const& _arguments, - bool _tryCall + bool _tryCall, + FunctionCallAnnotation* _annotation ) { solAssert( @@ -2905,8 +2908,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 cfa36de4bc..0ba13f8258 100644 --- a/libsolidity/codegen/ExpressionCompiler.h +++ b/libsolidity/codegen/ExpressionCompiler.h @@ -110,7 +110,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.