[Sol -> Yul] Implement delete for function pointers

This commit is contained in:
Mathias Baumann 2019-05-22 12:25:00 +02:00
parent 81702717b0
commit 981983089c
8 changed files with 89 additions and 6 deletions

View File

@ -1138,6 +1138,25 @@ string YulUtilFunctions::negateNumberCheckedFunction(Type const& _type)
}); });
} }
string YulUtilFunctions::zeroValueFunction(Type const& _type)
{
solUnimplementedAssert(_type.sizeOnStack() == 1, "Stacksize not yet implemented!");
solUnimplementedAssert(_type.isValueType(), "Zero value for non-value types not yet implemented");
string const functionName = "zero_value_for_" + _type.identifier();
return m_functionCollector->createFunction(functionName, [&]() {
return Whiskers(R"(
function <functionName>() -> ret {
<body>
}
)")
("functionName", functionName)
("body", "ret := 0x0")
.render();
});
}
string YulUtilFunctions::conversionFunctionSpecial(Type const& _from, Type const& _to) string YulUtilFunctions::conversionFunctionSpecial(Type const& _from, Type const& _to)
{ {
string functionName = string functionName =

View File

@ -183,6 +183,9 @@ public:
std::string negateNumberCheckedFunction(Type const& _type); std::string negateNumberCheckedFunction(Type const& _type);
/// @returns the name of a function that returns the zero value for the
/// provided type
std::string zeroValueFunction(Type const& _type);
private: private:
/// Special case of conversionFunction - handles everything that does not /// Special case of conversionFunction - handles everything that does not
/// use exactly one variable to hold the value. /// use exactly one variable to hold the value.

View File

@ -114,7 +114,7 @@ string IRGenerationContext::internalDispatch(size_t _in, size_t _out)
string funName = "dispatch_internal_in_" + to_string(_in) + "_out_" + to_string(_out); string funName = "dispatch_internal_in_" + to_string(_in) + "_out_" + to_string(_out);
return m_functions->createFunction(funName, [&]() { return m_functions->createFunction(funName, [&]() {
Whiskers templ(R"( Whiskers templ(R"(
function <functionName>(fun <comma> <in>) -> <out> { function <functionName>(fun <comma> <in>) <arrow> <out> {
switch fun switch fun
<#cases> <#cases>
case <funID> case <funID>
@ -129,6 +129,7 @@ string IRGenerationContext::internalDispatch(size_t _in, size_t _out)
templ("comma", _in > 0 ? "," : ""); templ("comma", _in > 0 ? "," : "");
YulUtilFunctions utils(m_evmVersion, m_functions); YulUtilFunctions utils(m_evmVersion, m_functions);
templ("in", utils.suffixedVariableNameList("in_", 0, _in)); templ("in", utils.suffixedVariableNameList("in_", 0, _in));
templ("arrow", _out > 0 ? "->" : "");
templ("out", utils.suffixedVariableNameList("out_", 0, _out)); templ("out", utils.suffixedVariableNameList("out_", 0, _out));
vector<map<string, string>> functions; vector<map<string, string>> functions;
for (auto const& contract: m_inheritanceHierarchy) for (auto const& contract: m_inheritanceHierarchy)
@ -138,10 +139,15 @@ string IRGenerationContext::internalDispatch(size_t _in, size_t _out)
function->parameters().size() == _in && function->parameters().size() == _in &&
function->returnParameters().size() == _out function->returnParameters().size() == _out
) )
{
// 0 is reserved for uninitialized function pointers
solAssert(function->id() != 0, "Unexpected function ID: 0");
functions.emplace_back(map<string, string> { functions.emplace_back(map<string, string> {
{ "funID", to_string(function->id()) }, { "funID", to_string(function->id()) },
{ "name", functionName(*function)} { "name", functionName(*function)}
}); });
}
templ("cases", move(functions)); templ("cases", move(functions));
return templ.render(); return templ.render();
}); });

View File

@ -246,7 +246,13 @@ void IRGeneratorForStatements::endVisit(UnaryOperation const& _unaryOperation)
Type const& resultType = type(_unaryOperation); Type const& resultType = type(_unaryOperation);
Token const op = _unaryOperation.getOperator(); Token const op = _unaryOperation.getOperator();
if (resultType.category() == Type::Category::RationalNumber) if (op == Token::Delete)
{
solAssert(!!m_currentLValue, "LValue not retrieved.");
m_code << m_currentLValue->setToZero();
m_currentLValue.reset();
}
else if (resultType.category() == Type::Category::RationalNumber)
{ {
defineExpression(_unaryOperation) << defineExpression(_unaryOperation) <<
formatNumber(resultType.literalValue(nullptr)) << formatNumber(resultType.literalValue(nullptr)) <<

View File

@ -22,6 +22,7 @@
#include <libsolidity/codegen/ir/IRGenerationContext.h> #include <libsolidity/codegen/ir/IRGenerationContext.h>
#include <libsolidity/codegen/YulUtilFunctions.h> #include <libsolidity/codegen/YulUtilFunctions.h>
#include <libsolidity/codegen/CompilerUtils.h>
#include <libsolidity/ast/AST.h> #include <libsolidity/ast/AST.h>
#include <libdevcore/Whiskers.h> #include <libdevcore/Whiskers.h>
@ -45,6 +46,11 @@ string IRLocalVariable::storeValue(string const& _value, Type const& _type) cons
return m_variableName + " := " + _value + "\n"; return m_variableName + " := " + _value + "\n";
} }
string IRLocalVariable::setToZero() const
{
return storeValue(m_context.utils().zeroValueFunction(*m_type) + "()", *m_type);
}
IRStorageItem::IRStorageItem( IRStorageItem::IRStorageItem(
IRGenerationContext& _context, IRGenerationContext& _context,
VariableDeclaration const& _varDecl VariableDeclaration const& _varDecl
@ -110,3 +116,7 @@ string IRStorageItem::storeValue(string const& _value, Type const& _sourceType)
} }
} }
string IRStorageItem::setToZero() const
{
solUnimplemented("Delete for storage location not yet implemented");
}

View File

@ -51,6 +51,8 @@ public:
/// of type @a _type in the lvalue. Might perform type conversion. /// of type @a _type in the lvalue. Might perform type conversion.
virtual std::string storeValue(std::string const& _value, Type const& _type) const = 0; virtual std::string storeValue(std::string const& _value, Type const& _type) const = 0;
/// Returns code that will reset the stored value to zero
virtual std::string setToZero() const = 0;
protected: protected:
IRGenerationContext& m_context; IRGenerationContext& m_context;
Type const* m_type; Type const* m_type;
@ -66,6 +68,7 @@ public:
std::string retrieveValue() const override { return m_variableName; } std::string retrieveValue() const override { return m_variableName; }
std::string storeValue(std::string const& _value, Type const& _type) const override; std::string storeValue(std::string const& _value, Type const& _type) const override;
std::string setToZero() const override;
private: private:
std::string m_variableName; std::string m_variableName;
}; };
@ -86,6 +89,7 @@ public:
std::string retrieveValue() const override; std::string retrieveValue() const override;
std::string storeValue(std::string const& _value, Type const& _type) const override; std::string storeValue(std::string const& _value, Type const& _type) const override;
std::string setToZero() const override;
private: private:
std::string m_slot; std::string m_slot;
unsigned m_offset; unsigned m_offset;

