Fix assignment to non-lvalue storage values.

This commit is contained in:
chriseth 2020-11-17 12:58:54 +01:00
parent df53b53aa5
commit 74ce8d6979
5 changed files with 26 additions and 15 deletions

View File

@ -1274,7 +1274,6 @@ string YulUtilFunctions::storageArrayPushFunction(ArrayType const& _type)
{
solAssert(_type.location() == DataLocation::Storage, "");
solAssert(_type.isDynamicallySized(), "");
solUnimplementedAssert(_type.baseType()->storageBytes() <= 32, "Base type is not yet implemented.");
string functionName = "array_push_" + _type.identifier();
return m_functionCollector.createFunction(functionName, [&]() {
@ -1540,7 +1539,7 @@ string YulUtilFunctions::copyArrayToStorageFunction(ArrayType const& _fromType,
let <elementValues> := srcPtr
</fromStorage>
<updateStorageValue>(elementSlot<?isValueType>, elementOffset</isValueType>, <elementValues>)
<updateStorageValue>(elementSlot, elementOffset, <elementValues>)
srcPtr := add(srcPtr, <srcStride>)
@ -2317,11 +2316,14 @@ string YulUtilFunctions::updateStorageValueFunction(
solAssert(_offset.value_or(0) == 0, "");
Whiskers templ(R"(
function <functionName>(slot, <value>) {
function <functionName>(slot, <?dynamicOffset>offset, </dynamicOffset><value>) {
<?dynamicOffset>if offset { <panic>() }</dynamicOffset>
<copyArrayToStorage>(slot, <value>)
}
)");
templ("functionName", functionName);
templ("dynamicOffset", !_offset.has_value());
templ("panic", panicFunction());
templ("value", suffixedVariableNameList("value_", 0, _fromType.sizeOnStack()));
templ("copyArrayToStorage", copyArrayToStorageFunction(
dynamic_cast<ArrayType const&>(_fromType),
@ -2340,7 +2342,8 @@ string YulUtilFunctions::updateStorageValueFunction(
solAssert(_offset.value_or(0) == 0, "");
Whiskers templ(R"(
function <functionName>(slot, value) {
function <functionName>(slot, <?dynamicOffset>offset, </dynamicOffset>value) {
<?dynamicOffset>if offset { <panic>() }</dynamicOffset>
<?fromStorage> if eq(slot, value) { leave } </fromStorage>
<#member>
{
@ -2349,8 +2352,10 @@ string YulUtilFunctions::updateStorageValueFunction(
</member>
}
)");
templ("fromStorage", fromStructType.dataStoredIn(DataLocation::Storage));
templ("functionName", functionName);
templ("dynamicOffset", !_offset.has_value());
templ("panic", panicFunction());
templ("fromStorage", fromStructType.dataStoredIn(DataLocation::Storage));
MemberList::MemberMap structMembers = fromStructType.nativeMembers(nullptr);
MemberList::MemberMap toStructMembers = toStructType.nativeMembers(nullptr);
@ -2428,10 +2433,11 @@ string YulUtilFunctions::updateStorageValueFunction(
solAssert(srcOffset == 0, "");
}
t("memberStorageSlotOffset", to_string(offset));
t("updateStorageValue", updateStorageValueFunction(
memberType,
*toStructMembers[i].type,
memberType.isValueType() ? optional<unsigned>{offset} : std::nullopt
optional<unsigned>{offset}
));
memberParams[i]["updateMemberCall"] = t.render();
}

View File

@ -287,6 +287,7 @@ public:
/// Returns the name of a function will write the given value to
/// the specified slot and offset. If offset is not given, it is expected as
/// runtime parameter.
/// For reference types, offset is checked to be zero at runtime.
/// signature: (slot, [offset,] value)
std::string updateStorageValueFunction(
Type const& _fromType,

View File

@ -2660,22 +2660,22 @@ void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable
std::visit(
util::GenericVisitor{
[&](IRLValue::Storage const& _storage) {
std::optional<unsigned> offset;
string offsetArgument;
optional<unsigned> offsetStatic;
if (std::holds_alternative<unsigned>(_storage.offset))
offset = std::get<unsigned>(_storage.offset);
std::visit(GenericVisitor{
[&](unsigned _offset) { offsetStatic = _offset; },
[&](string const& _offset) { offsetArgument = ", " + _offset; }
}, _storage.offset);
m_code <<
m_utils.updateStorageValueFunction(_value.type(), _lvalue.type, offset) <<
m_utils.updateStorageValueFunction(_value.type(), _lvalue.type, offsetStatic) <<
"(" <<
_storage.slot <<
(
std::holds_alternative<string>(_storage.offset) ?
(", " + std::get<string>(_storage.offset)) :
""
) <<
offsetArgument <<
_value.commaSeparatedListPrefixed() <<
")\n";
},
[&](IRLValue::Memory const& _memory) {
if (_lvalue.type.isValueType())

View File

@ -33,6 +33,8 @@ contract c {
return (small.length, large.length);
}
}
// ====
// compileViaYul: also
// ----
// test() -> 0x02000202
// storage: empty

View File

@ -21,6 +21,8 @@ contract c {
delete inner;
}
}
// ====
// compileViaYul: also
// ----
// test() -> 1, 2, 3
// storage: empty