diff --git a/libsolidity/analysis/PostTypeChecker.cpp b/libsolidity/analysis/PostTypeChecker.cpp index a18ee4320..6ed306269 100644 --- a/libsolidity/analysis/PostTypeChecker.cpp +++ b/libsolidity/analysis/PostTypeChecker.cpp @@ -82,6 +82,16 @@ bool PostTypeChecker::visit(Identifier const& _identifier) return callVisit(_identifier); } +bool PostTypeChecker::visit(StructDefinition const& _struct) +{ + return callVisit(_struct); +} + +void PostTypeChecker::endVisit(StructDefinition const& _struct) +{ + callEndVisit(_struct); +} + bool PostTypeChecker::visit(ModifierInvocation const& _modifierInvocation) { return callVisit(_modifierInvocation); @@ -282,6 +292,55 @@ private: bool m_insideEmitStatement = false; }; +struct NoVariablesInInterfaceChecker: public PostTypeChecker::Checker +{ + NoVariablesInInterfaceChecker(ErrorReporter& _errorReporter): + Checker(_errorReporter) + {} + + bool visit(VariableDeclaration const& _variable) override + { + // Forbid any variable declarations inside interfaces unless they are part of + // * a function's input/output parameters, + // * or inside of a struct definition. + if ( + m_scope && m_scope->isInterface() + && !_variable.isCallableOrCatchParameter() + && !m_insideStruct + ) + m_errorReporter.typeError(_variable.location(), "Variables cannot be declared in interfaces."); + + return true; + } + + bool visit(ContractDefinition const& _contract) override + { + m_scope = &_contract; + return true; + } + + void endVisit(ContractDefinition const&) override + { + m_scope = nullptr; + } + + bool visit(StructDefinition const&) override + { + solAssert(m_insideStruct >= 0, ""); + m_insideStruct++; + return true; + } + + void endVisit(StructDefinition const&) override + { + m_insideStruct--; + solAssert(m_insideStruct >= 0, ""); + } +private: + ContractDefinition const* m_scope = nullptr; + /// Flag indicating whether we are currently inside a StructDefinition. + int m_insideStruct = 0; +}; } PostTypeChecker::PostTypeChecker(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) @@ -290,4 +349,5 @@ PostTypeChecker::PostTypeChecker(langutil::ErrorReporter& _errorReporter): m_err m_checkers.push_back(make_shared(_errorReporter)); m_checkers.push_back(make_shared(_errorReporter)); m_checkers.push_back(make_shared(_errorReporter)); + m_checkers.push_back(make_shared(_errorReporter)); } diff --git a/libsolidity/analysis/PostTypeChecker.h b/libsolidity/analysis/PostTypeChecker.h index 7a48dfb22..0a3358553 100644 --- a/libsolidity/analysis/PostTypeChecker.h +++ b/libsolidity/analysis/PostTypeChecker.h @@ -38,6 +38,7 @@ namespace solidity::frontend * - whether override specifiers are actually contracts * - whether a modifier is in a function header * - whether an event is used outside of an emit statement + * - whether a variable is declared in a interface * * When adding a new checker, make sure a visitor that forwards calls that your * checker uses exists in PostTypeChecker. Add missing ones. @@ -76,6 +77,9 @@ private: bool visit(Identifier const& _identifier) override; + bool visit(StructDefinition const& _struct) override; + void endVisit(StructDefinition const& _struct) override; + bool visit(ModifierInvocation const& _modifierInvocation) override; void endVisit(ModifierInvocation const& _modifierInvocation) override; diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 6315ac15f..eb1b6ddcc 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -317,10 +317,7 @@ bool TypeChecker::visit(StructDefinition const& _struct) if (CycleDetector(visitor).run(_struct) != nullptr) m_errorReporter.fatalTypeError(_struct.location(), "Recursive struct definition."); - bool insideStruct = true; - swap(insideStruct, m_insideStruct); ASTNode::listAccept(_struct.members(), *this); - m_insideStruct = insideStruct; return false; } @@ -451,16 +448,6 @@ bool TypeChecker::visit(FunctionDefinition const& _function) bool TypeChecker::visit(VariableDeclaration const& _variable) { - // Forbid any variable declarations inside interfaces unless they are part of - // * a function's input/output parameters, - // * or inside of a struct definition. - if ( - m_scope->isInterface() - && !_variable.isCallableOrCatchParameter() - && !m_insideStruct - ) - m_errorReporter.typeError(_variable.location(), "Variables cannot be declared in interfaces."); - if (_variable.typeName()) _variable.typeName()->accept(*this); diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h index 1e30ac1b5..c7443b29c 100644 --- a/libsolidity/analysis/TypeChecker.h +++ b/libsolidity/analysis/TypeChecker.h @@ -163,9 +163,6 @@ private: langutil::EVMVersion m_evmVersion; - /// Flag indicating whether we are currently inside a StructDefinition. - bool m_insideStruct = false; - langutil::ErrorReporter& m_errorReporter; };