Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ Language Features:
* Yul: Introduce builtin ``blobbasefee()`` for retrieving the blob base fee of the current block.
* Yul: Introduce builtin ``blobhash()`` for retrieving versioned hashes of blobs associated with the transaction.
* Yul: Introduce builtin ``mcopy()`` for cheaply copying data between memory areas.
* Yul: Introduce builtins ``tload()`` and ``tstore()`` for transient storage access.

Comment thread
matheusaaguiar marked this conversation as resolved.

Compiler Features:
* EVM: Support for the EVM Version "Cancun".
* SMTChecker: Support `bytes.concat` except when string literals are passed as arguments.


Bugfixes:
* AST import: Fix bug when importing inline assembly with empty ``let`` variable declaration.

Expand Down
2 changes: 1 addition & 1 deletion docs/grammar/SolidityLexer.g4
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ YulEVMBuiltin:
'stop' | 'add' | 'sub' | 'mul' | 'div' | 'sdiv' | 'mod' | 'smod' | 'exp' | 'not'
| 'lt' | 'gt' | 'slt' | 'sgt' | 'eq' | 'iszero' | 'and' | 'or' | 'xor' | 'byte'
| 'shl' | 'shr' | 'sar' | 'addmod' | 'mulmod' | 'signextend' | 'keccak256'
| 'pop' | 'mload' | 'mstore' | 'mstore8' | 'sload' | 'sstore' | 'msize' | 'gas'
| 'pop' | 'mload' | 'mstore' | 'mstore8' | 'sload' | 'sstore' | 'tload' | 'tstore'| 'msize' | 'gas'
| 'address' | 'balance' | 'selfbalance' | 'caller' | 'callvalue' | 'calldataload'
| 'calldatasize' | 'calldatacopy' | 'extcodesize' | 'extcodecopy' | 'returndatasize'
| 'returndatacopy' | 'mcopy' | 'extcodehash' | 'create' | 'create2' | 'call' | 'callcode'
Expand Down
1 change: 1 addition & 0 deletions docs/using-the-compiler.rst
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ at each version. Backward compatibility is not guaranteed between each version.
- The block's blob base fee (`EIP-7516 <https://eips.ethereum.org/EIPS/eip-7516>`_ and `EIP-4844 <https://eips.ethereum.org/EIPS/eip-4844>`_) can be accessed via the global ``block.blobbasefee`` or ``blobbasefee()`` in inline assembly.
- Introduces ``blobhash()`` in inline assembly and a corresponding global function to retrieve versioned hashes of blobs associated with the transaction (see `EIP-4844 <https://eips.ethereum.org/EIPS/eip-4844>`_).
- Opcode ``mcopy`` is available in assembly (see `EIP-5656 <https://eips.ethereum.org/EIPS/eip-5656>`_).
- Opcodes ``tstore`` and ``tload`` are available in assembly (see `EIP-1153 <https://eips.ethereum.org/EIPS/eip-1153>`_).

.. index:: ! standard JSON, ! --standard-json
.. _compiler-api:
Expand Down
7 changes: 6 additions & 1 deletion docs/yul.rst
Original file line number Diff line number Diff line change
Expand Up @@ -756,7 +756,8 @@ Opcodes marked with ``F``, ``H``, ``B``, ``C``, ``I``, ``L``, ``P`` and ``N`` ar
Homestead, Byzantium, Constantinople, Istanbul, London, Paris or Cancun respectively.

In the following, ``mem[a...b)`` signifies the bytes of memory starting at position ``a`` up to
but not including position ``b`` and ``storage[p]`` signifies the storage contents at slot ``p``.
but not including position ``b``, ``storage[p]`` signifies the storage contents at slot ``p``, and
similarly, ``transientStorage[p]`` signifies the transient storage contents at slot ``p``.

