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:
@@ -30,6 +30,7 @@
|
||||
#include <libsolidity/codegen/CompilerUtils.h>
|
||||
#include <libsolidity/codegen/ReturnInfo.h>
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
#include <libsolidity/ast/ASTUtils.h>
|
||||
|
||||
#include <libevmasm/GasMeter.h>
|
||||
|
||||
@@ -68,43 +69,12 @@ struct CopyTranslate: public yul::ASTCopier
|
||||
|
||||
yul::Expression operator()(yul::Identifier const& _identifier) override
|
||||
{
|
||||
// The operator() function is only called in lvalue context. In rvalue context,
|
||||
// only translate(yul::Identifier) is called.
|
||||
if (m_references.count(&_identifier))
|
||||
{
|
||||
auto const& reference = m_references.at(&_identifier);
|
||||
auto const varDecl = dynamic_cast<VariableDeclaration const*>(reference.declaration);
|
||||
solUnimplementedAssert(varDecl, "");
|
||||
|
||||
if (reference.isOffset || reference.isSlot)
|
||||
{
|
||||
solAssert(reference.isOffset != reference.isSlot, "");
|
||||
|
||||
string value;
|
||||
if (varDecl->isStateVariable())
|
||||
value =
|
||||
reference.isSlot ?
|
||||
m_context.storageLocationOfStateVariable(*varDecl).first.str() :
|
||||
to_string(m_context.storageLocationOfStateVariable(*varDecl).second);
|
||||
else
|
||||
{
|
||||
solAssert(varDecl->isLocalVariable(), "");
|
||||
if (reference.isSlot)
|
||||
value = IRVariable{*varDecl}.part("slot").name();
|
||||
else if (varDecl->type()->isValueType())
|
||||
value = IRVariable{*varDecl}.part("offset").name();
|
||||
else
|
||||
{
|
||||
solAssert(!IRVariable{*varDecl}.hasPart("offset"), "");
|
||||
value = "0";
|
||||
}
|
||||
}
|
||||
|
||||
if (isdigit(value.front()))
|
||||
return yul::Literal{_identifier.location, yul::LiteralKind::Number, yul::YulString{value}, {}};
|
||||
else
|
||||
return yul::Identifier{_identifier.location, yul::YulString{value}};
|
||||
}
|
||||
}
|
||||
return ASTCopier::operator()(_identifier);
|
||||
return translateReference(_identifier);
|
||||
else
|
||||
return ASTCopier::operator()(_identifier);
|
||||
}
|
||||
|
||||
yul::YulString translateIdentifier(yul::YulString _name) override
|
||||
@@ -124,24 +94,114 @@ struct CopyTranslate: public yul::ASTCopier
|
||||
if (!m_references.count(&_identifier))
|
||||
return ASTCopier::translate(_identifier);
|
||||
|
||||
auto const& reference = m_references.at(&_identifier);
|
||||
auto const varDecl = dynamic_cast<VariableDeclaration const*>(reference.declaration);
|
||||
solUnimplementedAssert(varDecl, "");
|
||||
|
||||
solAssert(
|
||||
reference.isOffset == false && reference.isSlot == false,
|
||||
"Should not be called for offset/slot"
|
||||
);
|
||||
auto const& var = m_context.localVariable(*varDecl);
|
||||
solAssert(var.type().sizeOnStack() == 1, "");
|
||||
|
||||
return yul::Identifier{
|
||||
_identifier.location,
|
||||
yul::YulString{var.commaSeparatedList()}
|
||||
};
|
||||
yul::Expression translated = translateReference(_identifier);
|
||||
solAssert(holds_alternative<yul::Identifier>(translated), "");
|
||||
return get<yul::Identifier>(std::move(translated));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/// Translates a reference to a local variable, potentially including
|
||||
/// a suffix. Might return a literal, which causes this to be invalid in
|
||||
/// lvalue-context.
|
||||
yul::Expression translateReference(yul::Identifier const& _identifier)
|
||||
{
|
||||
auto const& reference = m_references.at(&_identifier);
|
||||
auto const varDecl = dynamic_cast<VariableDeclaration const*>(reference.declaration);
|
||||
solUnimplementedAssert(varDecl, "");
|
||||
string const& suffix = reference.suffix;
|
||||
|
||||
if (suffix.empty() && !varDecl->isStateVariable())
|
||||
{
|
||||
auto const& var = m_context.localVariable(*varDecl);
|
||||
solAssert(var.type().sizeOnStack() == 1, "");
|
||||
|
||||
return yul::Identifier{
|
||||
_identifier.location,
|
||||
yul::YulString{var.commaSeparatedList()}
|
||||
};
|
||||
}
|
||||
|
||||
string value;
|
||||
if (varDecl->isConstant())
|
||||
{
|
||||
VariableDeclaration const* variable = rootConstVariableDeclaration(*varDecl);
|
||||
solAssert(variable, "");
|
||||
|
||||
if (variable->value()->annotation().type->category() == Type::Category::RationalNumber)
|
||||
{
|
||||
u256 intValue = dynamic_cast<RationalNumberType const&>(*variable->value()->annotation().type).literalValue(nullptr);
|
||||
if (auto const* bytesType = dynamic_cast<FixedBytesType const*>(variable->type()))
|
||||
intValue <<= 256 - 8 * bytesType->numBytes();
|
||||
else
|
||||
solAssert(variable->type()->category() == Type::Category::Integer, "");
|
||||
value = intValue.str();
|
||||
}
|
||||
else if (auto const* literal = dynamic_cast<Literal const*>(variable->value().get()))
|
||||
{
|
||||
TypePointer type = literal->annotation().type;
|
||||
|
||||
switch (type->category())
|
||||
{
|
||||
case Type::Category::Bool:
|
||||
case Type::Category::Address:
|
||||
solAssert(type->category() == variable->annotation().type->category(), "");
|
||||
value = toCompactHexWithPrefix(type->literalValue(literal));
|
||||
break;
|
||||
case Type::Category::StringLiteral:
|
||||
{
|
||||
auto const& stringLiteral = dynamic_cast<StringLiteralType const&>(*type);
|
||||
solAssert(variable->type()->category() == Type::Category::FixedBytes, "");
|
||||
unsigned const numBytes = dynamic_cast<FixedBytesType const&>(*variable->type()).numBytes();
|
||||
solAssert(stringLiteral.value().size() <= numBytes, "");
|
||||
value = formatNumber(u256(h256(stringLiteral.value(), h256::AlignLeft)));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
solAssert(false, "");
|
||||
}
|
||||
}
|
||||
else
|
||||
solAssert(false, "Invalid constant in inline assembly.");
|
||||
}
|
||||
else if (varDecl->isStateVariable())
|
||||
{
|
||||
if (suffix == "slot")
|
||||
value = m_context.storageLocationOfStateVariable(*varDecl).first.str();
|
||||
else if (suffix == "offset")
|
||||
value = to_string(m_context.storageLocationOfStateVariable(*varDecl).second);
|
||||
else
|
||||
solAssert(false, "");
|
||||
}
|
||||
else if (varDecl->type()->dataStoredIn(DataLocation::Storage))
|
||||
{
|
||||
solAssert(suffix == "slot" || suffix == "offset", "");
|
||||
solAssert(varDecl->isLocalVariable(), "");
|
||||
if (suffix == "slot")
|
||||
value = IRVariable{*varDecl}.part("slot").name();
|
||||
else if (varDecl->type()->isValueType())
|
||||
value = IRVariable{*varDecl}.part("offset").name();
|
||||
else
|
||||
{
|
||||
solAssert(!IRVariable{*varDecl}.hasPart("offset"), "");
|
||||
value = "0";
|
||||
}
|
||||
}
|
||||
else if (varDecl->type()->dataStoredIn(DataLocation::CallData))
|
||||
{
|
||||
solAssert(suffix == "offset" || suffix == "length", "");
|
||||
value = IRVariable{*varDecl}.part(suffix).name();
|
||||
}
|
||||
else
|
||||
solAssert(false, "");
|
||||
|
||||
if (isdigit(value.front()))
|
||||
return yul::Literal{_identifier.location, yul::LiteralKind::Number, yul::YulString{value}, {}};
|
||||
else
|
||||
return yul::Identifier{_identifier.location, yul::YulString{value}};
|
||||
}
|
||||
|
||||
|
||||
yul::Dialect const& m_dialect;
|
||||
IRGenerationContext& m_context;
|
||||
ExternalRefsMap const& m_references;
|
||||
@@ -857,10 +917,8 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
{
|
||||
solAssert(!functionType->bound(), "");
|
||||
if (auto contractType = dynamic_cast<ContractType const*>(expressionType->actualType()))
|
||||
solUnimplementedAssert(
|
||||
!contractType->contractDefinition().isLibrary() || functionType->kind() == FunctionType::Kind::Internal,
|
||||
"Only internal function calls implemented for libraries"
|
||||
);
|
||||
if (contractType->contractDefinition().isLibrary())
|
||||
solAssert(functionType->kind() == FunctionType::Kind::Internal || functionType->kind() == FunctionType::Kind::DelegateCall, "");
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -2143,9 +2201,10 @@ void IRGeneratorForStatements::endVisit(Identifier const& _identifier)
|
||||
}
|
||||
else if (VariableDeclaration const* varDecl = dynamic_cast<VariableDeclaration const*>(declaration))
|
||||
handleVariableReference(*varDecl, _identifier);
|
||||
else if (dynamic_cast<ContractDefinition const*>(declaration))
|
||||
else if (auto const* contract = dynamic_cast<ContractDefinition const*>(declaration))
|
||||
{
|
||||
// no-op
|
||||
if (contract->isLibrary())
|
||||
define(IRVariable(_identifier).part("address")) << linkerSymbol(*contract) << "\n";
|
||||
}
|
||||
else if (dynamic_cast<EventDefinition const*>(declaration))
|
||||
{
|
||||
@@ -2965,3 +3024,9 @@ void IRGeneratorForStatements::setLocation(ASTNode const& _node)
|
||||
{
|
||||
m_currentLocation = _node.location();
|
||||
}
|
||||
|
||||
string IRGeneratorForStatements::linkerSymbol(ContractDefinition const& _library) const
|
||||
{
|
||||
solAssert(_library.isLibrary(), "");
|
||||
return "linkersymbol(" + util::escapeAndQuoteString(_library.fullyQualifiedName()) + ")";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user