Skip to content

Commit 7c1daa5

Browse files
authored
Merge pull request #12523 from ethereum/immutable-ctor-fail-12379
Fix wrong error with immutables when base contract c'tor uses return
2 parents f36a0eb + 2c4c826 commit 7c1daa5

File tree

4 files changed

+30
-11
lines changed

4 files changed

+30
-11
lines changed

Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Compiler Features:
1111

1212
Bugfixes:
1313
* Control Flow Graph: Perform proper virtual lookup for modifiers for uninitialized variable and unreachable code analysis.
14+
* Immutables: Fix wrong error when the constructor of a base contract uses ``return`` and the parent contract contains immutable variables.
1415

1516

1617
Solc-Js:

libsolidity/analysis/ImmutableValidator.cpp

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ void ImmutableValidator::analyze()
2929
{
3030
m_inCreationContext = true;
3131

32-
auto linearizedContracts = m_currentContract.annotation().linearizedBaseContracts | ranges::views::reverse;
32+
auto linearizedContracts = m_mostDerivedContract.annotation().linearizedBaseContracts | ranges::views::reverse;
3333

3434
for (ContractDefinition const* contract: linearizedContracts)
3535
for (VariableDeclaration const* stateVar: contract->stateVariables())
@@ -62,7 +62,7 @@ void ImmutableValidator::analyze()
6262
visitCallableIfNew(*modDef);
6363
}
6464

65-
checkAllVariablesInitialized(m_currentContract.location());
65+
checkAllVariablesInitialized(m_mostDerivedContract.location());
6666
}
6767

6868
bool ImmutableValidator::visit(Assignment const& _assignment)
@@ -137,7 +137,7 @@ void ImmutableValidator::endVisit(IdentifierPath const& _identifierPath)
137137
if (auto const callableDef = dynamic_cast<CallableDeclaration const*>(_identifierPath.annotation().referencedDeclaration))
138138
visitCallableIfNew(
139139
*_identifierPath.annotation().requiredLookup == VirtualLookup::Virtual ?
140-
callableDef->resolveVirtual(m_currentContract) :
140+
callableDef->resolveVirtual(m_mostDerivedContract) :
141141
*callableDef
142142
);
143143

@@ -147,7 +147,7 @@ void ImmutableValidator::endVisit(IdentifierPath const& _identifierPath)
147147
void ImmutableValidator::endVisit(Identifier const& _identifier)
148148
{
149149
if (auto const callableDef = dynamic_cast<CallableDeclaration const*>(_identifier.annotation().referencedDeclaration))
150-
visitCallableIfNew(*_identifier.annotation().requiredLookup == VirtualLookup::Virtual ? callableDef->resolveVirtual(m_currentContract) : *callableDef);
150+
visitCallableIfNew(*_identifier.annotation().requiredLookup == VirtualLookup::Virtual ? callableDef->resolveVirtual(m_mostDerivedContract) : *callableDef);
151151
if (auto const varDecl = dynamic_cast<VariableDeclaration const*>(_identifier.annotation().referencedDeclaration))
152152
analyseVariableReference(*varDecl, _identifier);
153153
}
@@ -160,15 +160,18 @@ void ImmutableValidator::endVisit(Return const& _return)
160160

161161
bool ImmutableValidator::analyseCallable(CallableDeclaration const& _callableDeclaration)
162162
{
163-
FunctionDefinition const* prevConstructor = m_currentConstructor;
164-
m_currentConstructor = nullptr;
163+
ScopedSaveAndRestore constructorGuard{m_currentConstructor, {}};
164+
ScopedSaveAndRestore constructorContractGuard{m_currentConstructorContract, {}};
165165

166166
if (FunctionDefinition const* funcDef = dynamic_cast<decltype(funcDef)>(&_callableDeclaration))
167167
{
168168
ASTNode::listAccept(funcDef->modifiers(), *this);
169169

170170
if (funcDef->isConstructor())
171+
{
172+
m_currentConstructorContract = funcDef->annotation().contract;
171173
m_currentConstructor = funcDef;
174+
}
172175

173176
if (funcDef->isImplemented())
174177
funcDef->body().accept(*this);
@@ -177,8 +180,6 @@ bool ImmutableValidator::analyseCallable(CallableDeclaration const& _callableDec
177180
if (modDef->isImplemented())
178181
modDef->body().accept(*this);
179182

180-
m_currentConstructor = prevConstructor;
181-
182183
return false;
183184
}
184185

@@ -253,7 +254,8 @@ void ImmutableValidator::analyseVariableReference(VariableDeclaration const& _va
253254

254255
void ImmutableValidator::checkAllVariablesInitialized(solidity::langutil::SourceLocation const& _location)
255256
{
256-
for (ContractDefinition const* contract: m_currentContract.annotation().linearizedBaseContracts)
257+
for (ContractDefinition const* contract: m_mostDerivedContract.annotation().linearizedBaseContracts | ranges::views::reverse)
258+
{
257259
for (VariableDeclaration const* varDecl: contract->stateVariables())
258260
if (varDecl->immutable())
259261
if (!util::contains(m_initializedStateVariables, varDecl))
@@ -263,6 +265,11 @@ void ImmutableValidator::checkAllVariablesInitialized(solidity::langutil::Source
263265
solidity::langutil::SecondarySourceLocation().append("Not initialized: ", varDecl->location()),
264266
"Construction control flow ends without initializing all immutable state variables."
265267
);
268+
269+
// Don't check further than the current c'tors contract
270+
if (contract == m_currentConstructorContract)
271+
break;
272+
}
266273
}
267274

268275
void ImmutableValidator::visitCallableIfNew(Declaration const& _declaration)

libsolidity/analysis/ImmutableValidator.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class ImmutableValidator: private ASTConstVisitor
4242

4343
public:
4444
ImmutableValidator(langutil::ErrorReporter& _errorReporter, ContractDefinition const& _contractDefinition):
45-
m_currentContract(_contractDefinition),
45+
m_mostDerivedContract(_contractDefinition),
4646
m_errorReporter(_errorReporter)
4747
{ }
4848

@@ -66,14 +66,15 @@ class ImmutableValidator: private ASTConstVisitor
6666

6767
void visitCallableIfNew(Declaration const& _declaration);
6868

69-
ContractDefinition const& m_currentContract;
69+
ContractDefinition const& m_mostDerivedContract;
7070

7171
CallableDeclarationSet m_visitedCallables;
7272

7373
std::set<VariableDeclaration const*, ASTNode::CompareByID> m_initializedStateVariables;
7474
langutil::ErrorReporter& m_errorReporter;
7575

7676
FunctionDefinition const* m_currentConstructor = nullptr;
77+
ContractDefinition const* m_currentConstructorContract = nullptr;
7778
bool m_inLoop = false;
7879
bool m_inBranch = false;
7980
bool m_inCreationContext = true;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
contract Parent {
2+
constructor() {
3+
return;
4+
}
5+
}
6+
7+
contract Child is Parent {
8+
uint public immutable baked = 123;
9+
}
10+

0 commit comments

Comments
 (0)