mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #9776 from ethereum/reportUnimplemented
Sol->Yul: Report source locations related to unimplemented features.
This commit is contained in:
@@ -164,7 +164,7 @@ string IRGenerator::generate(
|
||||
string IRGenerator::generate(Block const& _block)
|
||||
{
|
||||
IRGeneratorForStatements generator(m_context, m_utils);
|
||||
_block.accept(generator);
|
||||
generator.generate(_block);
|
||||
return generator.code();
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
#include <libyul/Dialect.h>
|
||||
#include <libyul/optimiser/ASTCopier.h>
|
||||
|
||||
#include <liblangutil/Exceptions.h>
|
||||
|
||||
#include <libsolutil/Whiskers.h>
|
||||
#include <libsolutil/StringUtils.h>
|
||||
#include <libsolutil/Keccak256.h>
|
||||
@@ -152,70 +154,130 @@ string IRGeneratorForStatements::code() const
|
||||
return m_code.str();
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::generate(Block const& _block)
|
||||
{
|
||||
try
|
||||
{
|
||||
_block.accept(*this);
|
||||
}
|
||||
catch (langutil::UnimplementedFeatureError const& _error)
|
||||
{
|
||||
if (!boost::get_error_info<langutil::errinfo_sourceLocation>(_error))
|
||||
_error << langutil::errinfo_sourceLocation(m_currentLocation);
|
||||
throw _error;
|
||||
}
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::initializeStateVar(VariableDeclaration const& _varDecl)
|
||||
{
|
||||
solAssert(_varDecl.immutable() || m_context.isStateVariable(_varDecl), "Must be immutable or a state variable.");
|
||||
solAssert(!_varDecl.isConstant(), "");
|
||||
if (!_varDecl.value())
|
||||
return;
|
||||
try
|
||||
{
|
||||
setLocation(_varDecl);
|
||||
|
||||
_varDecl.value()->accept(*this);
|
||||
writeToLValue(
|
||||
_varDecl.immutable() ?
|
||||
IRLValue{*_varDecl.annotation().type, IRLValue::Immutable{&_varDecl}} :
|
||||
IRLValue{*_varDecl.annotation().type, IRLValue::Storage{
|
||||
util::toCompactHexWithPrefix(m_context.storageLocationOfStateVariable(_varDecl).first),
|
||||
m_context.storageLocationOfStateVariable(_varDecl).second
|
||||
}},
|
||||
*_varDecl.value()
|
||||
);
|
||||
solAssert(_varDecl.immutable() || m_context.isStateVariable(_varDecl), "Must be immutable or a state variable.");
|
||||
solAssert(!_varDecl.isConstant(), "");
|
||||
if (!_varDecl.value())
|
||||
return;
|
||||
|
||||
_varDecl.value()->accept(*this);
|
||||
writeToLValue(
|
||||
_varDecl.immutable() ?
|
||||
IRLValue{*_varDecl.annotation().type, IRLValue::Immutable{&_varDecl}} :
|
||||
IRLValue{*_varDecl.annotation().type, IRLValue::Storage{
|
||||
util::toCompactHexWithPrefix(m_context.storageLocationOfStateVariable(_varDecl).first),
|
||||
m_context.storageLocationOfStateVariable(_varDecl).second
|
||||
}},
|
||||
*_varDecl.value()
|
||||
);
|
||||
}
|
||||
catch (langutil::UnimplementedFeatureError const& _error)
|
||||
{
|
||||
if (!boost::get_error_info<langutil::errinfo_sourceLocation>(_error))
|
||||
_error << langutil::errinfo_sourceLocation(m_currentLocation);
|
||||
throw _error;
|
||||
}
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::initializeLocalVar(VariableDeclaration const& _varDecl)
|
||||
{
|
||||
solAssert(m_context.isLocalVariable(_varDecl), "Must be a local variable.");
|
||||
try
|
||||
{
|
||||
setLocation(_varDecl);
|
||||
|
||||
auto const* type = _varDecl.type();
|
||||
if (auto const* refType = dynamic_cast<ReferenceType const*>(type))
|
||||
if (refType->dataStoredIn(DataLocation::Storage) && refType->isPointer())
|
||||
return;
|
||||
solAssert(m_context.isLocalVariable(_varDecl), "Must be a local variable.");
|
||||
|
||||
IRVariable zero = zeroValue(*type);
|
||||
assign(m_context.localVariable(_varDecl), zero);
|
||||
auto const* type = _varDecl.type();
|
||||
if (auto const* refType = dynamic_cast<ReferenceType const*>(type))
|
||||
if (refType->dataStoredIn(DataLocation::Storage) && refType->isPointer())
|
||||
return;
|
||||
|
||||
IRVariable zero = zeroValue(*type);
|
||||
assign(m_context.localVariable(_varDecl), zero);
|
||||
}
|
||||
catch (langutil::UnimplementedFeatureError const& _error)
|
||||
{
|
||||
if (!boost::get_error_info<langutil::errinfo_sourceLocation>(_error))
|
||||
_error << langutil::errinfo_sourceLocation(m_currentLocation);
|
||||
throw _error;
|
||||
}
|
||||
}
|
||||
|
||||
IRVariable IRGeneratorForStatements::evaluateExpression(Expression const& _expression, Type const& _targetType)
|
||||
{
|
||||
_expression.accept(*this);
|
||||
IRVariable variable{m_context.newYulVariable(), _targetType};
|
||||
define(variable, _expression);
|
||||
return variable;
|
||||
try
|
||||
{
|
||||
setLocation(_expression);
|
||||
|
||||
_expression.accept(*this);
|
||||
IRVariable variable{m_context.newYulVariable(), _targetType};
|
||||
define(variable, _expression);
|
||||
return variable;
|
||||
}
|
||||
catch (langutil::UnimplementedFeatureError const& _error)
|
||||
{
|
||||
if (!boost::get_error_info<langutil::errinfo_sourceLocation>(_error))
|
||||
_error << langutil::errinfo_sourceLocation(m_currentLocation);
|
||||
throw _error;
|
||||
}
|
||||
}
|
||||
|
||||
string IRGeneratorForStatements::constantValueFunction(VariableDeclaration const& _constant)
|
||||
{
|
||||
string functionName = IRNames::constantValueFunction(_constant);
|
||||
return m_context.functionCollector().createFunction(functionName, [&] {
|
||||
Whiskers templ(R"(
|
||||
function <functionName>() -> <ret> {
|
||||
<code>
|
||||
<ret> := <value>
|
||||
}
|
||||
)");
|
||||
templ("functionName", functionName);
|
||||
IRGeneratorForStatements generator(m_context, m_utils);
|
||||
solAssert(_constant.value(), "");
|
||||
Type const& constantType = *_constant.type();
|
||||
templ("value", generator.evaluateExpression(*_constant.value(), constantType).commaSeparatedList());
|
||||
templ("code", generator.code());
|
||||
templ("ret", IRVariable("ret", constantType).commaSeparatedList());
|
||||
try
|
||||
{
|
||||
setLocation(_constant);
|
||||
|
||||
return templ.render();
|
||||
});
|
||||
string functionName = IRNames::constantValueFunction(_constant);
|
||||
return m_context.functionCollector().createFunction(functionName, [&] {
|
||||
Whiskers templ(R"(
|
||||
function <functionName>() -> <ret> {
|
||||
<code>
|
||||
<ret> := <value>
|
||||
}
|
||||
)");
|
||||
templ("functionName", functionName);
|
||||
IRGeneratorForStatements generator(m_context, m_utils);
|
||||
solAssert(_constant.value(), "");
|
||||
Type const& constantType = *_constant.type();
|
||||
templ("value", generator.evaluateExpression(*_constant.value(), constantType).commaSeparatedList());
|
||||
templ("code", generator.code());
|
||||
templ("ret", IRVariable("ret", constantType).commaSeparatedList());
|
||||
|
||||
return templ.render();
|
||||
});
|
||||
}
|
||||
catch (langutil::UnimplementedFeatureError const& _error)
|
||||
{
|
||||
if (!boost::get_error_info<langutil::errinfo_sourceLocation>(_error))
|
||||
_error << langutil::errinfo_sourceLocation(m_currentLocation);
|
||||
throw _error;
|
||||
}
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::endVisit(VariableDeclarationStatement const& _varDeclStatement)
|
||||
{
|
||||
setLocation(_varDeclStatement);
|
||||
|
||||
if (Expression const* expression = _varDeclStatement.initialValue())
|
||||
{
|
||||
if (_varDeclStatement.declarations().size() > 1)
|
||||
@@ -249,14 +311,22 @@ bool IRGeneratorForStatements::visit(Conditional const& _conditional)
|
||||
{
|
||||
_conditional.condition().accept(*this);
|
||||
|
||||
setLocation(_conditional);
|
||||
|
||||
string condition = expressionAsType(_conditional.condition(), *TypeProvider::boolean());
|
||||
declare(_conditional);
|
||||
|
||||
m_code << "switch " << condition << "\n" "case 0 {\n";
|
||||
|
||||
_conditional.falseExpression().accept(*this);
|
||||
setLocation(_conditional);
|
||||
|
||||
assign(_conditional, _conditional.falseExpression());
|
||||
m_code << "}\n" "default {\n";
|
||||
|
||||
_conditional.trueExpression().accept(*this);
|
||||
setLocation(_conditional);
|
||||
|
||||
assign(_conditional, _conditional.trueExpression());
|
||||
m_code << "}\n";
|
||||
|
||||
@@ -266,6 +336,7 @@ bool IRGeneratorForStatements::visit(Conditional const& _conditional)
|
||||
bool IRGeneratorForStatements::visit(Assignment const& _assignment)
|
||||
{
|
||||
_assignment.rightHandSide().accept(*this);
|
||||
setLocation(_assignment);
|
||||
|
||||
Token assignmentOperator = _assignment.assignmentOperator();
|
||||
Token binaryOperator =
|
||||
@@ -283,6 +354,7 @@ bool IRGeneratorForStatements::visit(Assignment const& _assignment)
|
||||
IRVariable value = convert(_assignment.rightHandSide(), *rightIntermediateType);
|
||||
_assignment.leftHandSide().accept(*this);
|
||||
solAssert(!!m_currentLValue, "LValue not retrieved.");
|
||||
setLocation(_assignment);
|
||||
|
||||
if (assignmentOperator != Token::Assign)
|
||||
{
|
||||
@@ -323,6 +395,8 @@ bool IRGeneratorForStatements::visit(Assignment const& _assignment)
|
||||
|
||||
bool IRGeneratorForStatements::visit(TupleExpression const& _tuple)
|
||||
{
|
||||
setLocation(_tuple);
|
||||
|
||||
if (_tuple.isInlineArray())
|
||||
{
|
||||
auto const& arrayType = dynamic_cast<ArrayType const&>(*_tuple.annotation().type);
|
||||
@@ -339,6 +413,7 @@ bool IRGeneratorForStatements::visit(TupleExpression const& _tuple)
|
||||
{
|
||||
Expression const& component = *_tuple.components()[i];
|
||||
component.accept(*this);
|
||||
setLocation(_tuple);
|
||||
IRVariable converted = convert(component, baseType);
|
||||
m_code <<
|
||||
m_utils.writeToMemoryFunction(baseType) <<
|
||||
@@ -358,6 +433,7 @@ bool IRGeneratorForStatements::visit(TupleExpression const& _tuple)
|
||||
{
|
||||
solAssert(_tuple.components().front(), "");
|
||||
_tuple.components().front()->accept(*this);
|
||||
setLocation(_tuple);
|
||||
if (willBeWrittenTo)
|
||||
solAssert(!!m_currentLValue, "");
|
||||
else
|
||||
@@ -370,6 +446,7 @@ bool IRGeneratorForStatements::visit(TupleExpression const& _tuple)
|
||||
if (auto const& component = _tuple.components()[i])
|
||||
{
|
||||
component->accept(*this);
|
||||
setLocation(_tuple);
|
||||
if (willBeWrittenTo)
|
||||
{
|
||||
solAssert(!!m_currentLValue, "");
|
||||
@@ -395,17 +472,20 @@ bool IRGeneratorForStatements::visit(TupleExpression const& _tuple)
|
||||
bool IRGeneratorForStatements::visit(IfStatement const& _ifStatement)
|
||||
{
|
||||
_ifStatement.condition().accept(*this);
|
||||
setLocation(_ifStatement);
|
||||
string condition = expressionAsType(_ifStatement.condition(), *TypeProvider::boolean());
|
||||
|
||||
if (_ifStatement.falseStatement())
|
||||
{
|
||||
m_code << "switch " << condition << "\n" "case 0 {\n";
|
||||
_ifStatement.falseStatement()->accept(*this);
|
||||
setLocation(_ifStatement);
|
||||
m_code << "}\n" "default {\n";
|
||||
}
|
||||
else
|
||||
m_code << "if " << condition << " {\n";
|
||||
_ifStatement.trueStatement().accept(*this);
|
||||
setLocation(_ifStatement);
|
||||
m_code << "}\n";
|
||||
|
||||
return false;
|
||||
@@ -413,6 +493,7 @@ bool IRGeneratorForStatements::visit(IfStatement const& _ifStatement)
|
||||
|
||||
bool IRGeneratorForStatements::visit(ForStatement const& _forStatement)
|
||||
{
|
||||
setLocation(_forStatement);
|
||||
generateLoop(
|
||||
_forStatement.body(),
|
||||
_forStatement.condition(),
|
||||
@@ -425,6 +506,7 @@ bool IRGeneratorForStatements::visit(ForStatement const& _forStatement)
|
||||
|
||||
bool IRGeneratorForStatements::visit(WhileStatement const& _whileStatement)
|
||||
{
|
||||
setLocation(_whileStatement);
|
||||
generateLoop(
|
||||
_whileStatement.body(),
|
||||
&_whileStatement.condition(),
|
||||
@@ -436,20 +518,23 @@ bool IRGeneratorForStatements::visit(WhileStatement const& _whileStatement)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IRGeneratorForStatements::visit(Continue const&)
|
||||
bool IRGeneratorForStatements::visit(Continue const& _continue)
|
||||
{
|
||||
setLocation(_continue);
|
||||
m_code << "continue\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IRGeneratorForStatements::visit(Break const&)
|
||||
bool IRGeneratorForStatements::visit(Break const& _break)
|
||||
{
|
||||
setLocation(_break);
|
||||
m_code << "break\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::endVisit(Return const& _return)
|
||||
{
|
||||
setLocation(_return);
|
||||
if (Expression const* value = _return.expression())
|
||||
{
|
||||
solAssert(_return.annotation().functionReturnParameters, "Invalid return parameters pointer.");
|
||||
@@ -466,6 +551,7 @@ void IRGeneratorForStatements::endVisit(Return const& _return)
|
||||
|
||||
void IRGeneratorForStatements::endVisit(UnaryOperation const& _unaryOperation)
|
||||
{
|
||||
setLocation(_unaryOperation);
|
||||
Type const& resultType = type(_unaryOperation);
|
||||
Token const op = _unaryOperation.getOperator();
|
||||
|
||||
@@ -551,6 +637,8 @@ void IRGeneratorForStatements::endVisit(UnaryOperation const& _unaryOperation)
|
||||
|
||||
bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
|
||||
{
|
||||
setLocation(_binOp);
|
||||
|
||||
solAssert(!!_binOp.annotation().commonType, "");
|
||||
TypePointer commonType = _binOp.annotation().commonType;
|
||||
langutil::Token op = _binOp.getOperator();
|
||||
@@ -570,6 +658,7 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
|
||||
|
||||
_binOp.leftExpression().accept(*this);
|
||||
_binOp.rightExpression().accept(*this);
|
||||
setLocation(_binOp);
|
||||
|
||||
if (TokenTraits::isCompareOp(op))
|
||||
{
|
||||
@@ -629,6 +718,7 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
|
||||
|
||||
bool IRGeneratorForStatements::visit(FunctionCall const& _functionCall)
|
||||
{
|
||||
setLocation(_functionCall);
|
||||
FunctionTypePointer functionType = dynamic_cast<FunctionType const*>(&type(_functionCall.expression()));
|
||||
if (
|
||||
functionType &&
|
||||
@@ -643,6 +733,7 @@ bool IRGeneratorForStatements::visit(FunctionCall const& _functionCall)
|
||||
|
||||
void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
{
|
||||
setLocation(_functionCall);
|
||||
auto functionCallKind = *_functionCall.annotation().kind;
|
||||
|
||||
if (functionCallKind == FunctionCallKind::TypeConversion)
|
||||
@@ -1360,6 +1451,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
|
||||
void IRGeneratorForStatements::endVisit(FunctionCallOptions const& _options)
|
||||
{
|
||||
setLocation(_options);
|
||||
FunctionType const& previousType = dynamic_cast<FunctionType const&>(*_options.expression().annotation().type);
|
||||
|
||||
solUnimplementedAssert(!previousType.bound(), "");
|
||||
@@ -1379,6 +1471,7 @@ void IRGeneratorForStatements::endVisit(FunctionCallOptions const& _options)
|
||||
|
||||
void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
||||
{
|
||||
setLocation(_memberAccess);
|
||||
ASTString const& member = _memberAccess.memberName();
|
||||
auto memberFunctionType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type);
|
||||
Type::Category objectCategory = _memberAccess.expression().annotation().type->category();
|
||||
@@ -1764,6 +1857,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
||||
|
||||
bool IRGeneratorForStatements::visit(InlineAssembly const& _inlineAsm)
|
||||
{
|
||||
setLocation(_inlineAsm);
|
||||
CopyTranslate bodyCopier{_inlineAsm.dialect(), m_context, _inlineAsm.annotation().externalReferences};
|
||||
|
||||
yul::Statement modified = bodyCopier(_inlineAsm.operations());
|
||||
@@ -1778,6 +1872,7 @@ bool IRGeneratorForStatements::visit(InlineAssembly const& _inlineAsm)
|
||||
|
||||
void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess)
|
||||
{
|
||||
setLocation(_indexAccess);
|
||||
Type const& baseType = *_indexAccess.baseExpression().annotation().type;
|
||||
|
||||
if (baseType.category() == Type::Category::Mapping)
|
||||
@@ -1913,6 +2008,7 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess)
|
||||
|
||||
void IRGeneratorForStatements::endVisit(IndexRangeAccess const& _indexRangeAccess)
|
||||
{
|
||||
setLocation(_indexRangeAccess);
|
||||
Type const& baseType = *_indexRangeAccess.baseExpression().annotation().type;
|
||||
solAssert(
|
||||
baseType.category() == Type::Category::Array || baseType.category() == Type::Category::ArraySlice,
|
||||
@@ -1959,6 +2055,7 @@ void IRGeneratorForStatements::endVisit(IndexRangeAccess const& _indexRangeAcces
|
||||
|
||||
void IRGeneratorForStatements::endVisit(Identifier const& _identifier)
|
||||
{
|
||||
setLocation(_identifier);
|
||||
Declaration const* declaration = _identifier.annotation().referencedDeclaration;
|
||||
if (MagicVariableDeclaration const* magicVar = dynamic_cast<MagicVariableDeclaration const*>(declaration))
|
||||
{
|
||||
@@ -2017,6 +2114,7 @@ void IRGeneratorForStatements::endVisit(Identifier const& _identifier)
|
||||
|
||||
bool IRGeneratorForStatements::visit(Literal const& _literal)
|
||||
{
|
||||
setLocation(_literal);
|
||||
Type const& literalType = type(_literal);
|
||||
|
||||
switch (literalType.category())
|
||||
@@ -2039,6 +2137,7 @@ void IRGeneratorForStatements::handleVariableReference(
|
||||
Expression const& _referencingExpression
|
||||
)
|
||||
{
|
||||
setLocation(_referencingExpression);
|
||||
if (_variable.isStateVariable() && _variable.isConstant())
|
||||
define(_referencingExpression) << constantValueFunction(_variable) << "()\n";
|
||||
else if (_variable.isStateVariable() && _variable.immutable())
|
||||
@@ -2480,6 +2579,7 @@ void IRGeneratorForStatements::appendAndOrOperatorCode(BinaryOperation const& _b
|
||||
solAssert(op == Token::Or || op == Token::And, "");
|
||||
|
||||
_binOp.leftExpression().accept(*this);
|
||||
setLocation(_binOp);
|
||||
|
||||
IRVariable value(_binOp);
|
||||
define(value, _binOp.leftExpression());
|
||||
@@ -2488,6 +2588,7 @@ void IRGeneratorForStatements::appendAndOrOperatorCode(BinaryOperation const& _b
|
||||
else
|
||||
m_code << "if " << value.name() << " {\n";
|
||||
_binOp.rightExpression().accept(*this);
|
||||
setLocation(_binOp);
|
||||
assign(value, _binOp.rightExpression());
|
||||
m_code << "}\n";
|
||||
}
|
||||
@@ -2687,6 +2788,7 @@ bool IRGeneratorForStatements::visit(TryStatement const& _tryStatement)
|
||||
{
|
||||
Expression const& externalCall = _tryStatement.externalCall();
|
||||
externalCall.accept(*this);
|
||||
setLocation(_tryStatement);
|
||||
|
||||
m_code << "switch iszero(" << IRNames::trySuccessConditionVariable(externalCall) << ")\n";
|
||||
|
||||
@@ -2707,6 +2809,7 @@ bool IRGeneratorForStatements::visit(TryStatement const& _tryStatement)
|
||||
}
|
||||
|
||||
successClause.block().accept(*this);
|
||||
setLocation(_tryStatement);
|
||||
m_code << "}\n";
|
||||
|
||||
m_code << "default { // failure case\n";
|
||||
@@ -2797,3 +2900,8 @@ bool IRGeneratorForStatements::visit(TryCatchClause const& _clause)
|
||||
_clause.block().accept(*this);
|
||||
return false;
|
||||
}
|
||||
|
||||
void IRGeneratorForStatements::setLocation(ASTNode const& _node)
|
||||
{
|
||||
m_currentLocation = _node.location();
|
||||
}
|
||||
|
||||
@@ -47,6 +47,9 @@ public:
|
||||
|
||||
std::string code() const;
|
||||
|
||||
/// Generate the code for the statements in the block;
|
||||
void generate(Block const& _block);
|
||||
|
||||
/// Generates code to initialize the given state variable.
|
||||
void initializeStateVar(VariableDeclaration const& _varDecl);
|
||||
/// Generates code to initialize the given local variable.
|
||||
@@ -179,10 +182,13 @@ private:
|
||||
|
||||
static Type const& type(Expression const& _expression);
|
||||
|
||||
void setLocation(ASTNode const& _node);
|
||||
|
||||
std::ostringstream m_code;
|
||||
IRGenerationContext& m_context;
|
||||
YulUtilFunctions& m_utils;
|
||||
std::optional<IRLValue> m_currentLValue;
|
||||
langutil::SourceLocation m_currentLocation;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -524,6 +524,10 @@ bool CompilerStack::compile()
|
||||
{
|
||||
if (m_generateEvmBytecode)
|
||||
compileContract(*contract, otherCompilers);
|
||||
if (m_generateIR || m_generateEwasm)
|
||||
generateIR(*contract);
|
||||
if (m_generateEwasm)
|
||||
generateEwasm(*contract);
|
||||
}
|
||||
catch (Error const& _error)
|
||||
{
|
||||
@@ -532,10 +536,28 @@ bool CompilerStack::compile()
|
||||
m_errorReporter.error(_error.errorId(), _error.type(), SourceLocation(), _error.what());
|
||||
return false;
|
||||
}
|
||||
if (m_generateIR || m_generateEwasm)
|
||||
generateIR(*contract);
|
||||
if (m_generateEwasm)
|
||||
generateEwasm(*contract);
|
||||
catch (UnimplementedFeatureError const& _unimplementedError)
|
||||
{
|
||||
if (
|
||||
SourceLocation const* sourceLocation =
|
||||
boost::get_error_info<langutil::errinfo_sourceLocation>(_unimplementedError)
|
||||
)
|
||||
{
|
||||
string const* comment = _unimplementedError.comment();
|
||||
m_errorReporter.error(
|
||||
1834_error,
|
||||
Error::Type::CodeGenerationError,
|
||||
*sourceLocation,
|
||||
"Unimplemented feature error" +
|
||||
((comment && !comment->empty()) ? ": " + *comment : string{}) +
|
||||
" in " +
|
||||
_unimplementedError.lineInfo()
|
||||
);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
throw;
|
||||
}
|
||||
}
|
||||
m_stackState = CompilationSuccessful;
|
||||
this->link();
|
||||
|
||||
Reference in New Issue
Block a user