Since Yul manages local variables and control-flow,
opcodes that interfere with these features are not available. This includes
Expand Down Expand Up @@ -833,6 +834,10 @@ the ``dup`` and ``swap`` instructions as well as ``jump`` instructions, labels a
+-------------------------+-----+---+-----------------------------------------------------------------+
| sstore(p, v) | `-` | F | storage[p] := v |
+-------------------------+-----+---+-----------------------------------------------------------------+
| tload(p) | | N | transientStorage[p] |
+-------------------------+-----+---+-----------------------------------------------------------------+
| tstore(p, v) | `-` | N | transientStorage[p] := v |
+-------------------------+-----+---+-----------------------------------------------------------------+
| msize() | | F | size of memory, i.e. largest accessed memory index |
+-------------------------+-----+---+-----------------------------------------------------------------+
| gas() | | F | gas still available to execution |
Expand Down
15 changes: 8 additions & 7 deletions libevmasm/GasMeter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,13 +274,14 @@ unsigned GasMeter::runGas(Instruction _instruction, langutil::EVMVersion _evmVer

switch (instructionInfo(_instruction, _evmVersion).gasPriceTier)
{
case Tier::Zero: return GasCosts::tier0Gas;
case Tier::Base: return GasCosts::tier1Gas;
case Tier::VeryLow: return GasCosts::tier2Gas;
case Tier::Low: return GasCosts::tier3Gas;
case Tier::Mid: return GasCosts::tier4Gas;
case Tier::High: return GasCosts::tier5Gas;
case Tier::Ext: return GasCosts::tier6Gas;
case Tier::Zero: return GasCosts::tier0Gas;
case Tier::Base: return GasCosts::tier1Gas;
case Tier::VeryLow: return GasCosts::tier2Gas;
case Tier::Low: return GasCosts::tier3Gas;
case Tier::Mid: return GasCosts::tier4Gas;
case Tier::High: return GasCosts::tier5Gas;
case Tier::Ext: return GasCosts::tier6Gas;
case Tier::WarmAccess: return GasCosts::warmStorageReadCost;
default: break;
}
assertThrow(false, OptimizerException, "Invalid gas tier for instruction " + instructionInfo(_instruction, _evmVersion).name);
Expand Down
4 changes: 4 additions & 0 deletions libevmasm/Instruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ std::map<std::string, Instruction> const solidity::evmasm::c_instructions =
{ "MSTORE8", Instruction::MSTORE8 },
{ "SLOAD", Instruction::SLOAD },
{ "SSTORE", Instruction::SSTORE },
{ "TLOAD", Instruction::TLOAD },
{ "TSTORE", Instruction::TSTORE },
{ "JUMP", Instruction::JUMP },
{ "JUMPI", Instruction::JUMPI },
{ "PC", Instruction::PC },
Expand Down Expand Up @@ -242,6 +244,8 @@ static std::map<Instruction, InstructionInfo> const c_instructionInfo =
{ Instruction::MSTORE8, { "MSTORE8", 0, 2, 0, true, Tier::VeryLow } },
{ Instruction::SLOAD, { "SLOAD", 0, 1, 1, false, Tier::Special } },
{ Instruction::SSTORE, { "SSTORE", 0, 2, 0, true, Tier::Special } },
{ Instruction::TLOAD, { "TLOAD", 0, 1, 1, false, Tier::WarmAccess} },
{ Instruction::TSTORE, { "TSTORE", 0, 2, 0, true, Tier::WarmAccess} },

@cameel cameel Jan 12, 2024

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We mark TSTORE here as having side-effects, but in SemanticInformation.cpp both TSTORE and TLOAD have Effect::None for all side-effect types (memory, storage and other). If we're not always checking both of these sources of info in the optimizer, these opcodes could be accidentally treated as having no side-effects at all.

For example SideEffectsCollector::movableRelativeTo() does just that. It will treat as TSTORE and TLOAD or even two TSTOREs as movable relative to each other, which would change semantics. Fortunately right now this function is used only in one place (LoopInvariantCodeMotion) and only for initializers of variable declarations (where TSTORE cannot be used), so I think it does not break anything in practice but someone could unwittingly use this function somewhere else and end up with a broken optimization. Or there could be some other place where it matters. I searched for all uses of SideEffects and otherState to make sure but I could have easily missed something.

@ekpyron Adding a new side-effect type for transitional storage in this PR would be quite tedious, so how about we mark them as reading/writing 'other' with a TODO to change that to transitional storage effects once that's available? Could that have any unintended consequences?

@ekpyron ekpyron Jan 15, 2024

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'd have assumed to basically treat both of them as "worst side effects" like an external call or such for the time being. If we can avoid invalidating storage or memory knowledge that's good, though.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SideEffectsCollector::movableRelativeTo() looks a bit dangerously implemented right now :-) - although nobody would have anticipated just introducing a new data region like this...

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I don't see how movableRelativeTo can be properly implemented without adding transient storage to SideEffects.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even in the loop invariant code motion, this may very well already lead to moving a tload past a tstore in the loop, won't it? (Without having really looked into it)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Damn, you're right. It's broken.

