Skip to content

Commit ff886e7

Browse files
Reports an error on unimplemented modifiers in a function definition.
1 parent 215bbe2 commit ff886e7

File tree

8 files changed

+73
-10
lines changed

8 files changed

+73
-10
lines changed

Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ Bugfixes:
3030
* Type Checker: Fix internal compiler error when attempting to use an invalid external function type on pre-byzantium EVMs.
3131
* Type Checker: Make errors about (nested) mapping type in event or error parameter into fatal type errors.
3232
* Type Checker: Fix internal compiler error when overriding receive ether function with one having different parameters during inheritance.
33+
* Type Checker: Fix internal compiler error when overriding an implemented modifier with an unimplemented one.
3334

3435

3536
AST Changes:

libsolidity/analysis/OverrideChecker.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,19 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr
573573
);
574574
}
575575

576+
if (_overriding.unimplemented() && !_super.unimplemented())
577+
{
578+
solAssert(!_overriding.isVariable() || !_overriding.unimplemented(), "");
579+
overrideError(
580+
_overriding,
581+
_super,
582+
4593_error,
583+
"Overriding an implemented " + _super.astNodeName() +
584+
" with an unimplemented " + _overriding.astNodeName() +
585+
" is not allowed."
586+
);
587+
}
588+
576589
if (_super.isFunction())
577590
{
578591
FunctionType const* functionType = _overriding.functionType();
@@ -613,14 +626,6 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr
613626
stateMutabilityToString(_overriding.stateMutability()) +
614627
"\"."
615628
);
616-
617-
if (_overriding.unimplemented() && !_super.unimplemented())
618-
overrideError(
619-
_overriding,
620-
_super,
621-
4593_error,
622-
"Overriding an implemented function with an unimplemented function is not allowed."
623-
);
624629
}
625630
}
626631

libsolidity/analysis/TypeChecker.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,8 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
430430
for (ASTPointer<ModifierInvocation> const& modifier: _function.modifiers())
431431
{
432432
vector<ContractDefinition const*> baseContracts;
433-
if (auto contract = dynamic_cast<ContractDefinition const*>(_function.scope()))
433+
auto contract = dynamic_cast<ContractDefinition const*>(_function.scope());
434+
if (contract)
434435
{
435436
baseContracts = contract->annotation().linearizedBaseContracts;
436437
// Delete first base which is just the main contract itself
@@ -439,6 +440,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
439440

440441
visitManually(
441442
*modifier,
443+
contract,
442444
_function.isConstructor() ? baseContracts : vector<ContractDefinition const*>()
443445
);
444446
Declaration const* decl = &dereference(modifier->name());
@@ -613,6 +615,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
613615

614616
void TypeChecker::visitManually(
615617
ModifierInvocation const& _modifier,
618+
ContractDefinition const* _contract,
616619
vector<ContractDefinition const*> const& _bases
617620
)
618621
{
@@ -630,6 +633,7 @@ void TypeChecker::visitManually(
630633
{
631634
parameters = &modifierDecl->parameters();
632635
if (auto const* modifierContract = dynamic_cast<ContractDefinition const*>(modifierDecl->scope()))
636+
{
633637
if (m_currentContract)
634638
{
635639
if (!contains(m_currentContract->annotation().linearizedBaseContracts, modifierContract))
@@ -639,6 +643,17 @@ void TypeChecker::visitManually(
639643
"Can only use modifiers defined in the current contract or in base contracts."
640644
);
641645
}
646+
647+
if (!modifierDecl->isImplemented() && !_contract->abstract())
648+
{
649+
m_errorReporter.typeError(
650+
9113_error,
651+
_modifier.location(),
652+
"Cannot call unimplemented modifier."
653+
);
654+
}
655+
}
656+
642657
}
643658
else
644659
// check parameters for Base constructors

libsolidity/analysis/TypeChecker.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ class TypeChecker: private ASTConstVisitor
122122
bool visit(VariableDeclaration const& _variable) override;
123123
/// We need to do this manually because we want to pass the bases of the current contract in
124124
/// case this is a base constructor call.
125-
void visitManually(ModifierInvocation const& _modifier, std::vector<ContractDefinition const*> const& _bases);
125+
void visitManually(ModifierInvocation const& _modifier, ContractDefinition const* _contract, std::vector<ContractDefinition const*> const& _bases);
126126
bool visit(EventDefinition const& _eventDef) override;
127127
bool visit(ErrorDefinition const& _errorDef) override;
128128
void endVisit(FunctionTypeName const& _funType) override;

test/libsolidity/syntaxTests/inheritance/virtual/modifier_virtual_err.sol

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ library test {
55
}
66
// ----
77
// TypeError 3275: (19-38): Modifiers in a library cannot be virtual.
8+
// TypeError 9113: (56-57): Cannot call unimplemented modifier.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
contract A {
2+
modifier m() virtual { _; }
3+
}
4+
abstract contract B is A {
5+
modifier m() virtual override;
6+
}
7+
contract C is B {
8+
function f() m public {}
9+
}
10+
// ----
11+
// TypeError 4593: (78-108): Overriding an implemented modifier with an unimplemented modifier is not allowed.
12+
// TypeError 9113: (146-147): Cannot call unimplemented modifier.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity >= 0.5.0;
3+
4+
contract A {
5+
modifier m() virtual { _; }
6+
}
7+
abstract contract B {
8+
modifier m() virtual;
9+
}
10+
contract C is A, B {
11+
modifier m() override(A, B) { _; }
12+
function f() B.m public {}
13+
}
14+
// ----
15+
// TypeError 9113: (240-243): Cannot call unimplemented modifier.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity >= 0.5.0;
3+
4+
abstract contract A {
5+
modifier m() virtual;
6+
}
7+
contract B is A {
8+
modifier m() virtual override { _; }
9+
}
10+
contract C is B {
11+
function f() A.m public {}
12+
}
13+
// ----
14+
// TypeError 9113: (212-215): Cannot call unimplemented modifier.

0 commit comments

Comments
 (0)