Allow access to `_slot` for local storage pointer variables.

This commit is contained in:
chriseth 2020-02-24 15:53:32 +01:00
parent 44bcff42f5
commit 45041e5d3a
8 changed files with 78 additions and 7 deletions

View File

@ -1,6 +1,7 @@
### 0.6.4 (unreleased) ### 0.6.4 (unreleased)
Language Features: Language Features:
* Inline Assembly: Allow assigning to `_slot` of local storage variable pointers.
Compiler Features: Compiler Features:

View File

@ -172,6 +172,11 @@ Assignments are possible to assembly-local variables and to function-local
variables. Take care that when you assign to variables that point to variables. Take care that when you assign to variables that point to
memory or storage, you will only change the pointer and not the data. memory or storage, you will only change the pointer and not the data.
You can assign to the ``_slot`` part of a local storage variable pointer.
For these (structs, arrays or mappings), the ``_offset`` part is always zero.
It is not possible to assign to the ``_slot`` or ``_offset`` part of a state variable,
though.
Things to Avoid Things to Avoid
@ -225,4 +230,3 @@ first slot of the array and followed by the array elements.
Statically-sized memory arrays do not have a length field, but it might be added later Statically-sized memory arrays do not have a length field, but it might be added later
to allow better convertibility between statically- and dynamically-sized arrays, so to allow better convertibility between statically- and dynamically-sized arrays, so
do not rely on this. do not rely on this.

View File

@ -677,10 +677,20 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
m_errorReporter.typeError(_identifier.location, "The suffixes _offset and _slot can only be used on storage variables."); m_errorReporter.typeError(_identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
return size_t(-1); return size_t(-1);
} }
else if (_context != yul::IdentifierContext::RValue) else if (_context == yul::IdentifierContext::LValue)
{ {
m_errorReporter.typeError(_identifier.location, "Storage variables cannot be assigned to."); if (var->isStateVariable())
return size_t(-1); {
m_errorReporter.typeError(_identifier.location, "State variables cannot be assigned to - you have to use \"sstore()\".");
return size_t(-1);
}
else if (ref->second.isOffset)
{
m_errorReporter.typeError(_identifier.location, "Only _slot can be assigned to.");
return size_t(-1);
}
else
solAssert(ref->second.isSlot, "");
} }
} }
else if (!var->isConstant() && var->isStateVariable()) else if (!var->isConstant() && var->isStateVariable())

View File

@ -781,7 +781,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
else else
{ {
// lvalue context // lvalue context
solAssert(!ref->second.isOffset && !ref->second.isSlot, ""); solAssert(!ref->second.isOffset, "");
auto variable = dynamic_cast<VariableDeclaration const*>(decl); auto variable = dynamic_cast<VariableDeclaration const*>(decl);
solAssert( solAssert(
!!variable && m_context.isLocalVariable(variable), !!variable && m_context.isLocalVariable(variable),

View File

@ -0,0 +1,33 @@
contract C {
struct S {
uint a;
uint b;
}
mapping(uint => S) public mappingAccess;
function data() internal view returns (S storage _data) {
// We need to assign it from somewhere, otherwise we would
// get an "uninitialized access" error.
_data = mappingAccess[20];
bytes32 slot = keccak256(abi.encode(uint(1), uint(0)));
assembly {
_data_slot := slot
}
}
function set(uint x) public {
data().a = x;
}
function get() public view returns (uint) {
return data().a;
}
}
// ----
// get() -> 0
// mappingAccess(uint256): 1 -> 0, 0
// set(uint256): 4
// get() -> 4
// mappingAccess(uint256): 1 -> 4, 0

View File

@ -9,5 +9,4 @@ contract C {
} }
} }
// ---- // ----
// TypeError: (114-120): Storage variables cannot be assigned to. // TypeError: (138-146): Only _slot can be assigned to.
// TypeError: (138-146): Storage variables cannot be assigned to.

View File

@ -0,0 +1,12 @@
contract C {
uint[] x;
fallback() external {
assembly {
x_slot := 1
x_offset := 2
}
}
}
// ----
// TypeError: (84-90): State variables cannot be assigned to - you have to use "sstore()".
// TypeError: (108-116): State variables cannot be assigned to - you have to use "sstore()".

View File

@ -0,0 +1,12 @@
contract C {
uint[] x;
fallback() external {
uint[] storage y = x;
assembly {
y_slot := 1
y_offset := 2
}
}
}
// ----
// TypeError: (138-146): Only _slot can be assigned to.