mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Fix assignment to non-lvalue storage values.
This commit is contained in:
parent
df53b53aa5
commit
74ce8d6979
@ -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();
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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())
|
||||
|
@ -33,6 +33,8 @@ contract c {
|
||||
return (small.length, large.length);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// test() -> 0x02000202
|
||||
// storage: empty
|
||||
|
@ -21,6 +21,8 @@ contract c {
|
||||
delete inner;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// test() -> 1, 2, 3
|
||||
// storage: empty
|
||||
|
Loading…
Reference in New Issue
Block a user