This

{
    for { let i := 1 } iszero(eq(i, 10)) { i := add(i, 1) }
    {
        tstore(0, i)
        sstore(i, tload(0))
    }
}

gets optimized into this (with the default sequence):

{
    let i := 1
    let i_1 := 1
    let _1 := tload(0)
    for { } iszero(eq(i_1, 10)) { i_1 := add(i_1, i) }
    {
        tstore(0, i_1)
        sstore(i_1, _1)
    }
}

I focused on tstore() being moved, but somehow missed that moving tload() can effectively lead to the same thing.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good that we still found it then :-).

@matheusaaguiar matheusaaguiar Jan 15, 2024

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I overlooked that part of semantic information when starting to work on this. I have covered the case @cameel pointed out. I am still looking the code for more places where we might need to add coverage.

{ Instruction::JUMP, { "JUMP", 0, 1, 0, true, Tier::Mid } },
{ Instruction::JUMPI, { "JUMPI", 0, 2, 0, true, Tier::High } },
{ Instruction::PC, { "PC", 0, 0, 1, false, Tier::Base } },
Expand Down
4 changes: 4 additions & 0 deletions libevmasm/Instruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ enum class Instruction: uint8_t
JUMPDEST, ///< set a potential jump destination
MCOPY = 0x5e, ///< copy between memory areas

TLOAD = 0x5c, ///< load word from transient storage
TSTORE = 0x5d, ///< save word to transient storage

