Merge pull request #4527 from ethereum/mappingEnforceStorage

Enforces explicit data location for mappings
This commit is contained in:
Alex Beregszaszi 2018-07-23 20:43:38 +01:00 committed by GitHub
commit de90290c28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 46 additions and 11 deletions

View File

@ -72,6 +72,7 @@ Bugfixes:
* Tests: Fix chain parameters to make ipc tests work with newer versions of cpp-ethereum. * Tests: Fix chain parameters to make ipc tests work with newer versions of cpp-ethereum.
* Code Generator: Fix allocation of byte arrays (zeroed out too much memory). * Code Generator: Fix allocation of byte arrays (zeroed out too much memory).
* Fix NatSpec json output for `@notice` and `@dev` tags on contract definitions. * Fix NatSpec json output for `@notice` and `@dev` tags on contract definitions.
* References Resolver: Enforce ``storage`` as data location for mappings.
* Type Checker: Consider fixed size arrays when checking for recursive structs. * Type Checker: Consider fixed size arrays when checking for recursive structs.
* Type System: Allow arbitrary exponents for literals with a mantissa of zero. * Type System: Allow arbitrary exponents for literals with a mantissa of zero.

View File

@ -404,9 +404,16 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
} }
isPointer = !_variable.isStateVariable(); isPointer = !_variable.isStateVariable();
} }
type = ref->copyForLocation(typeLoc, isPointer); type = ref->copyForLocation(typeLoc, isPointer);
} }
else if (dynamic_cast<MappingType const*>(type.get()))
{
if (_variable.isLocalVariable() && varLoc != Location::Storage)
typeError(
_variable.location(),
"Data location for mappings must be specified as \"storage\"."
);
}
else if (varLoc != Location::Default && !ref) else if (varLoc != Location::Default && !ref)
typeError(_variable.location(), "Data location can only be given for array or struct types."); typeError(_variable.location(), "Data location can only be given for array or struct types.");

View File

@ -1534,7 +1534,7 @@ BOOST_AUTO_TEST_CASE(struct_reference)
} }
function set() public { function set() public {
data.z = 2; data.z = 2;
mapping(uint8 => s2) map = data.recursive; mapping(uint8 => s2) storage map = data.recursive;
s2 storage inner = map[0]; s2 storage inner = map[0];
inner.z = 3; inner.z = 3;
inner.recursive[0].z = inner.recursive[1].z + 1; inner.recursive[0].z = inner.recursive[1].z + 1;

View File

@ -4,9 +4,9 @@ contract test {
} }
str data; str data;
function fun() public { function fun() public {
mapping(uint=>uint) a = data.map; mapping(uint=>uint) storage a = data.map;
data.map = a; data.map = a;
} }
} }
// ---- // ----
// TypeError: (164-176): Mappings cannot be assigned to. // TypeError: (172-184): Mappings cannot be assigned to.

View File

@ -1,9 +1,9 @@
contract C { contract C {
mapping(uint => uint) x; mapping(uint => uint) x;
function f() public returns (bool ret) { function f() public returns (bool ret) {
mapping(uint => uint) y = x; mapping(uint => uint) storage y = x;
return x == y; return x == y;
} }
} }
// ---- // ----
// TypeError: (139-145): Operator == not compatible with types mapping(uint256 => uint256) and mapping(uint256 => uint256) // TypeError: (147-153): Operator == not compatible with types mapping(uint256 => uint256) and mapping(uint256 => uint256)

View File

@ -1,8 +1,8 @@
contract C { contract C {
function f() public { function f() public {
mapping(uint => uint) x; mapping(uint => uint) storage x;
x; x;
} }
} }
// ---- // ----
// TypeError: (47-70): Uninitialized mapping. Mappings cannot be created dynamically, you have to assign them from a state variable. // TypeError: (47-78): Uninitialized mapping. Mappings cannot be created dynamically, you have to assign them from a state variable.

View File

@ -1,7 +1,7 @@
contract C { contract C {
function f(uint size) public { function f(uint size) public {
mapping(uint => uint) x = new mapping(uint => uint)[](4); mapping(uint => uint) storage x = new mapping(uint => uint)[](4);
} }
} }
// ---- // ----
// TypeError: (86-109): Type cannot live outside storage. // TypeError: (94-117): Type cannot live outside storage.

View File

@ -71,7 +71,7 @@ contract C {
(uint n, uint o) = true ? (1, 2) : (3, 4); (uint n, uint o) = true ? (1, 2) : (3, 4);
(n, o) = (o, n); // Avoid unused var warning (n, o) = (o, n); // Avoid unused var warning
// mapping // mapping
mapping(uint8 => uint8) p = true ? table1 : table2; mapping(uint8 => uint8) storage p = true ? table1 : table2;
p[0] = 0; // Avoid unused var warning p[0] = 0; // Avoid unused var warning
// typetype // typetype
uint32 q = true ? uint32(1) : uint32(2); uint32 q = true ? uint32(1) : uint32(2);

View File

@ -0,0 +1,9 @@
contract c {
mapping(uint => uint) y;
function f() view public {
mapping(uint => uint) calldata x = y;
x;
}
}
// ----
// TypeError: (81-113): Data location for mappings must be specified as "storage".

View File

@ -0,0 +1,9 @@
contract c {
mapping(uint => uint) y;
function f() view public {
mapping(uint => uint) x = y;
x;
}
}
// ----
// TypeError: (81-104): Data location for mappings must be specified as "storage".

View File

@ -0,0 +1,9 @@
contract c {
mapping(uint => uint) y;
function f() view public {
mapping(uint => uint) memory x = y;
x;
}
}
// ----
// TypeError: (81-111): Data location for mappings must be specified as "storage".