Assembly: Revive warning on not-yet-available EVM instructions in (strict) inline assembly.

This commit is contained in:
Christian Parpart 2019-09-18 11:36:20 +02:00 committed by Christian Parpart
parent 044eb2d161
commit a6e34bd441
3 changed files with 47 additions and 4 deletions

View File

@ -337,7 +337,8 @@ bool AsmAnalyzer::operator()(FunctionCall const& _funCall)
} }
))) )))
{ {
m_errorReporter.declarationError(_funCall.functionName.location, "Function not found."); if (!warnOnInstructions(_funCall.functionName.name.str(), _funCall.functionName.location))
m_errorReporter.declarationError(_funCall.functionName.location, "Function not found.");
success = false; success = false;
} }
if (success) if (success)
@ -653,7 +654,39 @@ void AsmAnalyzer::expectValidType(string const& type, SourceLocation const& _loc
); );
} }
void AsmAnalyzer::warnOnInstructions(dev::eth::Instruction _instr, SourceLocation const& _location) // FIXME: copy'n'paste from AsmParser. make it more general (by putting it into dev::eth namespace)
std::map<string, dev::eth::Instruction> const& instructions()
{
// Allowed instructions, lowercase names.
static map<string, dev::eth::Instruction> s_instructions;
if (s_instructions.empty())
{
for (auto const& instruction: dev::eth::c_instructions)
{
if (
instruction.second == dev::eth::Instruction::JUMPDEST ||
dev::eth::isPushInstruction(instruction.second)
)
continue;
string name = instruction.first;
transform(name.begin(), name.end(), name.begin(), [](unsigned char _c) { return tolower(_c); });
s_instructions[name] = instruction.second;
}
}
return s_instructions;
}
bool AsmAnalyzer::warnOnInstructions(std::string const& _instructionIdentifier, langutil::SourceLocation const& _location)
{
auto const& instructionMap = instructions();
auto const identifier = boost::to_lower_copy(_instructionIdentifier);
if (auto const i = instructionMap.find(identifier); i != instructionMap.end())
return warnOnInstructions(i->second, _location);
else
return false;
}
bool AsmAnalyzer::warnOnInstructions(dev::eth::Instruction _instr, SourceLocation const& _location)
{ {
// We assume that returndatacopy, returndatasize and staticcall are either all available // We assume that returndatacopy, returndatasize and staticcall are either all available
// or all not available. // or all not available.
@ -725,4 +758,8 @@ void AsmAnalyzer::warnOnInstructions(dev::eth::Instruction _instr, SourceLocatio
"Use functions, \"switch\", \"if\" or \"for\" statements instead." "Use functions, \"switch\", \"if\" or \"for\" statements instead."
); );
} }
else
return false;
return true;
} }

View File

@ -106,7 +106,8 @@ private:
Scope& scope(Block const* _block); Scope& scope(Block const* _block);
void expectValidType(std::string const& type, langutil::SourceLocation const& _location); void expectValidType(std::string const& type, langutil::SourceLocation const& _location);
void warnOnInstructions(dev::eth::Instruction _instr, langutil::SourceLocation const& _location); bool warnOnInstructions(dev::eth::Instruction _instr, langutil::SourceLocation const& _location);
bool warnOnInstructions(std::string const& _instrIdentifier, langutil::SourceLocation const& _location);
int m_stackHeight = 0; int m_stackHeight = 0;
yul::ExternalIdentifierAccess::Resolver m_resolver; yul::ExternalIdentifierAccess::Resolver m_resolver;

View File

@ -321,7 +321,12 @@ Parser::ElementaryOperation Parser::parseElementaryOperation()
{ {
Identifier identifier{location(), literal}; Identifier identifier{location(), literal};
advance(); advance();
return FunctionCall{identifier.location, identifier, {}}; if (m_scanner->currentToken() == Token::LParen)
return FunctionCall{identifier.location, identifier, {}};
else if (instructions().count(identifier.name.str()))
m_errorReporter.syntaxError(identifier.location, "Instructions must be invoked function style. Expecting an '(' after the instruction.");
else
m_errorReporter.syntaxError(identifier.location, "Invalid identifier.");
} }
else else
ret = Identifier{location(), literal}; ret = Identifier{location(), literal};