Skip to content

Commit

Permalink
Don't ignore errors reported at optimization and assembling steps in …
Browse files Browse the repository at this point in the history
…Yul compilation
  • Loading branch information
cameel committed Dec 4, 2024
1 parent d09b495 commit 1d4d683
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 49 deletions.
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Compiler Features:

Bugfixes:
* General: Fix internal compiler error when requesting IR AST outputs for interfaces and abstract contracts.
* Yul: Fix internal compiler error when a code generation error should be reported instead.


### 0.8.28 (2024-10-09)
Expand Down
56 changes: 29 additions & 27 deletions libsolidity/interface/StandardCompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1616,9 +1616,35 @@ Json StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings)
std::string const& sourceName = _inputsAndSettings.sources.begin()->first;
std::string const& sourceContents = _inputsAndSettings.sources.begin()->second;

// Inconsistent state - stop here to receive error reports from users
if (!stack.parseAndAnalyze(sourceName, sourceContents) && !stack.hasErrors())
solAssert(false, "No error reported, but parsing/analysis failed.");
std::string contractName;
bool const wildcardMatchesExperimental = true;
MachineAssemblyObject object;
MachineAssemblyObject deployedObject;

bool successful = stack.parseAndAnalyze(sourceName, sourceContents);
if (!successful)
// Inconsistent state - stop here to receive error reports from users
solAssert(stack.hasErrors(), "No error reported, but parsing/analysis failed.");
else
{
contractName = stack.parserResult()->name;
if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, contractName, "ir", wildcardMatchesExperimental))
output["contracts"][sourceName][contractName]["ir"] = stack.print();

if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, contractName, "ast", wildcardMatchesExperimental))
{
Json sourceResult;
sourceResult["id"] = 0;
sourceResult["ast"] = stack.astJson();
output["sources"][sourceName] = sourceResult;
}
stack.optimize();
std::tie(object, deployedObject) = stack.assembleWithDeployed();
if (object.bytecode)
object.bytecode->link(_inputsAndSettings.libraries);
if (deployedObject.bytecode)
deployedObject.bytecode->link(_inputsAndSettings.libraries);
}

for (auto const& error: stack.errors())
{
Expand All @@ -1635,30 +1661,6 @@ Json StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings)
if (stack.hasErrors())
return output;

std::string contractName = stack.parserResult()->name;

bool const wildcardMatchesExperimental = true;
if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, contractName, "ir", wildcardMatchesExperimental))
output["contracts"][sourceName][contractName]["ir"] = stack.print();

if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, contractName, "ast", wildcardMatchesExperimental))
{
Json sourceResult;
sourceResult["id"] = 0;
sourceResult["ast"] = stack.astJson();
output["sources"][sourceName] = sourceResult;
}
stack.optimize();

MachineAssemblyObject object;
MachineAssemblyObject deployedObject;
std::tie(object, deployedObject) = stack.assembleWithDeployed();

if (object.bytecode)
object.bytecode->link(_inputsAndSettings.libraries);
if (deployedObject.bytecode)
deployedObject.bytecode->link(_inputsAndSettings.libraries);

