mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Equality operator allowed for external function types
This commit is contained in:
@@ -3018,8 +3018,18 @@ TypeResult FunctionType::binaryOperatorResult(Token _operator, Type const* _othe
|
||||
if (_other->category() != category() || !(_operator == Token::Equal || _operator == Token::NotEqual))
|
||||
return nullptr;
|
||||
FunctionType const& other = dynamic_cast<FunctionType const&>(*_other);
|
||||
if (kind() == Kind::Internal && other.kind() == Kind::Internal && sizeOnStack() == 1 && other.sizeOnStack() == 1)
|
||||
if (kind() == Kind::Internal && sizeOnStack() == 1 && other.kind() == Kind::Internal && other.sizeOnStack() == 1)
|
||||
return commonType(this, _other);
|
||||
else if (
|
||||
kind() == Kind::External &&
|
||||
sizeOnStack() == 2 &&
|
||||
!bound() &&
|
||||
other.kind() == Kind::External &&
|
||||
other.sizeOnStack() == 2 &&
|
||||
!other.bound()
|
||||
)
|
||||
return commonType(this, _other);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -2278,12 +2278,29 @@ void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation const& _binaryO
|
||||
|
||||
void ExpressionCompiler::appendCompareOperatorCode(Token _operator, Type const& _type)
|
||||
{
|
||||
solAssert(_type.sizeOnStack() == 1, "Comparison of multi-slot types.");
|
||||
if (_operator == Token::Equal || _operator == Token::NotEqual)
|
||||
{
|
||||
if (FunctionType const* funType = dynamic_cast<decltype(funType)>(&_type))
|
||||
FunctionType const* functionType = dynamic_cast<decltype(functionType)>(&_type);
|
||||
if (functionType && functionType->kind() == FunctionType::Kind::External)
|
||||
{
|
||||
if (funType->kind() == FunctionType::Kind::Internal)
|
||||
solUnimplementedAssert(functionType->sizeOnStack() == 2, "");
|
||||
m_context << Instruction::SWAP3;
|
||||
|
||||
m_context << ((u256(1) << 160) - 1) << Instruction::AND;
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << ((u256(1) << 160) - 1) << Instruction::AND;
|
||||
m_context << Instruction::EQ;
|
||||
m_context << Instruction::SWAP2;
|
||||
m_context << ((u256(1) << 32) - 1) << Instruction::AND;
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << ((u256(1) << 32) - 1) << Instruction::AND;
|
||||
m_context << Instruction::EQ;
|
||||
m_context << Instruction::AND;
|
||||
}
|
||||
else
|
||||
{
|
||||
solAssert(_type.sizeOnStack() == 1, "Comparison of multi-slot types.");
|
||||
if (functionType && functionType->kind() == FunctionType::Kind::Internal)
|
||||
{
|
||||
// We have to remove the upper bits (construction time value) because they might
|
||||
// be "unknown" in one of the operands and not in the other.
|
||||
@@ -2291,13 +2308,14 @@ void ExpressionCompiler::appendCompareOperatorCode(Token _operator, Type const&
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context << ((u256(1) << 32) - 1) << Instruction::AND;
|
||||
}
|
||||
m_context << Instruction::EQ;
|
||||
}
|
||||
m_context << Instruction::EQ;
|
||||
if (_operator == Token::NotEqual)
|
||||
m_context << Instruction::ISZERO;
|
||||
}
|
||||
else
|
||||
{
|
||||
solAssert(_type.sizeOnStack() == 1, "Comparison of multi-slot types.");
|
||||
bool isSigned = false;
|
||||
if (auto type = dynamic_cast<IntegerType const*>(&_type))
|
||||
isSigned = type->isSigned();
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <libsolutil/FunctionSelector.h>
|
||||
#include <libsolutil/Whiskers.h>
|
||||
#include <libsolutil/StringUtils.h>
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
@@ -4548,3 +4549,31 @@ string YulUtilFunctions::externalCodeFunction()
|
||||
.render();
|
||||
});
|
||||
}
|
||||
|
||||
std::string YulUtilFunctions::externalFunctionPointersEqualFunction()
|
||||
{
|
||||
std::string const functionName = "externalFunctionPointersEqualFunction";
|
||||
return m_functionCollector.createFunction(functionName, [&]() {
|
||||
return util::Whiskers(R"(
|
||||
function <functionName>(
|
||||
leftAddress,
|
||||
leftSelector,
|
||||
rightAddress,
|
||||
rightSelector
|
||||
) -> result {
|
||||
result := and(
|
||||
eq(
|
||||
<addressCleanUpFunction>(leftAddress), <addressCleanUpFunction>(rightAddress)
|
||||
),
|
||||
eq(
|
||||
<selectorCleanUpFunction>(leftSelector), <selectorCleanUpFunction>(rightSelector)
|
||||
)
|
||||
)
|
||||
}
|
||||
)")
|
||||
("functionName", functionName)
|
||||
("addressCleanUpFunction", cleanupFunction(*TypeProvider::address()))
|
||||
("selectorCleanUpFunction", cleanupFunction(*TypeProvider::uint(32)))
|
||||
.render();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -522,6 +522,9 @@ public:
|
||||
/// Signature: (address) -> mpos
|
||||
std::string externalCodeFunction();
|
||||
|
||||
/// @return the name of a function that that checks if two external functions pointers are equal or not
|
||||
std::string externalFunctionPointersEqualFunction();
|
||||
|
||||
private:
|
||||
/// @returns the name of a function that copies a struct from calldata or memory to storage
|
||||
/// signature: (slot, value) ->
|
||||
|
||||
@@ -799,13 +799,8 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
|
||||
|
||||
if (TokenTraits::isCompareOp(op))
|
||||
{
|
||||
if (auto type = dynamic_cast<FunctionType const*>(commonType))
|
||||
{
|
||||
solAssert(op == Token::Equal || op == Token::NotEqual, "Invalid function pointer comparison!");
|
||||
solAssert(type->kind() != FunctionType::Kind::External, "External function comparison not allowed!");
|
||||
}
|
||||
|
||||
solAssert(commonType->isValueType(), "");
|
||||
|
||||
bool isSigned = false;
|
||||
if (auto type = dynamic_cast<IntegerType const*>(commonType))
|
||||
isSigned = type->isSigned();
|
||||
@@ -813,8 +808,25 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
|
||||
string args = expressionAsType(_binOp.leftExpression(), *commonType, true);
|
||||
args += ", " + expressionAsType(_binOp.rightExpression(), *commonType, true);
|
||||
|
||||
auto functionType = dynamic_cast<FunctionType const*>(commonType);
|
||||
solAssert(functionType ? (op == Token::Equal || op == Token::NotEqual) : true, "Invalid function pointer comparison!");
|
||||
|
||||
string expr;
|
||||
if (op == Token::Equal)
|
||||
|
||||
if (functionType && functionType->kind() == FunctionType::Kind::External)
|
||||
{
|
||||
solUnimplementedAssert(functionType->sizeOnStack() == 2, "");
|
||||
expr = m_utils.externalFunctionPointersEqualFunction() +
|
||||
"(" +
|
||||
IRVariable{_binOp.leftExpression()}.part("address").name() + "," +
|
||||
IRVariable{_binOp.leftExpression()}.part("functionSelector").name() + "," +
|
||||
IRVariable{_binOp.rightExpression()}.part("address").name() + "," +
|
||||
IRVariable{_binOp.rightExpression()}.part("functionSelector").name() +
|
||||
")";
|
||||
if (op == Token::NotEqual)
|
||||
expr = "iszero(" + expr + ")";
|
||||
}
|
||||
else if (op == Token::Equal)
|
||||
expr = "eq(" + move(args) + ")";
|
||||
else if (op == Token::NotEqual)
|
||||
expr = "iszero(eq(" + move(args) + "))";
|
||||
|
||||
Reference in New Issue
Block a user