| 1013 | } |
| 1014 | |
| 1015 | void ContractCompiler::handleCatch(std::vector<ASTPointer<TryCatchClause>> const& _catchClauses) |
| 1016 | { |
| 1017 | // Stack is empty. |
| 1018 | ASTPointer<TryCatchClause> error{}; |
| 1019 | ASTPointer<TryCatchClause> panic{}; |
| 1020 | ASTPointer<TryCatchClause> fallback{}; |
| 1021 | for (size_t i = 1; i < _catchClauses.size(); ++i) |
| 1022 | if (_catchClauses[i]->errorName() == "Error") |
| 1023 | error = _catchClauses[i]; |
| 1024 | else if (_catchClauses[i]->errorName() == "Panic") |
| 1025 | panic = _catchClauses[i]; |
| 1026 | else if (_catchClauses[i]->errorName().empty()) |
| 1027 | fallback = _catchClauses[i]; |
| 1028 | else |
| 1029 | solAssert(false, ""); |
| 1030 | |
| 1031 | solAssert(_catchClauses.size() == 1ul + (error ? 1 : 0) + (panic ? 1 : 0) + (fallback ? 1 : 0), ""); |
| 1032 | |
| 1033 | evmasm::AssemblyItem endTag = m_context.newTag(); |
| 1034 | evmasm::AssemblyItem fallbackTag = m_context.newTag(); |
| 1035 | evmasm::AssemblyItem panicTag = m_context.newTag(); |
| 1036 | if (error || panic) |
| 1037 | // Note that this function returns zero on failure, which is not a problem yet, |
| 1038 | // but will be a problem once we allow user-defined errors. |
| 1039 | m_context.callYulFunction(m_context.utilFunctions().returnDataSelectorFunction(), 0, 1); |
| 1040 | // stack: <selector> |
| 1041 | if (error) |
| 1042 | { |
| 1043 | solAssert( |
| 1044 | error->parameters() && |
| 1045 | error->parameters()->parameters().size() == 1 && |
| 1046 | error->parameters()->parameters().front() && |
| 1047 | *error->parameters()->parameters().front()->annotation().type == *TypeProvider::stringMemory(), |
| 1048 | "" |
| 1049 | ); |
| 1050 | solAssert(m_context.evmVersion().supportsReturndata(), ""); |
| 1051 | |
| 1052 | // stack: <selector> |
| 1053 | m_context << Instruction::DUP1 << util::selectorFromSignatureU32("Error(string)") << Instruction::EQ; |
| 1054 | m_context << Instruction::ISZERO; |
| 1055 | m_context.appendConditionalJumpTo(panicTag); |
| 1056 | m_context << Instruction::POP; // remove selector |
| 1057 | |
| 1058 | // Try to decode the error message. |
| 1059 | // If this fails, leaves 0 on the stack, otherwise the pointer to the data string. |
| 1060 | m_context.callYulFunction(m_context.utilFunctions().tryDecodeErrorMessageFunction(), 0, 1); |
| 1061 | m_context << Instruction::DUP1; |
| 1062 | AssemblyItem decodeSuccessTag = m_context.appendConditionalJump(); |
| 1063 | m_context << Instruction::POP; |
| 1064 | m_context.appendJumpTo(fallbackTag); |
| 1065 | m_context.adjustStackOffset(1); |
| 1066 | |
| 1067 | m_context << decodeSuccessTag; |
| 1068 | error->accept(*this); |
| 1069 | m_context.appendJumpTo(endTag); |
| 1070 | m_context.adjustStackOffset(1); |
| 1071 | } |
| 1072 | m_context << panicTag; |
nothing calls this directly
no test coverage detected