for (auto&& [kind, isDeployed]: {make_pair("bytecode"s, false), make_pair("deployedBytecode"s, true)})
if (isArtifactRequested(
_inputsAndSettings.outputSelection,
Expand Down
38 changes: 22 additions & 16 deletions solc/CommandLineInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1232,9 +1232,10 @@ void CommandLineInterface::assembleYul(yul::YulStack::Language _language, yul::Y

bool successful = true;
std::map<std::string, yul::YulStack> yulStacks;
for (auto const& src: m_fileReader.sourceUnits())
std::map<std::string, yul::MachineAssemblyObject> objects;
for (auto const& [sourceUnitName, yulSource]: m_fileReader.sourceUnits())
{
auto& stack = yulStacks[src.first] = yul::YulStack(
auto& stack = yulStacks[sourceUnitName] = yul::YulStack(
m_options.output.evmVersion,
m_options.output.eofVersion,
_language,
Expand All @@ -1244,20 +1245,28 @@ void CommandLineInterface::assembleYul(yul::YulStack::Language _language, yul::Y
DebugInfoSelection::Default()
);

if (!stack.parseAndAnalyze(src.first, src.second))
successful = false;
successful = successful && stack.parseAndAnalyze(sourceUnitName, yulSource);
if (!successful)
solAssert(stack.hasErrors(), "No error reported, but parsing/analysis failed.");
else
stack.optimize();

if (successful && m_options.compiler.outputs.asmJson)
{
std::shared_ptr<yul::Object> result = stack.parserResult();
if (result && !result->hasContiguousSourceIndices())
if (
m_options.compiler.outputs.asmJson &&
stack.parserResult() &&
!stack.parserResult()->hasContiguousSourceIndices()
)
solThrow(
CommandLineExecutionError,
"Generating the assembly JSON output was not possible. "
"Source indices provided in the @use-src annotation in the Yul input do not start at 0 or are not contiguous."
);

stack.optimize();

yul::MachineAssemblyObject object = stack.assemble(_targetMachine);
if (object.bytecode)
object.bytecode->link(m_options.linker.libraries);
objects.insert({sourceUnitName, std::move(object)});
}
}

Expand All @@ -1281,13 +1290,14 @@ void CommandLineInterface::assembleYul(yul::YulStack::Language _language, yul::Y
solThrow(CommandLineExecutionError, "");
}

for (auto const& src: m_fileReader.sourceUnits())
for (auto const& [sourceUnitName, yulSource]: m_fileReader.sourceUnits())
{
solAssert(_targetMachine == yul::YulStack::Machine::EVM);
std::string machine = "EVM";
sout() << std::endl << "======= " << src.first << " (" << machine << ") =======" << std::endl;
sout() << std::endl << "======= " << sourceUnitName << " (" << machine << ") =======" << std::endl;

yul::YulStack& stack = yulStacks[src.first];
yul::YulStack const& stack = yulStacks[sourceUnitName];
yul::MachineAssemblyObject const& object = objects[sourceUnitName];

if (m_options.compiler.outputs.irOptimized)
{
Expand All @@ -1297,10 +1307,6 @@ void CommandLineInterface::assembleYul(yul::YulStack::Language _language, yul::Y
sout() << stack.print() << std::endl;
}

yul::MachineAssemblyObject object;
object = stack.assemble(_targetMachine);
object.bytecode->link(m_options.linker.libraries);

if (m_options.compiler.outputs.binary)
{
sout() << std::endl << "Binary representation:" << std::endl;
Expand Down
16 changes: 10 additions & 6 deletions test/libyul/ObjectCompilerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,18 +71,22 @@ TestCase::TestResult ObjectCompilerTest::run(std::ostream& _stream, std::string
OptimiserSettings::preset(m_optimisationPreset),
DebugInfoSelection::All()
);
if (!stack.parseAndAnalyze("source", m_source))
bool successful = stack.parseAndAnalyze("source", m_source);
MachineAssemblyObject obj;
if (successful)
{
stack.optimize();
obj = stack.assemble(YulStack::Machine::EVM);
}
if (stack.hasErrors())
{
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << std::endl;
SourceReferenceFormatter{_stream, stack, true, false}
.printErrorInformation(stack.errors());
return TestResult::FatalError;
}
stack.optimize();

MachineAssemblyObject obj = stack.assemble(YulStack::Machine::EVM);
solAssert(obj.bytecode, "");
solAssert(obj.sourceMappings, "");
solAssert(obj.bytecode);
solAssert(obj.sourceMappings);

m_obtainedResult = "Assembly:\n" + obj.assembly->assemblyString(stack.debugInfoSelection());
if (obj.bytecode->bytecode.empty())
Expand Down

0 comments on commit 1d4d683

Please sign in to comment.