mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Copy byte arrays from storage to storage.
This commit is contained in:
parent
5431afcc8c
commit
62893aa1a1
@ -1571,12 +1571,13 @@ string YulUtilFunctions::copyByteArrayToStorageFunction(ArrayType const& _fromTy
|
||||
);
|
||||
solAssert(_fromType.isByteArray(), "");
|
||||
solAssert(_toType.isByteArray(), "");
|
||||
solUnimplementedAssert(!_fromType.dataStoredIn(DataLocation::Storage), "");
|
||||
|
||||
string functionName = "copy_byte_array_to_storage_from_" + _fromType.identifier() + "_to_" + _toType.identifier();
|
||||
return m_functionCollector.createFunction(functionName, [&](){
|
||||
Whiskers templ(R"(
|
||||
function <functionName>(slot, src<?fromCalldata>, len</fromCalldata>) {
|
||||
<?fromStorage> if eq(slot, src) { leave } </fromStorage>
|
||||
|
||||
let newLen := <arrayLength>(src<?fromCalldata>, len</fromCalldata>)
|
||||
// Make sure array length is sane
|
||||
if gt(newLen, 0xffffffffffffffff) { <panic>() }
|
||||
@ -1605,11 +1606,11 @@ string YulUtilFunctions::copyByteArrayToStorageFunction(ArrayType const& _fromTy
|
||||
let dstPtr := dstDataArea
|
||||
let i := 0
|
||||
for { } lt(i, loopEnd) { i := add(i, 32) } {
|
||||
sstore(dstPtr, <readFromCalldataOrMemory>(add(src, i)))
|
||||
sstore(dstPtr, <read>(add(src, i)))
|
||||
dstPtr := add(dstPtr, 1)
|
||||
}
|
||||
if lt(loopEnd, newLen) {
|
||||
let lastValue := <readFromCalldataOrMemory>(add(src, i))
|
||||
let lastValue := <read>(add(src, i))
|
||||
sstore(dstPtr, <maskBytes>(lastValue, and(newLen, 0x1f)))
|
||||
}
|
||||
sstore(slot, add(mul(newLen, 2), 1))
|
||||
@ -1617,13 +1618,15 @@ string YulUtilFunctions::copyByteArrayToStorageFunction(ArrayType const& _fromTy
|
||||
default {
|
||||
let value := 0
|
||||
if newLen {
|
||||
value := <readFromCalldataOrMemory>(src)
|
||||
value := <read>(src)
|
||||
}
|
||||
sstore(slot, <byteArrayCombineShort>(value, newLen))
|
||||
}
|
||||
}
|
||||
)");
|
||||
templ("functionName", functionName);
|
||||
bool fromStorage = _fromType.dataStoredIn(DataLocation::Storage);
|
||||
templ("fromStorage", fromStorage);
|
||||
bool fromCalldata = _fromType.dataStoredIn(DataLocation::CallData);
|
||||
templ("fromMemory", _fromType.dataStoredIn(DataLocation::Memory));
|
||||
templ("fromCalldata", fromCalldata);
|
||||
@ -1632,7 +1635,7 @@ string YulUtilFunctions::copyByteArrayToStorageFunction(ArrayType const& _fromTy
|
||||
templ("byteArrayLength", extractByteArrayLengthFunction());
|
||||
templ("dstDataLocation", arrayDataAreaFunction(_toType));
|
||||
templ("clearStorageRange", clearStorageRangeFunction(*_toType.baseType()));
|
||||
templ("readFromCalldataOrMemory", readFromMemoryOrCalldata(*TypeProvider::uint256(), fromCalldata));
|
||||
templ("read", fromStorage ? "sload" : fromCalldata ? "calldataload" : "mload");
|
||||
templ("maskBytes", maskBytesFunctionDynamic());
|
||||
templ("byteArrayCombineShort", shortByteArrayEncodeUsedAreaSetLengthFunction());
|
||||
|
||||
@ -2200,8 +2203,7 @@ string YulUtilFunctions::updateStorageValueFunction(
|
||||
("prepare", prepareStoreFunction(_toType))
|
||||
.render();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
auto const* toReferenceType = dynamic_cast<ReferenceType const*>(&_toType);
|
||||
auto const* fromReferenceType = dynamic_cast<ReferenceType const*>(&_fromType);
|
||||
solAssert(fromReferenceType && toReferenceType, "");
|
||||
@ -2209,10 +2211,6 @@ string YulUtilFunctions::updateStorageValueFunction(
|
||||
fromReferenceType->location(),
|
||||
fromReferenceType->isPointer()
|
||||
).get() == *fromReferenceType, "");
|
||||
solUnimplementedAssert(
|
||||
fromReferenceType->location() != DataLocation::Storage,
|
||||
"Copying from storage to storage is not yet implemented."
|
||||
);
|
||||
solAssert(toReferenceType->category() == fromReferenceType->category(), "");
|
||||
|
||||
if (_toType.category() == Type::Category::Array)
|
||||
@ -2233,8 +2231,14 @@ string YulUtilFunctions::updateStorageValueFunction(
|
||||
|
||||
return templ.render();
|
||||
}
|
||||
else if (_toType.category() == Type::Category::Struct)
|
||||
else
|
||||
{
|
||||
solAssert(_toType.category() == Type::Category::Struct, "");
|
||||
|
||||
solUnimplementedAssert(
|
||||
fromReferenceType->location() != DataLocation::Storage,
|
||||
"Copying from storage to storage is not yet implemented."
|
||||
);
|
||||
auto const& fromStructType = dynamic_cast<StructType const&>(_fromType);
|
||||
auto const& toStructType = dynamic_cast<StructType const&>(_toType);
|
||||
solAssert(fromStructType.structDefinition() == toStructType.structDefinition(), "");
|
||||
@ -2324,9 +2328,6 @@ string YulUtilFunctions::updateStorageValueFunction(
|
||||
|
||||
return templ.render();
|
||||
}
|
||||
else
|
||||
solAssert(false, "Invalid non-value type for assignment.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -128,7 +128,7 @@ function test_solc_behaviour()
|
||||
sed -i.bak -e '/^Warning (3805): This is a pre-release compiler version, please do not use it in production./d' "$stderr_path"
|
||||
sed -i.bak -e 's/\(^[ ]*auxdata: \)0x[0-9a-f]*$/\1<AUXDATA REMOVED>/' "$stdout_path"
|
||||
sed -i.bak -e 's/ Consider adding "pragma .*$//' "$stderr_path"
|
||||
sed -i.bak -e 's/\(Unimplemented feature error: .* in \).*$/\1<FILENAME REMOVED>/' "$stderr_path"
|
||||
sed -i.bak -e 's/\(Unimplemented feature error.* in \).*$/\1<FILENAME REMOVED>/' "$stderr_path"
|
||||
sed -i.bak -e 's/"version": "[^"]*"/"version": "<VERSION REMOVED>"/' "$stdout_path"
|
||||
|
||||
# Remove bytecode (but not linker references). Since non-JSON output is unstructured,
|
||||
|
@ -1,5 +1,5 @@
|
||||
Error (1834): Unimplemented feature error: Copying from storage to storage is not yet implemented. in <FILENAME REMOVED>
|
||||
--> yul_unimplemented/input.sol:7:9:
|
||||
Error (1834): Unimplemented feature error in <FILENAME REMOVED>
|
||||
--> yul_unimplemented/input.sol:8:9:
|
||||
|
|
||||
7 | a = b;
|
||||
8 | x.f();
|
||||
| ^^^^^
|
||||
|
@ -1,9 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
library L { function f(uint) public {} }
|
||||
contract test {
|
||||
bytes a;
|
||||
bytes b;
|
||||
using L for uint;
|
||||
function f() public {
|
||||
a = b;
|
||||
uint x;
|
||||
x.f();
|
||||
}
|
||||
}
|
@ -3,6 +3,8 @@ contract c {
|
||||
function copy(uint from, uint to) public returns (bool) { data[to] = data[from]; return true; }
|
||||
mapping(uint => bytes) data;
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// set(uint256): 1, 2 -> true
|
||||
// set(uint256): 2, 2, 3, 4, 5 -> true
|
||||
|
@ -5,6 +5,8 @@ contract c {
|
||||
bytes data1;
|
||||
bytes data2;
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// set(): 1, 2, 3, 4, 5 -> true
|
||||
// storage: nonempty
|
||||
|
@ -12,6 +12,8 @@ contract Test {
|
||||
return bytes(s).length;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(string,uint256): 0x40, 0x02, 0x06, "abcdef" -> "c"
|
||||
// l() -> 0x06
|
||||
|
Loading…
Reference in New Issue
Block a user