Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Numerical Yul node id handles #15215

Draft
wants to merge 15 commits into
base: develop
Choose a base branch
from
  •  
  •  
  •  
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Compiler Features:


Bugfixes:
* AsmParser: Parsing rules for source location comments have been relaxed: Whitespace between the indices as well as single-quoted code snippets are now allowed.
* SMTChecker: Fix error that reports invalid number of verified checks for BMC and CHC engines.
* SMTChecker: Fix formatting of unary minus expressions in invariants.
* SMTChecker: Fix internal compiler error when reporting proved targets for BMC engine.
Expand Down
2 changes: 0 additions & 2 deletions libsolc/libsolc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
#include <libsolc/libsolc.h>
#include <libsolidity/interface/StandardCompiler.h>
#include <libsolidity/interface/Version.h>
#include <libyul/YulString.h>

#include <cstdlib>
#include <list>
Expand Down Expand Up @@ -153,7 +152,6 @@ extern void solidity_reset() noexcept
{
// This is called right before each compilation, but not at the end, so additional memory
// can be freed here.
yul::YulStringRepository::reset();
solidityAllocations.clear();
}
}
10 changes: 5 additions & 5 deletions libsolidity/analysis/ControlFlowBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ bool ControlFlowBuilder::visit(InlineAssembly const& _inlineAssembly)
solAssert(!!m_currentNode && !m_inlineAssembly, "");

m_inlineAssembly = &_inlineAssembly;
(*this)(_inlineAssembly.operations());
(*this)(_inlineAssembly.operations().block());
m_inlineAssembly = nullptr;

return false;
Expand Down Expand Up @@ -582,13 +582,13 @@ void ControlFlowBuilder::operator()(yul::FunctionCall const& _functionCall)
solAssert(m_currentNode && m_inlineAssembly, "");
yul::ASTWalker::operator()(_functionCall);

if (auto const *builtinFunction = m_inlineAssembly->dialect().builtin(_functionCall.functionName.name))
if (auto const *builtinFunction = m_inlineAssembly->operations().nameRepository().builtin(_functionCall.functionName.name))
{
if (builtinFunction->controlFlowSideEffects.canTerminate)
if (builtinFunction->data->controlFlowSideEffects.canTerminate)
connect(m_currentNode, m_transactionReturnNode);
if (builtinFunction->controlFlowSideEffects.canRevert)
if (builtinFunction->data->controlFlowSideEffects.canRevert)
connect(m_currentNode, m_revertNode);
if (!builtinFunction->controlFlowSideEffects.canContinue)
if (!builtinFunction->data->controlFlowSideEffects.canContinue)
m_currentNode = newLabel();
}
}
Expand Down
10 changes: 6 additions & 4 deletions libsolidity/analysis/PostTypeChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,8 @@ struct ReservedErrorSelector: public PostTypeChecker::Checker
class YulLValueChecker : public solidity::yul::ASTWalker
{
public:
YulLValueChecker(ASTString const& _identifierName): m_identifierName(_identifierName) {}
YulLValueChecker(ASTString const& _identifierName, yul::YulNameRepository const& _yulNameRepository):
m_identifierName(_identifierName), m_yulNameRepository(_yulNameRepository) {}
bool willBeWrittenTo() const { return m_willBeWrittenTo; }
using solidity::yul::ASTWalker::operator();
void operator()(solidity::yul::Assignment const& _assignment) override
Expand All @@ -472,12 +473,13 @@ class YulLValueChecker : public solidity::yul::ASTWalker

if (ranges::any_of(
_assignment.variableNames,
[&](auto const& yulIdentifier) { return yulIdentifier.name.str() == m_identifierName; }
[&](auto const& yulIdentifier) { return m_yulNameRepository.requiredLabelOf(yulIdentifier.name) == m_identifierName; }
))
m_willBeWrittenTo = true;
}
private:
ASTString const& m_identifierName;
yul::YulNameRepository const& m_yulNameRepository;
bool m_willBeWrittenTo = false;
};

Expand Down Expand Up @@ -505,8 +507,8 @@ class LValueChecker: public ASTConstVisitor
if (m_willBeWrittenTo)
return;