View File

@ -6,18 +6,24 @@ contract C {
return true; return true;
} }
function equal() public pure returns (bool same, bool diff) { function equal() public pure returns (bool same, bool diff, bool inv) {
function() internal pure returns (bool) invalid;
delete invalid;
same = internal1 == internal1; same = internal1 == internal1;
diff = internal1 == internal2; diff = internal1 == internal2;
inv = internal1 == invalid;
} }
function unequal() public pure returns (bool same, bool diff) { function unequal() public pure returns (bool same, bool diff, bool inv) {
function() internal pure returns (bool) invalid;
delete invalid;
same = internal1 != internal1; same = internal1 != internal1;
diff = internal1 != internal2; diff = internal1 != internal2;
inv = internal1 != invalid;
} }
} }
// ==== // ====
// compileViaYul: true // compileViaYul: true
// ---- // ----
// equal() -> true, false // equal() -> true, false, false
// unequal() -> false, true // unequal() -> false, true, true

View File

@ -0,0 +1,29 @@
contract C {
function internal_func() internal pure returns (int8)
{
return 1;
}
function call_internal_func() public pure returns (bool ret)
{
function() internal pure returns(int8) func = internal_func;
return func() == internal_func();
}
function call_deleted_internal_func() public pure returns (bool ret)
{
function() internal pure returns(int8) func = internal_func;
delete func;
return func() == internal_func();
}
function external_func() external pure returns (int8)
{
return 1;
}
}
// ====
// compileViaYul: true
// ----
// call_deleted_internal_func() -> FAILURE
// call_internal_func() -> true