PUSH0 = 0x5f, ///< place the value 0 on stack
PUSH1 = 0x60, ///< place 1 byte item on stack
PUSH2, ///< place 2 byte item on stack
Expand Down Expand Up @@ -293,6 +296,7 @@ enum class Tier
Mid, // 8, Mid
High, // 10, Slow
Ext, // 20, Ext
WarmAccess, // 100, Warm Access
ExtCode, // 700, Extcode
Balance, // 400, Balance
Special, // multiparam or otherwise special
Expand Down
55 changes: 52 additions & 3 deletions libevmasm/SemanticInformation.cpp
Comment thread
matheusaaguiar marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ std::vector<SemanticInformation::Operation> SemanticInformation::readWriteOperat
{
assertThrow(memory(_instruction) == Effect::None, OptimizerException, "");
assertThrow(storage(_instruction) != Effect::None, OptimizerException, "");
assertThrow(transientStorage(_instruction) == Effect::None, OptimizerException, "");
Operation op;
op.effect = storage(_instruction);
op.location = Location::Storage;
Expand All @@ -51,6 +52,7 @@ std::vector<SemanticInformation::Operation> SemanticInformation::readWriteOperat
{
assertThrow(memory(_instruction) != Effect::None, OptimizerException, "");
assertThrow(storage(_instruction) == Effect::None, OptimizerException, "");
assertThrow(transientStorage(_instruction) == Effect::None, OptimizerException, "");
Operation op;
op.effect = memory(_instruction);
op.location = Location::Memory;
Expand All @@ -62,6 +64,19 @@ std::vector<SemanticInformation::Operation> SemanticInformation::readWriteOperat

return {op};
}
case Instruction::TSTORE:
case Instruction::TLOAD:
{
assertThrow(memory(_instruction) == Effect::None, OptimizerException, "");
assertThrow(storage(_instruction) == Effect::None, OptimizerException, "");
assertThrow(transientStorage(_instruction) != Effect::None, OptimizerException, "");
Operation op;
op.effect = transientStorage(_instruction);
op.location = Location::TransientStorage;
op.startParameter = 0;
op.lengthConstant = 1;
return {op};
}
case Instruction::REVERT:
case Instruction::RETURN:
case Instruction::KECCAK256:
Expand All @@ -72,6 +87,7 @@ std::vector<SemanticInformation::Operation> SemanticInformation::readWriteOperat
case Instruction::LOG4:
{
assertThrow(storage(_instruction) == Effect::None, OptimizerException, "");
assertThrow(transientStorage(_instruction) == Effect::None, OptimizerException, "");
assertThrow(memory(_instruction) == Effect::Read, OptimizerException, "");
Comment thread
cameel marked this conversation as resolved.
Operation op;
op.effect = memory(_instruction);
Expand All @@ -84,6 +100,7 @@ std::vector<SemanticInformation::Operation> SemanticInformation::readWriteOperat
{
assertThrow(memory(_instruction) == Effect::Write, OptimizerException, "");
assertThrow(storage(_instruction) == Effect::None, OptimizerException, "");
assertThrow(transientStorage(_instruction) == Effect::None, OptimizerException, "");
Operation op;
op.effect = memory(_instruction);
op.location = Location::Memory;
Expand All @@ -97,6 +114,7 @@ std::vector<SemanticInformation::Operation> SemanticInformation::readWriteOperat
{
assertThrow(memory(_instruction) == Effect::Write, OptimizerException, "");
assertThrow(storage(_instruction) == Effect::None, OptimizerException, "");
assertThrow(transientStorage(_instruction) == Effect::None, OptimizerException, "");
Comment thread
cameel marked this conversation as resolved.
Operation op;
op.effect = memory(_instruction);
op.location = Location::Memory;
Expand Down Expand Up @@ -131,10 +149,14 @@ std::vector<SemanticInformation::Operation> SemanticInformation::readWriteOperat
size_t paramCount = static_cast<size_t>(instructionInfo(_instruction, langutil::EVMVersion()).args);
std::vector<Operation> operations{
Operation{Location::Memory, Effect::Read, paramCount - 4, paramCount - 3, {}},
Operation{Location::Storage, Effect::Read, {}, {}, {}}
Operation{Location::Storage, Effect::Read, {}, {}, {}},
Operation{Location::TransientStorage, Effect::Read, {}, {}, {}}
};
if (_instruction != Instruction::STATICCALL)
{
operations.emplace_back(Operation{Location::Storage, Effect::Write, {}, {}, {}});
operations.emplace_back(Operation{Location::TransientStorage, Effect::Write, {}, {}, {}});
}
operations.emplace_back(Operation{
Location::Memory,
Effect::Write,
Expand All @@ -157,13 +179,15 @@ std::vector<SemanticInformation::Operation> SemanticInformation::readWriteOperat
{}
},
Operation{Location::Storage, Effect::Read, {}, {}, {}},
Operation{Location::Storage, Effect::Write, {}, {}, {}}
Operation{Location::Storage, Effect::Write, {}, {}, {}},
Operation{Location::TransientStorage, Effect::Read, {}, {}, {}},
Operation{Location::TransientStorage, Effect::Write, {}, {}, {}}
};
case Instruction::MSIZE:
// This is just to satisfy the assert below.
return std::vector<Operation>{};
default:
assertThrow(storage(_instruction) == None && memory(_instruction) == None, AssemblyException, "");
assertThrow(storage(_instruction) == None && memory(_instruction) == None && transientStorage(_instruction) == None, AssemblyException, "");
}
return {};
}
Expand Down Expand Up @@ -348,6 +372,7 @@ bool SemanticInformation::movable(Instruction _instruction)
case Instruction::EXTCODEHASH:
case Instruction::RETURNDATASIZE:
case Instruction::SLOAD:
case Instruction::TLOAD:
case Instruction::PC:
case Instruction::MSIZE:
case Instruction::GAS:
Expand Down Expand Up @@ -420,6 +445,7 @@ bool SemanticInformation::movableApartFromEffects(Instruction _instruction)
case Instruction::BALANCE:
case Instruction::SELFBALANCE:
case Instruction::SLOAD:
case Instruction::TLOAD:
case Instruction::KECCAK256:
case Instruction::MLOAD:
return true;
Expand Down Expand Up @@ -450,6 +476,27 @@ SemanticInformation::Effect SemanticInformation::storage(Instruction _instructio
}
}

SemanticInformation::Effect SemanticInformation::transientStorage(Instruction _instruction)
Comment thread
matheusaaguiar marked this conversation as resolved.
{
switch (_instruction)
{
case Instruction::CALL:
case Instruction::CALLCODE:
case Instruction::DELEGATECALL:
case Instruction::CREATE:
case Instruction::CREATE2:
case Instruction::TSTORE:
Comment thread
nikola-matic marked this conversation as resolved.
return SemanticInformation::Write;
Comment thread
matheusaaguiar marked this conversation as resolved.

case Instruction::TLOAD:
case Instruction::STATICCALL:
return SemanticInformation::Read;

default:
return SemanticInformation::None;
}
}

SemanticInformation::Effect SemanticInformation::otherState(Instruction _instruction)
{
switch (_instruction)
Expand Down Expand Up @@ -508,6 +555,7 @@ bool SemanticInformation::invalidInPureFunctions(Instruction _instruction)
case Instruction::GASLIMIT:
case Instruction::STATICCALL:
case Instruction::SLOAD:
case Instruction::TLOAD:
return true;
default:
break;
Expand All @@ -520,6 +568,7 @@ bool SemanticInformation::invalidInViewFunctions(Instruction _instruction)
switch (_instruction)
{
case Instruction::SSTORE:
case Instruction::TSTORE:
case Instruction::JUMP:
case Instruction::JUMPI:
case Instruction::LOG0:
Expand Down
11 changes: 6 additions & 5 deletions libevmasm/SemanticInformation.h
Comment thread
matheusaaguiar marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,16 @@ class AssemblyItem;
*/
struct SemanticInformation
{
/// Corresponds to the effect that a YUL-builtin has on a generic data location (storage, memory
/// and other blockchain state).
/// Corresponds to the effect that a YUL-builtin has on a generic data location (storage, memory,
/// transient storage and other blockchain state).
enum Effect
{
None,
Read,
Write
};

enum class Location { Storage, Memory };
enum class Location { Storage, Memory, TransientStorage };
Comment thread
cameel marked this conversation as resolved.

/**
* Represents a read or write operation from or to one of the data locations.
Expand Down Expand Up @@ -87,10 +87,10 @@ struct SemanticInformation
static bool terminatesControlFlow(Instruction _instruction);
static bool reverts(Instruction _instruction);
/// @returns false if the value put on the stack by _item depends on anything else than
/// the information in the current block header, memory, storage or stack.
/// the information in the current block header, memory, storage, transient storage or stack.
static bool isDeterministic(AssemblyItem const& _item);
/// @returns true if the instruction can be moved or copied (together with its arguments)
/// without altering the semantics. This means it cannot depend on storage or memory,
/// without altering the semantics. This means it cannot depend on storage, transient storage or memory,
/// cannot have any side-effects, but it can depend on a call-constant state of the blockchain.
static bool movable(Instruction _instruction);
/// If true, the expressions in this code can be moved or copied (together with their arguments)
Expand All @@ -109,6 +109,7 @@ struct SemanticInformation
static bool canBeRemovedIfNoMSize(Instruction _instruction);
static Effect memory(Instruction _instruction);
static Effect storage(Instruction _instruction);
static Effect transientStorage(Instruction _instruction);
static Effect otherState(Instruction _instruction);
static bool invalidInPureFunctions(Instruction _instruction);
static bool invalidInViewFunctions(Instruction _instruction);
Expand Down
2 changes: 2 additions & 0 deletions libevmasm/SimplificationRule.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ struct EVMBuiltins
static auto constexpr MSTORE8 = PatternGenerator<Instruction::MSTORE8>{};
static auto constexpr SLOAD = PatternGenerator<Instruction::SLOAD>{};
static auto constexpr SSTORE = PatternGenerator<Instruction::SSTORE>{};
static auto constexpr TLOAD = PatternGenerator<Instruction::TLOAD>{};
static auto constexpr TSTORE = PatternGenerator<Instruction::TSTORE>{};
static auto constexpr PC = PatternGenerator<Instruction::PC>{};
static auto constexpr MSIZE = PatternGenerator<Instruction::MSIZE>{};
static auto constexpr GAS = PatternGenerator<Instruction::GAS>{};
Expand Down
3 changes: 3 additions & 0 deletions liblangutil/EVMVersion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ bool EVMVersion::hasOpcode(Instruction _opcode) const
return hasBlobBaseFee();
case Instruction::MCOPY:
return hasMcopy();
case Instruction::TSTORE:
case Instruction::TLOAD:
return supportsTransientStorage();
default:
return true;
}
Expand Down
1 change: 1 addition & 0 deletions liblangutil/EVMVersion.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ class EVMVersion:
bool hasPush0() const { return *this >= shanghai(); }
bool hasBlobHash() const { return *this >= cancun(); }
bool hasMcopy() const { return *this >= cancun(); }
bool supportsTransientStorage() const { return *this >= cancun(); }

bool hasOpcode(evmasm::Instruction _opcode) const;

Expand Down
17 changes: 17 additions & 0 deletions libyul/AsmAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,20 @@ std::vector<YulString> AsmAnalyzer::operator()(FunctionCall const& _funCall)
"The underlying opcode will eventually undergo breaking changes, "
"and its use is not recommended."
);
else if (
m_evmVersion.supportsTransientStorage() &&
_funCall.functionName.name == "tstore"_yulstring
)
m_errorReporter.warning(
2394_error,
nativeLocationOf(_funCall.functionName),
"Transient storage as defined by EIP-1153 can break the composability of smart contracts: "
"Since transient storage is cleared only at the end of the transaction and not at the end of the outermost call frame to the contract within a transaction, "
"your contract may unintentionally misbehave when invoked multiple times in a complex transaction. "
"To avoid this, be sure to clear all transient storage at the end of any call to your contract. "
"The use of transient storage for reentrancy guards that are cleared at the end of the call is safe."
);

parameterTypes = &f->parameters;
returnTypes = &f->returns;
if (!f->literalArguments.empty())
Expand Down Expand Up @@ -739,6 +753,9 @@ bool AsmAnalyzer::validateInstructions(evmasm::Instruction _instr, SourceLocatio
else if (_instr == evmasm::Instruction::MCOPY && !m_evmVersion.hasMcopy())
// TODO: Change this assertion to an error, similar to the ones above, when Cancun becomes the default EVM version.
yulAssert(false);
else if ((_instr == evmasm::Instruction::TSTORE || _instr == evmasm::Instruction::TLOAD) && !m_evmVersion.supportsTransientStorage())
// TODO: Change this assertion to an error, similar to the ones above, when Cancun becomes the default EVM version.
yulAssert(false);
else if (_instr == evmasm::Instruction::PC)
m_errorReporter.error(
2450_error,
Expand Down
Loading