diff --git a/libsolidity/analysis/ImmutableValidator.cpp b/libsolidity/analysis/ImmutableValidator.cpp index 2cf34ae6d..33f8cf170 100644 --- a/libsolidity/analysis/ImmutableValidator.cpp +++ b/libsolidity/analysis/ImmutableValidator.cpp @@ -125,7 +125,7 @@ bool ImmutableValidator::visit(WhileStatement const& _whileStatement) void ImmutableValidator::endVisit(Identifier const& _identifier) { if (auto const callableDef = dynamic_cast(_identifier.annotation().referencedDeclaration)) - visitCallableIfNew(callableDef->resolveVirtual(m_currentContract)); + visitCallableIfNew(*_identifier.annotation().requiredLookup == VirtualLookup::Virtual ? callableDef->resolveVirtual(m_currentContract) : *callableDef); if (auto const varDecl = dynamic_cast(_identifier.annotation().referencedDeclaration)) analyseVariableReference(*varDecl, _identifier); } diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index b81e3844a..44edd0c8d 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -2546,8 +2546,10 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) TypePointer exprType = type(_memberAccess.expression()); ASTString const& memberName = _memberAccess.memberName(); + auto& annotation = _memberAccess.annotation(); + // Retrieve the types of the arguments if this is used to call a function. - auto const& arguments = _memberAccess.annotation().arguments; + auto const& arguments = annotation.arguments; MemberList::MemberMap possibleMembers = exprType->members(currentDefinitionScope()).membersByName(memberName); size_t const initialMemberCount = possibleMembers.size(); if (initialMemberCount > 1 && arguments) @@ -2563,8 +2565,6 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) ++it; } - auto& annotation = _memberAccess.annotation(); - annotation.isConstant = false; if (possibleMembers.empty()) @@ -2663,6 +2663,8 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) annotation.referencedDeclaration = possibleMembers.front().declaration; annotation.type = possibleMembers.front().type; + VirtualLookup requiredLookup = VirtualLookup::Static; + if (auto funType = dynamic_cast(annotation.type)) { solAssert( @@ -2681,8 +2683,15 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) _memberAccess.location(), "Using \"." + memberName + "(...)\" is deprecated. Use \"{" + memberName + ": ...}\" instead." ); + + if (!funType->bound()) + if (auto contractType = dynamic_cast(exprType)) + requiredLookup = contractType->isSuper() ? VirtualLookup::Super : VirtualLookup::Virtual; + } + annotation.requiredLookup = requiredLookup; + if (auto const* structType = dynamic_cast(exprType)) annotation.isLValue = !structType->dataStoredIn(DataLocation::CallData); else if (exprType->category() == Type::Category::Array) @@ -3078,6 +3087,10 @@ bool TypeChecker::visit(Identifier const& _identifier) annotation.isConstant = isConstant; + annotation.requiredLookup = + dynamic_cast(annotation.referencedDeclaration) ? + VirtualLookup::Virtual : VirtualLookup::Static; + // Check for deprecated function names. // The check is done here for the case without an actual function call. if (FunctionType const* fType = dynamic_cast(_identifier.annotation().type)) diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index fa339b53e..7fd9eef96 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -566,7 +566,10 @@ public: ASTPointer _baseName, std::unique_ptr>> _arguments ): - ASTNode(_id, _location), m_baseName(std::move(_baseName)), m_arguments(std::move(_arguments)) {} + ASTNode(_id, _location), m_baseName(std::move(_baseName)), m_arguments(std::move(_arguments)) + { + solAssert(m_baseName != nullptr, "Name cannot be null."); + } void accept(ASTVisitor& _visitor) override; void accept(ASTConstVisitor& _visitor) const override; @@ -596,7 +599,10 @@ public: ASTPointer _libraryName, ASTPointer _typeName ): - ASTNode(_id, _location), m_libraryName(std::move(_libraryName)), m_typeName(std::move(_typeName)) {} + ASTNode(_id, _location), m_libraryName(std::move(_libraryName)), m_typeName(std::move(_typeName)) + { + solAssert(m_libraryName != nullptr, "Name cannot be null."); + } void accept(ASTVisitor& _visitor) override; void accept(ASTConstVisitor& _visitor) const override; @@ -1052,7 +1058,10 @@ public: ASTPointer _name, std::unique_ptr>> _arguments ): - ASTNode(_id, _location), m_modifierName(std::move(_name)), m_arguments(std::move(_arguments)) {} + ASTNode(_id, _location), m_modifierName(std::move(_name)), m_arguments(std::move(_arguments)) + { + solAssert(m_modifierName != nullptr, "Name cannot be null."); + } void accept(ASTVisitor& _visitor) override; void accept(ASTConstVisitor& _visitor) const override; @@ -1195,6 +1204,7 @@ class UserDefinedTypeName: public TypeName public: UserDefinedTypeName(int64_t _id, SourceLocation const& _location, std::vector _namePath): TypeName(_id, _location), m_namePath(std::move(_namePath)) {} + void accept(ASTVisitor& _visitor) override; void accept(ASTConstVisitor& _visitor) const override; diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index 2aa48d03e..f9770e0e6 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -264,6 +264,8 @@ struct IdentifierAnnotation: ExpressionAnnotation { /// Referenced declaration, set at latest during overload resolution stage. Declaration const* referencedDeclaration = nullptr; + /// What kind of lookup needs to be done (static, virtual, super) find the declaration. + SetOnce requiredLookup; /// List of possible declarations it could refer to (can contain duplicates). std::vector candidateDeclarations; /// List of possible declarations it could refer to. @@ -274,6 +276,8 @@ struct MemberAccessAnnotation: ExpressionAnnotation { /// Referenced declaration, set at latest during overload resolution stage. Declaration const* referencedDeclaration = nullptr; + /// What kind of lookup needs to be done (static, virtual, super) find the declaration. + SetOnce requiredLookup; }; struct BinaryOperationAnnotation: ExpressionAnnotation diff --git a/libsolidity/ast/ASTEnums.h b/libsolidity/ast/ASTEnums.h index e167e7d49..09dff7337 100644 --- a/libsolidity/ast/ASTEnums.h +++ b/libsolidity/ast/ASTEnums.h @@ -30,6 +30,9 @@ namespace solidity::frontend { +/// Possible lookups for function resolving +enum class VirtualLookup { Static, Virtual, Super }; + // How a function can mutate the EVM state. enum class StateMutability { Pure, View, NonPayable, Payable }; diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index f70398a9f..66df9b249 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -1380,7 +1380,9 @@ private: bool const m_arbitraryParameters = false; bool const m_gasSet = false; ///< true iff the gas value to be used is on the stack bool const m_valueSet = false; ///< true iff the value to be sent is on the stack - bool const m_bound = false; ///< true iff the function is called as arg1.fun(arg2, ..., argn) + /// true iff the function is called as arg1.fun(arg2, ..., argn). + /// This is achieved through the "using for" directive. + bool const m_bound = false; Declaration const* m_declaration = nullptr; bool m_saltSet = false; ///< true iff the salt value to be used is on the stack }; diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 651152a2c..0cf650736 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -1299,6 +1299,8 @@ void ContractCompiler::appendModifierOrFunctionCode() appendModifierOrFunctionCode(); else { + solAssert(*modifierInvocation->name()->annotation().requiredLookup == VirtualLookup::Virtual, ""); + ModifierDefinition const& modifier = dynamic_cast( *modifierInvocation->name()->annotation().referencedDeclaration ).resolveVirtual(m_context.mostDerivedContract()); diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index f096583db..bb4156b93 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -595,6 +595,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) // Do not directly visit the identifier, because this way, we can avoid // the runtime entry label to be created at the creation time context. CompilerContext::LocationSetter locationSetter2(m_context, *identifier); + solAssert(*identifier->annotation().requiredLookup == VirtualLookup::Virtual, ""); utils().pushCombinedFunctionEntryLabel( functionDef->resolveVirtual(m_context.mostDerivedContract()), false @@ -1311,6 +1312,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) if (funType->kind() == FunctionType::Kind::Internal) { FunctionDefinition const& funDef = dynamic_cast(funType->declaration()); + solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static, ""); utils().pushCombinedFunctionEntryLabel(funDef); utils().moveIntoStack(funType->selfType()->sizeOnStack(), 1); } @@ -1346,7 +1348,10 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) // internal library function call, this would push the library address forcing // us to link against it although we actually do not need it. if (auto const* function = dynamic_cast(_memberAccess.annotation().referencedDeclaration)) + { + solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static, ""); utils().pushCombinedFunctionEntryLabel(*function); + } else solAssert(false, "Function not found in member access"); break; @@ -1460,6 +1465,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) if (type.isSuper()) { solAssert(!!_memberAccess.annotation().referencedDeclaration, "Referenced declaration not resolved."); + solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Super, ""); utils().pushCombinedFunctionEntryLabel(m_context.superFunction( dynamic_cast(*_memberAccess.annotation().referencedDeclaration), type.contractDefinition() @@ -1742,6 +1748,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) auto const* funDef = dynamic_cast(_memberAccess.annotation().referencedDeclaration); solAssert(funDef && funDef->isFree(), ""); solAssert(funType->kind() == FunctionType::Kind::Internal, ""); + solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static, ""); utils().pushCombinedFunctionEntryLabel(*funDef); } break; @@ -1933,11 +1940,14 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier) } } else if (FunctionDefinition const* functionDef = dynamic_cast(declaration)) + { // If the identifier is called right away, this code is executed in visit(FunctionCall...), because // we want to avoid having a reference to the runtime function entry point in the // constructor context, since this would force the compiler to include unreferenced // internal functions in the runtime context. + solAssert(*_identifier.annotation().requiredLookup == VirtualLookup::Virtual, ""); utils().pushCombinedFunctionEntryLabel(functionDef->resolveVirtual(m_context.mostDerivedContract())); + } else if (auto variable = dynamic_cast(declaration)) appendVariable(*variable, static_cast(_identifier)); else if (auto contract = dynamic_cast(declaration)) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 338f0eb3e..22c939d8f 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -839,7 +839,10 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) solAssert(functionType->declaration() == *functionDef, ""); if (identifier) + { + solAssert(*identifier->annotation().requiredLookup == VirtualLookup::Virtual, ""); functionDef = &functionDef->resolveVirtual(m_context.mostDerivedContract()); + } else { ContractType const* type = dynamic_cast(memberAccess->expression().annotation().type); @@ -847,6 +850,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) { ContractDefinition const* super = type->contractDefinition().superContract(m_context.mostDerivedContract()); solAssert(super, "Super contract not available."); + solAssert(*memberAccess->annotation().requiredLookup == VirtualLookup::Super, ""); functionDef = &functionDef->resolveVirtual(m_context.mostDerivedContract(), super); } } @@ -2086,6 +2090,7 @@ void IRGeneratorForStatements::endVisit(Identifier const& _identifier) } else if (FunctionDefinition const* functionDef = dynamic_cast(declaration)) { + solAssert(*_identifier.annotation().requiredLookup == VirtualLookup::Virtual, ""); FunctionDefinition const& resolvedFunctionDef = functionDef->resolveVirtual(m_context.mostDerivedContract()); define(_identifier) << to_string(resolvedFunctionDef.id()) << "\n";