YulLValueChecker yulChecker{m_declaration->name()};
yulChecker(_inlineAssembly.operations());
YulLValueChecker yulChecker{m_declaration->name(), _inlineAssembly.operations().nameRepository()};
yulChecker(_inlineAssembly.operations().block());
m_willBeWrittenTo = yulChecker.willBeWrittenTo();
}
private:
Expand Down
39 changes: 22 additions & 17 deletions libsolidity/analysis/ReferencesResolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,9 @@ bool ReferencesResolver::visit(UsingForDirective const& _usingFor)
bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
{
m_yulAnnotation = &_inlineAssembly.annotation();
(*this)(_inlineAssembly.operations());
m_yulNameRepository = &_inlineAssembly.operations().nameRepository();
(*this)(_inlineAssembly.operations().block());
m_yulNameRepository = nullptr;
m_yulAnnotation = nullptr;

return false;
Expand Down Expand Up @@ -270,12 +272,13 @@ bool ReferencesResolver::visit(BinaryOperation const& _binaryOperation)

void ReferencesResolver::operator()(yul::FunctionDefinition const& _function)
{
solAssert(m_yulNameRepository != nullptr);
solAssert(nativeLocationOf(_function) == originLocationOf(_function), "");
validateYulIdentifierName(_function.name, nativeLocationOf(_function));
validateYulIdentifierName(m_yulNameRepository->requiredLabelOf(_function.name), nativeLocationOf(_function));
for (yul::TypedName const& varName: _function.parameters + _function.returnVariables)
{
solAssert(nativeLocationOf(varName) == originLocationOf(varName), "");
validateYulIdentifierName(varName.name, nativeLocationOf(varName));
validateYulIdentifierName(m_yulNameRepository->requiredLabelOf(varName.name), nativeLocationOf(varName));
}

bool wasInsideFunction = m_yulInsideFunction;
Expand All @@ -286,12 +289,13 @@ void ReferencesResolver::operator()(yul::FunctionDefinition const& _function)

void ReferencesResolver::operator()(yul::Identifier const& _identifier)
{
solAssert(m_yulNameRepository != nullptr);
solAssert(nativeLocationOf(_identifier) == originLocationOf(_identifier), "");

auto const identifierLabel = m_yulNameRepository->requiredLabelOf(_identifier.name);
if (m_resolver.experimentalSolidity())
{
std::vector<std::string> splitName;
boost::split(splitName, _identifier.name.str(), boost::is_any_of("."));
boost::split(splitName, identifierLabel, boost::is_any_of("."));
solAssert(!splitName.empty());
if (splitName.size() > 2)
{
Expand Down Expand Up @@ -332,22 +336,22 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier)
static std::set<std::string> suffixes{"slot", "offset", "length", "address", "selector"};
std::string suffix;
for (std::string const& s: suffixes)
if (boost::algorithm::ends_with(_identifier.name.str(), "." + s))
if (boost::algorithm::ends_with(identifierLabel, "." + s))
suffix = s;

// Could also use `pathFromCurrentScope`, split by '.'.
// If we do that, suffix should only be set for when it has a special
// meaning, not for normal identifierPaths.
auto declarations = m_resolver.nameFromCurrentScope(_identifier.name.str());
auto declarations = m_resolver.nameFromCurrentScope(std::string(identifierLabel));
if (!suffix.empty())
{
// special mode to access storage variables
if (!declarations.empty())
// the special identifier exists itself, we should not allow that.
return;
std::string realName = _identifier.name.str().substr(0, _identifier.name.str().size() - suffix.size() - 1);
auto const realName = identifierLabel.substr(0, identifierLabel.size() - suffix.size() - 1);
solAssert(!realName.empty(), "Empty name.");
declarations = m_resolver.nameFromCurrentScope(realName);
declarations = m_resolver.nameFromCurrentScope(std::string(realName));
if (!declarations.empty())
// To support proper path resolution, we have to use pathFromCurrentScope.
solAssert(!util::contains(realName, '.'), "");
Expand All @@ -364,8 +368,8 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier)
else if (declarations.size() == 0)
{
if (
boost::algorithm::ends_with(_identifier.name.str(), "_slot") ||
boost::algorithm::ends_with(_identifier.name.str(), "_offset")
boost::algorithm::ends_with(identifierLabel, "_slot") ||
boost::algorithm::ends_with(identifierLabel, "_offset")
)
m_errorReporter.declarationError(
9467_error,
Expand All @@ -391,13 +395,14 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier)

void ReferencesResolver::operator()(yul::VariableDeclaration const& _varDecl)
{
solAssert(m_yulNameRepository != nullptr);
for (auto const& identifier: _varDecl.variables)
{
solAssert(nativeLocationOf(identifier) == originLocationOf(identifier), "");
validateYulIdentifierName(identifier.name, nativeLocationOf(identifier));
validateYulIdentifierName(m_yulNameRepository->requiredLabelOf(identifier.name), nativeLocationOf(identifier));

if (
auto declarations = m_resolver.nameFromCurrentScope(identifier.name.str());
auto declarations = m_resolver.nameFromCurrentScope(std::string(m_yulNameRepository->requiredLabelOf(identifier.name)));
!declarations.empty()
)
{
Expand Down Expand Up @@ -488,19 +493,19 @@ void ReferencesResolver::resolveInheritDoc(StructuredDocumentation const& _docum
}
}

void ReferencesResolver::validateYulIdentifierName(yul::YulString _name, SourceLocation const& _location)
void ReferencesResolver::validateYulIdentifierName(std::string_view const _name, SourceLocation const& _location)
{
if (util::contains(_name.str(), '.'))
if (util::contains(_name, '.'))
m_errorReporter.declarationError(
3927_error,
_location,
"User-defined identifiers in inline assembly cannot contain '.'."
);

if (std::set<std::string>{"this", "super", "_"}.count(_name.str()))
if (std::set<std::string, std::less<>>{"this", "super", "_"}.count(_name))
m_errorReporter.declarationError(
4113_error,
_location,
"The identifier name \"" + _name.str() + "\" is reserved."
fmt::format("The identifier name \"{}\" is reserved.", _name)
);
}
3 changes: 2 additions & 1 deletion libsolidity/analysis/ReferencesResolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ class ReferencesResolver: private ASTConstVisitor, private yul::ASTWalker
void resolveInheritDoc(StructuredDocumentation const& _documentation, StructurallyDocumentedAnnotation& _annotation);

/// Checks if the name contains a '.'.
void validateYulIdentifierName(yul::YulString _name, langutil::SourceLocation const& _location);
void validateYulIdentifierName(std::string_view _name, langutil::SourceLocation const& _location);

langutil::ErrorReporter& m_errorReporter;
NameAndTypeResolver& m_resolver;
Expand All @@ -104,6 +104,7 @@ class ReferencesResolver: private ASTConstVisitor, private yul::ASTWalker
bool const m_resolveInsideCode;

InlineAssemblyAnnotation* m_yulAnnotation = nullptr;
yul::YulNameRepository const* m_yulNameRepository = nullptr;
bool m_yulInsideFunction = false;
bool m_typeContext = false;
};
Expand Down
2 changes: 1 addition & 1 deletion libsolidity/analysis/SyntaxChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ bool SyntaxChecker::visit(InlineAssembly const& _inlineAssembly)
if (!m_useYulOptimizer)
return false;

if (yul::MSizeFinder::containsMSize(_inlineAssembly.dialect(), _inlineAssembly.operations()))
if (yul::MSizeFinder::containsMSize(_inlineAssembly.operations()))
m_errorReporter.syntaxError(
6553_error,
_inlineAssembly.location(),
Expand Down
4 changes: 2 additions & 2 deletions libsolidity/analysis/TypeChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -944,10 +944,10 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
yul::AsmAnalyzer analyzer(
*_inlineAssembly.annotation().analysisInfo,
m_errorReporter,
_inlineAssembly.dialect(),
_inlineAssembly.operations().nameRepository(),
identifierAccess
);
if (!analyzer.analyze(_inlineAssembly.operations()))
if (!analyzer.analyze(_inlineAssembly.operations().block()))
solAssert(m_errorReporter.hasErrors());
_inlineAssembly.annotation().hasMemoryEffects =
lvalueAccessToMemoryVariable ||
Expand Down
18 changes: 9 additions & 9 deletions libsolidity/analysis/ViewPureChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ class AssemblyViewPureChecker
{
public:
explicit AssemblyViewPureChecker(
yul::Dialect const& _dialect,
yul::YulNameRepository const& _yulNameRepository,
std::function<void(StateMutability, SourceLocation const&)> _reportMutability
):
m_dialect(_dialect),
m_yulNameRepository(_yulNameRepository),
m_reportMutability(std::move(_reportMutability)) {}

void operator()(yul::Literal const&) {}
Expand All @@ -65,10 +65,10 @@ class AssemblyViewPureChecker
}
void operator()(yul::FunctionCall const& _funCall)
{
if (yul::EVMDialect const* dialect = dynamic_cast<decltype(dialect)>(&m_dialect))
if (yul::BuiltinFunctionForEVM const* fun = dialect->builtin(_funCall.functionName.name))
if (fun->instruction)
checkInstruction(nativeLocationOf(_funCall), *fun->instruction);
if (yul::EVMDialect const* dialect = dynamic_cast<decltype(dialect)>(&m_yulNameRepository.dialect()))
if (auto const* fun = m_yulNameRepository.builtin(_funCall.functionName.name))
if (auto const* evmFun = dynamic_cast<yul::BuiltinFunctionForEVM const*>(fun->data); evmFun->instruction)
checkInstruction(nativeLocationOf(_funCall), *evmFun->instruction);

for (auto const& arg: _funCall.arguments)
std::visit(*this, arg);
Expand Down Expand Up @@ -119,7 +119,7 @@ class AssemblyViewPureChecker
m_reportMutability(StateMutability::View, _location);
}

yul::Dialect const& m_dialect;
yul::YulNameRepository const& m_yulNameRepository;
std::function<void(StateMutability, SourceLocation const&)> m_reportMutability;
};

Expand Down Expand Up @@ -224,9 +224,9 @@ void ViewPureChecker::endVisit(Identifier const& _identifier)
void ViewPureChecker::endVisit(InlineAssembly const& _inlineAssembly)
{
AssemblyViewPureChecker{
_inlineAssembly.dialect(),
_inlineAssembly.operations().nameRepository(),
[&](StateMutability _mutability, SourceLocation const& _location) { reportMutability(_mutability, _location); }
}(_inlineAssembly.operations());
}(_inlineAssembly.operations().block());
}

void ViewPureChecker::reportMutability(
Expand Down
16 changes: 16 additions & 0 deletions libsolidity/ast/AST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <libsolidity/ast/TypeProvider.h>
#include <libsolutil/FunctionSelector.h>
#include <libsolutil/Keccak256.h>
#include <libyul/YulName.h>

#include <range/v3/range/conversion.hpp>
#include <range/v3/view/tail.hpp>
Expand All @@ -38,6 +39,7 @@

#include <functional>
#include <utility>
#include <memory>

using namespace solidity;
using namespace solidity::frontend;
Expand Down Expand Up @@ -1060,6 +1062,20 @@ TryCatchClause const* TryStatement::fallbackClause() const {
return findClause(m_clauses);
}

InlineAssembly::InlineAssembly(
int64_t _id,
SourceLocation const& _location,
ASTPointer<ASTString> const& _docString,
ASTPointer<std::vector<ASTPointer<ASTString>>> _flags,
std::shared_ptr<yul::AST> _operations
):
Statement(_id, _location, _docString),
m_flags(std::move(_flags)),
m_operations(std::move(_operations))
{}

InlineAssembly::~InlineAssembly() = default;

/// Experimental Solidity nodes
/// @{
TypeClassDefinitionAnnotation& TypeClassDefinition::annotation() const
Expand Down
21 changes: 7 additions & 14 deletions libsolidity/ast/AST.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@
namespace solidity::yul
{
// Forward-declaration to <yul/AST.h>
struct Block;
struct Dialect;
class AST;
class YulNameRepository;
}

namespace solidity::frontend
Expand Down Expand Up @@ -1567,28 +1567,21 @@ class InlineAssembly: public Statement
int64_t _id,
SourceLocation const& _location,
ASTPointer<ASTString> const& _docString,
yul::Dialect const& _dialect,
ASTPointer<std::vector<ASTPointer<ASTString>>> _flags,
std::shared_ptr<yul::Block> _operations
):
Statement(_id, _location, _docString),
m_dialect(_dialect),
m_flags(std::move(_flags)),
m_operations(std::move(_operations))
{}
std::shared_ptr<yul::AST> _operations
);
~InlineAssembly() override;
void accept(ASTVisitor& _visitor) override;
void accept(ASTConstVisitor& _visitor) const override;

yul::Dialect const& dialect() const { return m_dialect; }
yul::Block const& operations() const { return *m_operations; }
yul::AST const& operations() const { return *m_operations; }
ASTPointer<std::vector<ASTPointer<ASTString>>> const& flags() const { return m_flags; }

InlineAssemblyAnnotation& annotation() const override;

private:
yul::Dialect const& m_dialect;
ASTPointer<std::vector<ASTPointer<ASTString>>> m_flags;
std::shared_ptr<yul::Block> m_operations;
std::shared_ptr<yul::AST> m_operations;
};

/**
Expand Down
6 changes: 3 additions & 3 deletions libsolidity/ast/ASTJsonExporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,7 @@ bool ASTJsonExporter::visit(InlineAssembly const& _node)
for (auto const& it: _node.annotation().externalReferences)
if (it.first)
externalReferences.emplace_back(std::make_pair(
it.first->name.str(),
_node.operations().nameRepository().requiredLabelOf(it.first->name),
inlineAssemblyIdentifierToJson(it)
));

Expand All @@ -665,9 +665,9 @@ bool ASTJsonExporter::visit(InlineAssembly const& _node)
externalReferencesJson.emplace_back(std::move(it));

std::vector<std::pair<std::string, Json>> attributes = {
std::make_pair("AST", Json(yul::AsmJsonConverter(sourceIndexFromLocation(_node.location()))(_node.operations()))),
std::make_pair("AST", Json(yul::AsmJsonConverter(sourceIndexFromLocation(_node.location()), _node.operations().nameRepository())(_node.operations().block()))),
std::make_pair("externalReferences", std::move(externalReferencesJson)),
std::make_pair("evmVersion", dynamic_cast<solidity::yul::EVMDialect const&>(_node.dialect()).evmVersion().name())
std::make_pair("evmVersion", dynamic_cast<solidity::yul::EVMDialect const&>(_node.operations().nameRepository().dialect()).evmVersion().name())
};

if (_node.flags())
Expand Down
Loading