mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge remote-tracking branch 'origin/develop' into breaking
This commit is contained in:
@@ -129,7 +129,7 @@ void ControlFlowAnalyzer::checkUninitializedAccess(CFGNode const* _entry, CFGNod
|
||||
// Propagate changes to all exits and queue them for traversal, if needed.
|
||||
for (auto const& exit: currentNode->exits)
|
||||
if (
|
||||
auto exists = valueOrNullptr(nodeInfos, exit);
|
||||
auto exists = util::valueOrNullptr(nodeInfos, exit);
|
||||
nodeInfos[exit].propagateFrom(nodeInfo) || !exists
|
||||
)
|
||||
nodesToTraverse.insert(exit);
|
||||
|
||||
@@ -457,8 +457,7 @@ void ControlFlowBuilder::operator()(yul::Switch const& _switch)
|
||||
}
|
||||
mergeFlow(nodes);
|
||||
|
||||
bool hasDefault = util::contains_if(_switch.cases, [](yul::Case const& _case) { return !_case.value; });
|
||||
if (!hasDefault)
|
||||
if (!hasDefaultCase(_switch))
|
||||
connect(beforeSwitch, m_currentNode);
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ void ControlFlowRevertPruner::run()
|
||||
|
||||
void ControlFlowRevertPruner::findRevertStates()
|
||||
{
|
||||
std::set<CFG::FunctionContractTuple> pendingFunctions = keys(m_functions);
|
||||
std::set<CFG::FunctionContractTuple> pendingFunctions = util::keys(m_functions);
|
||||
// We interrupt the search whenever we encounter a call to a function with (yet) unknown
|
||||
// revert behaviour. The ``wakeUp`` data structure contains information about which
|
||||
// searches to restart once we know about the behaviour.
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <liblangutil/ErrorReporter.h>
|
||||
|
||||
#include <libsolutil/Algorithms.h>
|
||||
#include <libsolutil/Visitor.h>
|
||||
|
||||
#include <range/v3/view/transform.hpp>
|
||||
|
||||
@@ -451,12 +452,39 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable)
|
||||
|
||||
bool DeclarationTypeChecker::visit(UsingForDirective const& _usingFor)
|
||||
{
|
||||
ContractDefinition const* library = dynamic_cast<ContractDefinition const*>(
|
||||
_usingFor.libraryName().annotation().referencedDeclaration
|
||||
);
|
||||
if (_usingFor.usesBraces())
|
||||
{
|
||||
for (ASTPointer<IdentifierPath> const& function: _usingFor.functionsOrLibrary())
|
||||
if (auto functionDefinition = dynamic_cast<FunctionDefinition const*>(function->annotation().referencedDeclaration))
|
||||
{
|
||||
if (!functionDefinition->isFree() && !(
|
||||
dynamic_cast<ContractDefinition const*>(functionDefinition->scope()) &&
|
||||
dynamic_cast<ContractDefinition const*>(functionDefinition->scope())->isLibrary()
|
||||
))
|
||||
m_errorReporter.typeError(
|
||||
4167_error,
|
||||
function->location(),
|
||||
"Only file-level functions and library functions can be bound to a type in a \"using\" statement"
|
||||
);
|
||||
}
|
||||
else
|
||||
m_errorReporter.fatalTypeError(8187_error, function->location(), "Expected function name." );
|
||||
}
|
||||
else
|
||||
{
|
||||
ContractDefinition const* library = dynamic_cast<ContractDefinition const*>(
|
||||
_usingFor.functionsOrLibrary().front()->annotation().referencedDeclaration
|
||||
);
|
||||
if (!library || !library->isLibrary())
|
||||
m_errorReporter.fatalTypeError(
|
||||
4357_error,
|
||||
_usingFor.functionsOrLibrary().front()->location(),
|
||||
"Library name expected. If you want to attach a function, use '{...}'."
|
||||
);
|
||||
}
|
||||
|
||||
if (!library || !library->isLibrary())
|
||||
m_errorReporter.fatalTypeError(4357_error, _usingFor.libraryName().location(), "Library name expected.");
|
||||
// We do not visit _usingFor.functions() because it will lead to an error since
|
||||
// library names cannot be mentioned stand-alone.
|
||||
|
||||
if (_usingFor.typeName())
|
||||
_usingFor.typeName()->accept(*this);
|
||||
|
||||
@@ -97,7 +97,7 @@ CallGraph FunctionCallGraphBuilder::buildDeployedGraph(
|
||||
// assigned to state variables and as such may be reachable after deployment as well.
|
||||
builder.m_currentNode = CallGraph::SpecialNode::InternalDispatch;
|
||||
set<CallGraph::Node, CallGraph::CompareByID> defaultNode;
|
||||
for (CallGraph::Node const& dispatchTarget: valueOrDefault(_creationGraph.edges, CallGraph::SpecialNode::InternalDispatch, defaultNode))
|
||||
for (CallGraph::Node const& dispatchTarget: util::valueOrDefault(_creationGraph.edges, CallGraph::SpecialNode::InternalDispatch, defaultNode))
|
||||
{
|
||||
solAssert(!holds_alternative<CallGraph::SpecialNode>(dispatchTarget), "");
|
||||
solAssert(get<CallableDeclaration const*>(dispatchTarget) != nullptr, "");
|
||||
|
||||
@@ -411,12 +411,12 @@ struct ReservedErrorSelector: public PostTypeChecker::Checker
|
||||
);
|
||||
else
|
||||
{
|
||||
uint32_t selector = selectorFromSignature32(_error.functionType(true)->externalSignature());
|
||||
uint32_t selector = util::selectorFromSignature32(_error.functionType(true)->externalSignature());
|
||||
if (selector == 0 || ~selector == 0)
|
||||
m_errorReporter.syntaxError(
|
||||
2855_error,
|
||||
_error.location(),
|
||||
"The selector 0x" + toHex(toCompactBigEndian(selector, 4)) + " is reserved. Please rename the error to avoid the collision."
|
||||
"The selector 0x" + util::toHex(toCompactBigEndian(selector, 4)) + " is reserved. Please rename the error to avoid the collision."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ bool PostTypeContractLevelChecker::check(ContractDefinition const& _contract)
|
||||
for (ErrorDefinition const* error: _contract.interfaceErrors())
|
||||
{
|
||||
string signature = error->functionType(true)->externalSignature();
|
||||
uint32_t hash = selectorFromSignature32(signature);
|
||||
uint32_t hash = util::selectorFromSignature32(signature);
|
||||
// Fail if there is a different signature for the same hash.
|
||||
if (!errorHashes[hash].empty() && !errorHashes[hash].count(signature))
|
||||
{
|
||||
|
||||
@@ -403,6 +403,42 @@ void SyntaxChecker::endVisit(ContractDefinition const&)
|
||||
m_currentContractKind = std::nullopt;
|
||||
}
|
||||
|
||||
bool SyntaxChecker::visit(UsingForDirective const& _usingFor)
|
||||
{
|
||||
if (!m_currentContractKind && !_usingFor.typeName())
|
||||
m_errorReporter.syntaxError(
|
||||
8118_error,
|
||||
_usingFor.location(),
|
||||
"The type has to be specified explicitly at file level (cannot use '*')."
|
||||
);
|
||||
else if (_usingFor.usesBraces() && !_usingFor.typeName())
|
||||
m_errorReporter.syntaxError(
|
||||
3349_error,
|
||||
_usingFor.location(),
|
||||
"The type has to be specified explicitly when attaching specific functions."
|
||||
);
|
||||
if (_usingFor.global() && !_usingFor.typeName())
|
||||
m_errorReporter.syntaxError(
|
||||
2854_error,
|
||||
_usingFor.location(),
|
||||
"Can only globally bind functions to specific types."
|
||||
);
|
||||
if (_usingFor.global() && m_currentContractKind)
|
||||
m_errorReporter.syntaxError(
|
||||
3367_error,
|
||||
_usingFor.location(),
|
||||
"\"global\" can only be used at file level."
|
||||
);
|
||||
if (m_currentContractKind == ContractKind::Interface)
|
||||
m_errorReporter.syntaxError(
|
||||
9088_error,
|
||||
_usingFor.location(),
|
||||
"The \"using for\" directive is not allowed inside interfaces."
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SyntaxChecker::visit(FunctionDefinition const& _function)
|
||||
{
|
||||
solAssert(_function.isFree() == (m_currentContractKind == std::nullopt), "");
|
||||
|
||||
@@ -88,6 +88,9 @@ private:
|
||||
|
||||
bool visit(ContractDefinition const& _contract) override;
|
||||
void endVisit(ContractDefinition const& _contract) override;
|
||||
|
||||
bool visit(UsingForDirective const& _usingFor) override;
|
||||
|
||||
bool visit(FunctionDefinition const& _function) override;
|
||||
bool visit(FunctionTypeName const& _node) override;
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <libsolutil/Algorithms.h>
|
||||
#include <libsolutil/StringUtils.h>
|
||||
#include <libsolutil/Views.h>
|
||||
#include <libsolutil/Visitor.h>
|
||||
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
@@ -267,6 +268,11 @@ TypePointers TypeChecker::typeCheckMetaTypeFunctionAndRetrieveReturnType(Functio
|
||||
return {TypeProvider::meta(dynamic_cast<TypeType const&>(*firstArgType).actualType())};
|
||||
}
|
||||
|
||||
bool TypeChecker::visit(ImportDirective const&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance)
|
||||
{
|
||||
auto base = dynamic_cast<ContractDefinition const*>(&dereference(_inheritance.name()));
|
||||
@@ -659,7 +665,7 @@ void TypeChecker::visitManually(
|
||||
if (auto const* modifierContract = dynamic_cast<ContractDefinition const*>(modifierDecl->scope()))
|
||||
if (m_currentContract)
|
||||
{
|
||||
if (!contains(m_currentContract->annotation().linearizedBaseContracts, modifierContract))
|
||||
if (!util::contains(m_currentContract->annotation().linearizedBaseContracts, modifierContract))
|
||||
m_errorReporter.typeError(
|
||||
9428_error,
|
||||
_modifier.location(),
|
||||
@@ -2143,7 +2149,7 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa
|
||||
functionPointerType->declaration().scope() == m_currentContract
|
||||
)
|
||||
msg += " Did you forget to prefix \"this.\"?";
|
||||
else if (contains(
|
||||
else if (util::contains(
|
||||
m_currentContract->annotation().linearizedBaseContracts,
|
||||
functionPointerType->declaration().scope()
|
||||
) && functionPointerType->declaration().scope() != m_currentContract)
|
||||
@@ -2204,9 +2210,9 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa
|
||||
"Cannot implicitly convert component at position " +
|
||||
to_string(i) +
|
||||
" from \"" +
|
||||
argType.canonicalName() +
|
||||
argType.toString() +
|
||||
"\" to \"" +
|
||||
functionPointerType->parameterTypes()[i]->canonicalName() +
|
||||
functionPointerType->parameterTypes()[i]->toString() +
|
||||
"\"" +
|
||||
(result.message().empty() ? "." : ": " + result.message())
|
||||
);
|
||||
@@ -3635,12 +3641,89 @@ void TypeChecker::endVisit(Literal const& _literal)
|
||||
|
||||
void TypeChecker::endVisit(UsingForDirective const& _usingFor)
|
||||
{
|
||||
if (m_currentContract->isInterface())
|
||||
m_errorReporter.typeError(
|
||||
9088_error,
|
||||
_usingFor.location(),
|
||||
"The \"using for\" directive is not allowed inside interfaces."
|
||||
if (!_usingFor.usesBraces())
|
||||
{
|
||||
solAssert(_usingFor.functionsOrLibrary().size() == 1);
|
||||
ContractDefinition const* library = dynamic_cast<ContractDefinition const*>(
|
||||
_usingFor.functionsOrLibrary().front()->annotation().referencedDeclaration
|
||||
);
|
||||
solAssert(library && library->isLibrary());
|
||||
// No type checking for libraries
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_usingFor.typeName())
|
||||
{
|
||||
solAssert(m_errorReporter.hasErrors());
|
||||
return;
|
||||
}
|
||||
|
||||
solAssert(_usingFor.typeName()->annotation().type);
|
||||
Type const* normalizedType = TypeProvider::withLocationIfReference(
|
||||
DataLocation::Storage,
|
||||
_usingFor.typeName()->annotation().type
|
||||
);
|
||||
solAssert(normalizedType);
|
||||
|
||||
if (_usingFor.global())
|
||||
{
|
||||
if (m_currentContract)
|
||||
solAssert(m_errorReporter.hasErrors());
|
||||
if (Declaration const* typeDefinition = _usingFor.typeName()->annotation().type->typeDefinition())
|
||||
{
|
||||
if (typeDefinition->scope() != m_currentSourceUnit)
|
||||
m_errorReporter.typeError(
|
||||
4117_error,
|
||||
_usingFor.location(),
|
||||
"Can only use \"global\" with types defined in the same source unit at file level."
|
||||
);
|
||||
}
|
||||
else
|
||||
m_errorReporter.typeError(
|
||||
8841_error,
|
||||
_usingFor.location(),
|
||||
"Can only use \"global\" with user-defined types."
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
for (ASTPointer<IdentifierPath> const& path: _usingFor.functionsOrLibrary())
|
||||
{
|
||||
solAssert(path->annotation().referencedDeclaration);
|
||||
FunctionDefinition const& functionDefinition =
|
||||
dynamic_cast<FunctionDefinition const&>(*path->annotation().referencedDeclaration);
|
||||
|
||||
solAssert(functionDefinition.type());
|
||||
|
||||
if (functionDefinition.parameters().empty())
|
||||
m_errorReporter.fatalTypeError(
|
||||
4731_error,
|
||||
path->location(),
|
||||
"The function \"" + joinHumanReadable(path->path(), ".") + "\" " +
|
||||
"does not have any parameters, and therefore cannot be bound to the type \"" +
|
||||
(normalizedType ? normalizedType->toString(true) : "*") + "\"."
|
||||
);
|
||||
|
||||
FunctionType const* functionType = dynamic_cast<FunctionType const&>(*functionDefinition.type()).asBoundFunction();
|
||||
solAssert(functionType && functionType->selfType(), "");
|
||||
BoolResult result = normalizedType->isImplicitlyConvertibleTo(
|
||||
*TypeProvider::withLocationIfReference(DataLocation::Storage, functionType->selfType())
|
||||
);
|
||||
if (!result)
|
||||
m_errorReporter.typeError(
|
||||
3100_error,
|
||||
path->location(),
|
||||
"The function \"" + joinHumanReadable(path->path(), ".") + "\" "+
|
||||
"cannot be bound to the type \"" + _usingFor.typeName()->annotation().type->toString() +
|
||||
"\" because the type cannot be implicitly converted to the first argument" +
|
||||
" of the function (\"" + functionType->selfType()->toString() + "\")" +
|
||||
(
|
||||
result.message().empty() ?
|
||||
"." :
|
||||
": " + result.message()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void TypeChecker::checkErrorAndEventParameters(CallableDeclaration const& _callable)
|
||||
|
||||
@@ -125,6 +125,8 @@ private:
|
||||
FunctionType const* _functionType
|
||||
);
|
||||
|
||||
bool visit(ImportDirective const&) override;
|
||||
|
||||
void endVisit(InheritanceSpecifier const& _inheritance) override;
|
||||
void endVisit(ModifierDefinition const& _modifier) override;
|
||||
bool visit(FunctionDefinition const& _function) override;
|
||||
|
||||
@@ -134,6 +134,11 @@ bool ViewPureChecker::check()
|
||||
return !m_errors;
|
||||
}
|
||||
|
||||
bool ViewPureChecker::visit(ImportDirective const&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ViewPureChecker::visit(FunctionDefinition const& _funDef)
|
||||
{
|
||||
solAssert(!m_currentFunction, "");
|
||||
|
||||
@@ -50,6 +50,8 @@ private:
|
||||
langutil::SourceLocation location;
|
||||
};
|
||||
|
||||
bool visit(ImportDirective const&) override;
|
||||
|
||||
bool visit(FunctionDefinition const& _funDef) override;
|
||||
void endVisit(FunctionDefinition const& _funDef) override;
|
||||
bool visit(ModifierDefinition const& _modifierDef) override;
|
||||
|
||||
Reference in New Issue
Block a user