Merge remote-tracking branch 'origin/develop' into breaking

This commit is contained in:
chriseth
2022-03-16 15:41:37 +01:00
542 changed files with 6696 additions and 2399 deletions
+1 -1
View File
@@ -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);
+1 -2
View File
@@ -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);
+1 -1
View File
@@ -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, "");
+2 -2
View File
@@ -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))
{
+36
View File
@@ -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), "");
+3
View File
@@ -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;
+92 -9
View File
@@ -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)
+2
View File
@@ -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;
+5
View File
@@ -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, "");
+2
View File
@@ -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;