mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #9189 from ethereum/simplifyResolver
Simplify inline assembly resolver.
This commit is contained in:
commit
8086ddd3bd
@ -668,17 +668,18 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
{
|
{
|
||||||
auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier);
|
auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier);
|
||||||
if (ref == _inlineAssembly.annotation().externalReferences.end())
|
if (ref == _inlineAssembly.annotation().externalReferences.end())
|
||||||
return numeric_limits<size_t>::max();
|
return false;
|
||||||
Declaration const* declaration = ref->second.declaration;
|
InlineAssemblyAnnotation::ExternalIdentifierInfo& identifierInfo = ref->second;
|
||||||
|
Declaration const* declaration = identifierInfo.declaration;
|
||||||
solAssert(!!declaration, "");
|
solAssert(!!declaration, "");
|
||||||
bool requiresStorage = ref->second.isSlot || ref->second.isOffset;
|
bool requiresStorage = identifierInfo.isSlot || identifierInfo.isOffset;
|
||||||
if (auto var = dynamic_cast<VariableDeclaration const*>(declaration))
|
if (auto var = dynamic_cast<VariableDeclaration const*>(declaration))
|
||||||
{
|
{
|
||||||
solAssert(var->type(), "Expected variable type!");
|
solAssert(var->type(), "Expected variable type!");
|
||||||
if (var->immutable())
|
if (var->immutable())
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(3773_error, _identifier.location, "Assembly access to immutable variables is not supported.");
|
m_errorReporter.typeError(3773_error, _identifier.location, "Assembly access to immutable variables is not supported.");
|
||||||
return numeric_limits<size_t>::max();
|
return false;
|
||||||
}
|
}
|
||||||
if (var->isConstant())
|
if (var->isConstant())
|
||||||
{
|
{
|
||||||
@ -687,17 +688,17 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
if (var && !var->value())
|
if (var && !var->value())
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(3224_error, _identifier.location, "Constant has no value.");
|
m_errorReporter.typeError(3224_error, _identifier.location, "Constant has no value.");
|
||||||
return numeric_limits<size_t>::max();
|
return false;
|
||||||
}
|
}
|
||||||
else if (_context == yul::IdentifierContext::LValue)
|
else if (_context == yul::IdentifierContext::LValue)
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(6252_error, _identifier.location, "Constant variables cannot be assigned to.");
|
m_errorReporter.typeError(6252_error, _identifier.location, "Constant variables cannot be assigned to.");
|
||||||
return numeric_limits<size_t>::max();
|
return false;
|
||||||
}
|
}
|
||||||
else if (requiresStorage)
|
else if (requiresStorage)
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(6617_error, _identifier.location, "The suffixes _offset and _slot can only be used on non-constant storage variables.");
|
m_errorReporter.typeError(6617_error, _identifier.location, "The suffixes _offset and _slot can only be used on non-constant storage variables.");
|
||||||
return numeric_limits<size_t>::max();
|
return false;
|
||||||
}
|
}
|
||||||
else if (var && var->value() && !var->value()->annotation().type && !dynamic_cast<Literal const*>(var->value().get()))
|
else if (var && var->value() && !var->value()->annotation().type && !dynamic_cast<Literal const*>(var->value().get()))
|
||||||
{
|
{
|
||||||
@ -706,7 +707,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
_identifier.location,
|
_identifier.location,
|
||||||
"Constant variables with non-literal values cannot be forward referenced from inline assembly."
|
"Constant variables with non-literal values cannot be forward referenced from inline assembly."
|
||||||
);
|
);
|
||||||
return size_t(-1);
|
return false;
|
||||||
}
|
}
|
||||||
else if (!var || !type(*var)->isValueType() || (
|
else if (!var || !type(*var)->isValueType() || (
|
||||||
!dynamic_cast<Literal const*>(var->value().get()) &&
|
!dynamic_cast<Literal const*>(var->value().get()) &&
|
||||||
@ -714,7 +715,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
))
|
))
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(7615_error, _identifier.location, "Only direct number constants and references to such constants are supported by inline assembly.");
|
m_errorReporter.typeError(7615_error, _identifier.location, "Only direct number constants and references to such constants are supported by inline assembly.");
|
||||||
return size_t(-1);
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -725,33 +726,33 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
if (!var->isStateVariable() && !var->type()->dataStoredIn(DataLocation::Storage))
|
if (!var->isStateVariable() && !var->type()->dataStoredIn(DataLocation::Storage))
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(3622_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
|
m_errorReporter.typeError(3622_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
|
||||||
return numeric_limits<size_t>::max();
|
return false;
|
||||||
}
|
}
|
||||||
else if (_context == yul::IdentifierContext::LValue)
|
else if (_context == yul::IdentifierContext::LValue)
|
||||||
{
|
{
|
||||||
if (var->isStateVariable())
|
if (var->isStateVariable())
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(4713_error, _identifier.location, "State variables cannot be assigned to - you have to use \"sstore()\".");
|
m_errorReporter.typeError(4713_error, _identifier.location, "State variables cannot be assigned to - you have to use \"sstore()\".");
|
||||||
return numeric_limits<size_t>::max();
|
return false;
|
||||||
}
|
}
|
||||||
else if (ref->second.isOffset)
|
else if (identifierInfo.isOffset)
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(9739_error, _identifier.location, "Only _slot can be assigned to.");
|
m_errorReporter.typeError(9739_error, _identifier.location, "Only _slot can be assigned to.");
|
||||||
return numeric_limits<size_t>::max();
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
solAssert(ref->second.isSlot, "");
|
solAssert(identifierInfo.isSlot, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!var->isConstant() && var->isStateVariable())
|
else if (!var->isConstant() && var->isStateVariable())
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(1408_error, _identifier.location, "Only local variables are supported. To access storage variables, use the _slot and _offset suffixes.");
|
m_errorReporter.typeError(1408_error, _identifier.location, "Only local variables are supported. To access storage variables, use the _slot and _offset suffixes.");
|
||||||
return numeric_limits<size_t>::max();
|
return false;
|
||||||
}
|
}
|
||||||
else if (var->type()->dataStoredIn(DataLocation::Storage))
|
else if (var->type()->dataStoredIn(DataLocation::Storage))
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(9068_error, _identifier.location, "You have to use the _slot or _offset suffix to access storage reference variables.");
|
m_errorReporter.typeError(9068_error, _identifier.location, "You have to use the _slot or _offset suffix to access storage reference variables.");
|
||||||
return numeric_limits<size_t>::max();
|
return false;
|
||||||
}
|
}
|
||||||
else if (var->type()->sizeOnStack() != 1)
|
else if (var->type()->sizeOnStack() != 1)
|
||||||
{
|
{
|
||||||
@ -759,21 +760,21 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
m_errorReporter.typeError(2370_error, _identifier.location, "Call data elements cannot be accessed directly. Copy to a local variable first or use \"calldataload\" or \"calldatacopy\" with manually determined offsets and sizes.");
|
m_errorReporter.typeError(2370_error, _identifier.location, "Call data elements cannot be accessed directly. Copy to a local variable first or use \"calldataload\" or \"calldatacopy\" with manually determined offsets and sizes.");
|
||||||
else
|
else
|
||||||
m_errorReporter.typeError(9857_error, _identifier.location, "Only types that use one stack slot are supported.");
|
m_errorReporter.typeError(9857_error, _identifier.location, "Only types that use one stack slot are supported.");
|
||||||
return numeric_limits<size_t>::max();
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (requiresStorage)
|
else if (requiresStorage)
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(7944_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
|
m_errorReporter.typeError(7944_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
|
||||||
return numeric_limits<size_t>::max();
|
return false;
|
||||||
}
|
}
|
||||||
else if (_context == yul::IdentifierContext::LValue)
|
else if (_context == yul::IdentifierContext::LValue)
|
||||||
{
|
{
|
||||||
if (dynamic_cast<MagicVariableDeclaration const*>(declaration))
|
if (dynamic_cast<MagicVariableDeclaration const*>(declaration))
|
||||||
return numeric_limits<size_t>::max();
|
return false;
|
||||||
|
|
||||||
m_errorReporter.typeError(1990_error, _identifier.location, "Only local variables can be assigned to in inline assembly.");
|
m_errorReporter.typeError(1990_error, _identifier.location, "Only local variables can be assigned to in inline assembly.");
|
||||||
return numeric_limits<size_t>::max();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_context == yul::IdentifierContext::RValue)
|
if (_context == yul::IdentifierContext::RValue)
|
||||||
@ -782,7 +783,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
if (dynamic_cast<FunctionDefinition const*>(declaration))
|
if (dynamic_cast<FunctionDefinition const*>(declaration))
|
||||||
{
|
{
|
||||||
m_errorReporter.declarationError(2025_error, _identifier.location, "Access to functions is not allowed in inline assembly.");
|
m_errorReporter.declarationError(2025_error, _identifier.location, "Access to functions is not allowed in inline assembly.");
|
||||||
return numeric_limits<size_t>::max();
|
return false;
|
||||||
}
|
}
|
||||||
else if (dynamic_cast<VariableDeclaration const*>(declaration))
|
else if (dynamic_cast<VariableDeclaration const*>(declaration))
|
||||||
{
|
{
|
||||||
@ -792,14 +793,14 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
if (!contract->isLibrary())
|
if (!contract->isLibrary())
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(4977_error, _identifier.location, "Expected a library.");
|
m_errorReporter.typeError(4977_error, _identifier.location, "Expected a library.");
|
||||||
return numeric_limits<size_t>::max();
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return numeric_limits<size_t>::max();
|
return false;
|
||||||
}
|
}
|
||||||
ref->second.valueSize = 1;
|
identifierInfo.valueSize = 1;
|
||||||
return size_t(1);
|
return true;
|
||||||
};
|
};
|
||||||
solAssert(!_inlineAssembly.annotation().analysisInfo, "");
|
solAssert(!_inlineAssembly.annotation().analysisInfo, "");
|
||||||
_inlineAssembly.annotation().analysisInfo = make_shared<yul::AsmAnalysisInfo>();
|
_inlineAssembly.annotation().analysisInfo = make_shared<yul::AsmAnalysisInfo>();
|
||||||
|
@ -384,12 +384,11 @@ void CompilerContext::appendInlineAssembly(
|
|||||||
yul::Identifier const& _identifier,
|
yul::Identifier const& _identifier,
|
||||||
yul::IdentifierContext,
|
yul::IdentifierContext,
|
||||||
bool _insideFunction
|
bool _insideFunction
|
||||||
) -> size_t
|
) -> bool
|
||||||
{
|
{
|
||||||
if (_insideFunction)
|
if (_insideFunction)
|
||||||
return numeric_limits<size_t>::max();
|
return false;
|
||||||
auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name.str());
|
return contains(_localVariables, _identifier.name.str());
|
||||||
return it == _localVariables.end() ? numeric_limits<size_t>::max() : 1;
|
|
||||||
};
|
};
|
||||||
identifierAccess.generateCode = [&](
|
identifierAccess.generateCode = [&](
|
||||||
yul::Identifier const& _identifier,
|
yul::Identifier const& _identifier,
|
||||||
|
@ -132,17 +132,11 @@ vector<YulString> AsmAnalyzer::operator()(Identifier const& _identifier)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = m_resolver && m_resolver(
|
||||||
if (m_resolver)
|
_identifier,
|
||||||
{
|
yul::IdentifierContext::RValue,
|
||||||
bool insideFunction = m_currentScope->insideFunction();
|
m_currentScope->insideFunction()
|
||||||
size_t stackSize = m_resolver(_identifier, yul::IdentifierContext::RValue, insideFunction);
|
);
|
||||||
if (stackSize != numeric_limits<size_t>::max())
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
yulAssert(stackSize == 1, "Invalid stack size of external reference.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found && watcher.ok())
|
if (!found && watcher.ok())
|
||||||
// Only add an error message if the callback did not do it.
|
// Only add an error message if the callback did not do it.
|
||||||
m_errorReporter.declarationError(8198_error, _identifier.location, "Identifier not found.");
|
m_errorReporter.declarationError(8198_error, _identifier.location, "Identifier not found.");
|
||||||
@ -478,12 +472,10 @@ void AsmAnalyzer::checkAssignment(Identifier const& _variable, YulString _valueT
|
|||||||
else if (m_resolver)
|
else if (m_resolver)
|
||||||
{
|
{
|
||||||
bool insideFunction = m_currentScope->insideFunction();
|
bool insideFunction = m_currentScope->insideFunction();
|
||||||
size_t variableSize = m_resolver(_variable, yul::IdentifierContext::LValue, insideFunction);
|
if (m_resolver(_variable, yul::IdentifierContext::LValue, insideFunction))
|
||||||
if (variableSize != numeric_limits<size_t>::max())
|
|
||||||
{
|
{
|
||||||
found = true;
|
found = true;
|
||||||
variableType = &m_dialect.defaultType;
|
variableType = &m_dialect.defaultType;
|
||||||
yulAssert(variableSize == 1, "Invalid stack size of external reference.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ enum class IdentifierContext { LValue, RValue, VariableDeclaration };
|
|||||||
/// to inline assembly (not used in standalone assembly mode).
|
/// to inline assembly (not used in standalone assembly mode).
|
||||||
struct ExternalIdentifierAccess
|
struct ExternalIdentifierAccess
|
||||||
{
|
{
|
||||||
using Resolver = std::function<size_t(Identifier const&, IdentifierContext, bool /*_crossesFunctionBoundary*/)>;
|
using Resolver = std::function<bool(Identifier const&, IdentifierContext, bool /*_crossesFunctionBoundary*/)>;
|
||||||
/// Resolve an external reference given by the identifier in the given context.
|
/// Resolve an external reference given by the identifier in the given context.
|
||||||
/// @returns the size of the value (number of stack slots) or size_t(-1) if not found.
|
/// @returns the size of the value (number of stack slots) or size_t(-1) if not found.
|
||||||
Resolver resolve;
|
Resolver resolve;
|
||||||
|
Loading…
Reference in New Issue
Block a user