mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #9568 from ethereum/fixImmutables
Fix reads checks for complex assignment and increment/decrement for immutable variables.
This commit is contained in:
commit
20efba6b55
@ -14,6 +14,7 @@ Compiler Features:
|
|||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
* AST: Remove ``null`` member values also when the compiler is used in standard-json-mode.
|
* AST: Remove ``null`` member values also when the compiler is used in standard-json-mode.
|
||||||
|
* Immutables: Properly treat complex assignment and increment/decrement as both reading and writing and thus disallow it everywhere for immutable variables.
|
||||||
* Optimizer: Keep side-effects of ``x`` in ``byte(a, shr(b, x))`` even if the constants ``a`` and ``b`` would make the expression zero unconditionally. This optimizer rule is very hard if not impossible to trigger in a way that it can result in invalid code, though.
|
* Optimizer: Keep side-effects of ``x`` in ``byte(a, shr(b, x))`` even if the constants ``a`` and ``b`` would make the expression zero unconditionally. This optimizer rule is very hard if not impossible to trigger in a way that it can result in invalid code, though.
|
||||||
* Scanner: Fix bug where whitespace would be allowed within the ``->`` token (e.g. ``function f() - > x {}`` becomes invalid in inline assembly and Yul).
|
* Scanner: Fix bug where whitespace would be allowed within the ``->`` token (e.g. ``function f() - > x {}`` becomes invalid in inline assembly and Yul).
|
||||||
* SMTChecker: Fix internal error in BMC function inlining.
|
* SMTChecker: Fix internal error in BMC function inlining.
|
||||||
|
@ -165,41 +165,44 @@ void ImmutableValidator::analyseVariableReference(VariableDeclaration const& _va
|
|||||||
if (!_variableReference.isStateVariable() || !_variableReference.immutable())
|
if (!_variableReference.isStateVariable() || !_variableReference.immutable())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_expression.annotation().willBeWrittenTo && _expression.annotation().lValueOfOrdinaryAssignment)
|
// If this is not an ordinary assignment, we write and read at the same time.
|
||||||
|
bool write = _expression.annotation().willBeWrittenTo;
|
||||||
|
bool read = !_expression.annotation().willBeWrittenTo || !_expression.annotation().lValueOfOrdinaryAssignment;
|
||||||
|
if (write)
|
||||||
{
|
{
|
||||||
if (!m_currentConstructor)
|
if (!m_currentConstructor)
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
1581_error,
|
1581_error,
|
||||||
_expression.location(),
|
_expression.location(),
|
||||||
"Immutable variables can only be initialized inline or assigned directly in the constructor."
|
"Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor."
|
||||||
);
|
);
|
||||||
else if (m_currentConstructor->annotation().contract->id() != _variableReference.annotation().contract->id())
|
else if (m_currentConstructor->annotation().contract->id() != _variableReference.annotation().contract->id())
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
7484_error,
|
7484_error,
|
||||||
_expression.location(),
|
_expression.location(),
|
||||||
"Immutable variables must be initialized in the constructor of the contract they are defined in."
|
"Cannot write to immutable here: Immutable variables must be initialized in the constructor of the contract they are defined in."
|
||||||
);
|
);
|
||||||
else if (m_inLoop)
|
else if (m_inLoop)
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
6672_error,
|
6672_error,
|
||||||
_expression.location(),
|
_expression.location(),
|
||||||
"Immutable variables can only be initialized once, not in a while statement."
|
"Cannot write to immutable here: Immutable variables cannot be initialized inside a loop."
|
||||||
);
|
);
|
||||||
else if (m_inBranch)
|
else if (m_inBranch)
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
4599_error,
|
4599_error,
|
||||||
_expression.location(),
|
_expression.location(),
|
||||||
"Immutable variables must be initialized unconditionally, not in an if statement."
|
"Cannot write to immutable here: Immutable variables cannot be initialized inside an if statement."
|
||||||
);
|
);
|
||||||
|
else if (m_initializedStateVariables.count(&_variableReference))
|
||||||
if (!m_initializedStateVariables.emplace(&_variableReference).second)
|
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
1574_error,
|
1574_error,
|
||||||
_expression.location(),
|
_expression.location(),
|
||||||
"Immutable state variable already initialized."
|
"Immutable state variable already initialized."
|
||||||
);
|
);
|
||||||
|
m_initializedStateVariables.emplace(&_variableReference);
|
||||||
}
|
}
|
||||||
else if (m_inConstructionContext)
|
if (read && m_inConstructionContext)
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
7733_error,
|
7733_error,
|
||||||
_expression.location(),
|
_expression.location(),
|
||||||
|
8
test/libsolidity/syntaxTests/immutable/complex.sol
Normal file
8
test/libsolidity/syntaxTests/immutable/complex.sol
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
contract A {
|
||||||
|
int immutable a;
|
||||||
|
constructor() { a = 5; }
|
||||||
|
function f() public { a += 7; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// TypeError 1581: (83-84): Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
|
@ -6,4 +6,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 4599: (86-87): Immutable variables must be initialized unconditionally, not in an if statement.
|
// TypeError 4599: (86-87): Cannot write to immutable here: Immutable variables cannot be initialized inside an if statement.
|
||||||
|
@ -9,4 +9,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 1581: (119-120): Immutable variables can only be initialized inline or assigned directly in the constructor.
|
// TypeError 1581: (119-120): Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
|
||||||
|
@ -9,4 +9,4 @@ contract C {
|
|||||||
function f(uint a) internal pure {}
|
function f(uint a) internal pure {}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 1581: (59-60): Immutable variables can only be initialized inline or assigned directly in the constructor.
|
// TypeError 1581: (59-60): Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
|
||||||
|
@ -8,4 +8,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 1581: (102-103): Immutable variables can only be initialized inline or assigned directly in the constructor.
|
// TypeError 1581: (102-103): Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
contract C {
|
contract C {
|
||||||
uint immutable x = 3;
|
uint immutable x;
|
||||||
constructor() {
|
constructor() {
|
||||||
x--;
|
x--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 7733: (67-68): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
// TypeError 7733: (63-64): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
contract C {
|
contract C {
|
||||||
uint immutable x = 3;
|
uint immutable x;
|
||||||
constructor() {
|
constructor() {
|
||||||
delete x;
|
delete x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 7733: (74-75): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
// TypeError 7733: (70-71): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
contract C {
|
||||||
|
uint immutable x = 3;
|
||||||
|
constructor() {
|
||||||
|
delete x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 1574: (74-75): Immutable state variable already initialized.
|
||||||
|
// TypeError 7733: (74-75): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
@ -10,5 +10,4 @@ contract C is B(C.f) {
|
|||||||
function f() internal returns(uint) { return x = 2; }
|
function f() internal returns(uint) { return x = 2; }
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 1581: (200-201): Immutable variables can only be initialized inline or assigned directly in the constructor.
|
// TypeError 1581: (200-201): Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
|
||||||
// TypeError 1574: (200-201): Immutable state variable already initialized.
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
contract C {
|
contract C {
|
||||||
uint immutable x = 3;
|
uint immutable x;
|
||||||
constructor() {
|
constructor() {
|
||||||
x++;
|
x++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 7733: (67-68): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
// TypeError 7733: (63-64): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
contract C {
|
||||||
|
uint immutable x;
|
||||||
|
uint immutable y;
|
||||||
|
constructor() {
|
||||||
|
++x;
|
||||||
|
--y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 7733: (77-78): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
||||||
|
// TypeError 7733: (86-87): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it.
|
@ -11,4 +11,4 @@ contract C is B {
|
|||||||
constructor() B(y = 3) { }
|
constructor() B(y = 3) { }
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 1581: (148-149): Immutable variables can only be initialized inline or assigned directly in the constructor.
|
// TypeError 1581: (148-149): Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
|
||||||
|
@ -10,4 +10,4 @@ contract C is B(C.y = 3) {
|
|||||||
uint immutable y;
|
uint immutable y;
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 1581: (104-107): Immutable variables can only be initialized inline or assigned directly in the constructor.
|
// TypeError 1581: (104-107): Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
|
||||||
|
@ -8,5 +8,4 @@ contract C is B {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 7484: (88-89): Immutable variables must be initialized in the constructor of the contract they are defined in.
|
// TypeError 7484: (88-89): Cannot write to immutable here: Immutable variables must be initialized in the constructor of the contract they are defined in.
|
||||||
// TypeError 1574: (88-89): Immutable state variable already initialized.
|
|
||||||
|
@ -6,4 +6,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 6672: (88-89): Immutable variables can only be initialized once, not in a while statement.
|
// TypeError 6672: (88-89): Cannot write to immutable here: Immutable variables cannot be initialized inside a loop.
|
||||||
|
8
test/libsolidity/syntaxTests/immutable/unary.sol
Normal file
8
test/libsolidity/syntaxTests/immutable/unary.sol
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
contract A {
|
||||||
|
int immutable a;
|
||||||
|
constructor() { a = 5; }
|
||||||
|
function f() public { --a; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// TypeError 1581: (85-86): Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
|
@ -6,5 +6,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 1581: (76-77): Immutable variables can only be initialized inline or assigned directly in the constructor.
|
// TypeError 1581: (76-77): Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
|
||||||
// TypeError 1574: (76-77): Immutable state variable already initialized.
|
|
||||||
|
@ -8,5 +8,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 1581: (111-112): Immutable variables can only be initialized inline or assigned directly in the constructor.
|
// TypeError 1581: (111-112): Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
|
||||||
// TypeError 1574: (111-112): Immutable state variable already initialized.
|
|
||||||
|
Loading…
Reference in New Issue
Block a user