mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge remote-tracking branch 'origin/develop' into breaking
This commit is contained in:
commit
64b6524bdb
19
Changelog.md
19
Changelog.md
@ -23,31 +23,38 @@ Bugfixes:
|
||||
* NatSpec: Constructors and functions have consistent userdoc output.
|
||||
|
||||
|
||||
### 0.6.11 (unreleased)
|
||||
### 0.6.12 (unreleased)
|
||||
|
||||
|
||||
|
||||
|
||||
### 0.6.11 (2020-07-07)
|
||||
|
||||
|
||||
Language Features:
|
||||
* General: Add unit denomination ``gwei``
|
||||
* Yul: Support ``linkersymbol`` builtin in standalone assembly mode.
|
||||
* Yul: Support ``linkersymbol`` builtin in standalone assembly mode to refer to library addresses.
|
||||
* Yul: Support using string literals exceeding 32 bytes as literal arguments for builtins.
|
||||
|
||||
|
||||
Compiler Features:
|
||||
* NatSpec: Add fields "kind" and "version" to the JSON output.
|
||||
* NatSpec: Inherit tags from unique base if derived function does not provide any.
|
||||
* NatSpec: Add fields ``kind`` and ``version`` to the JSON output.
|
||||
* NatSpec: Inherit tags from unique base functions if derived function does not provide any.
|
||||
* Commandline Interface: Prevent some incompatible commandline options from being used together.
|
||||
* NatSpec: Support NatSpec comments on events.
|
||||
* Yul Optimizer: Store knowledge about storage / memory after ``a := sload(x)`` / ``a := mload(x)``.
|
||||
* SMTChecker: Support external calls to unknown code.
|
||||
* Source Maps: Also tag jumps into and out of Yul functions as jumps into and out of functions.
|
||||
|
||||
|
||||
Bugfixes:
|
||||
* NatSpec: Do not consider ``////`` and ``/***`` as NatSpec comments.
|
||||
* Type Checker: Fix internal error related to ``using for`` applied to non-libraries.
|
||||
* Type Checker: Do not disallow assigning to calldata variables.
|
||||
* Type Checker: Disallow constructor parameters with ``calldata`` data location.
|
||||
* Type Checker: Do not disallow assigning to calldata variables.
|
||||
* Type Checker: Fix internal error related to ``using for`` applied to non-libraries.
|
||||
* Wasm backend: Fix code generation for for-loops with pre statements.
|
||||
* Wasm backend: Properly support both ``i32.drop`` and ``i64.drop``, and remove ``drop``.
|
||||
* Yul: Disallow the same variable to occur multiple times on the left-hand side of an assignment.
|
||||
* Yul: Fix source location of variable multi-assignment.
|
||||
|
||||
|
||||
|
@ -1109,6 +1109,10 @@
|
||||
"bugs": [],
|
||||
"released": "2020-06-11"
|
||||
},
|
||||
"0.6.11": {
|
||||
"bugs": [],
|
||||
"released": "2020-07-07"
|
||||
},
|
||||
"0.6.2": {
|
||||
"bugs": [
|
||||
"MissingEscapingInFormatting",
|
||||
|
@ -288,6 +288,8 @@ variables at the same time. For this, the number and types of the
|
||||
values have to match.
|
||||
If you want to assign the values returned from a function that has
|
||||
multiple return parameters, you have to provide multiple variables.
|
||||
The same variable may not occur multiple times on the left-hand side of
|
||||
an assignment, e.g. ``x, x := f()`` is invalid.
|
||||
|
||||
.. code-block:: yul
|
||||
|
||||
@ -506,6 +508,8 @@ In variable declarations and assignments, the right-hand-side expression
|
||||
variables on the left-hand-side.
|
||||
This is the only situation where an expression evaluating
|
||||
to more than one value is allowed.
|
||||
The same variable name cannot occur more than once in the left-hand-side of
|
||||
an assignment or variable declaration.
|
||||
|
||||
Expressions that are also statements (i.e. at the block level) have to
|
||||
evaluate to zero values.
|
||||
|
@ -151,13 +151,13 @@ void ContractLevelChecker::findDuplicateDefinitions(map<string, vector<T>> const
|
||||
if constexpr (is_same_v<T, FunctionDefinition const*>)
|
||||
{
|
||||
error = 1686_error;
|
||||
message = "Function with same name and arguments defined twice.";
|
||||
message = "Function with same name and parameter types defined twice.";
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(is_same_v<T, EventDefinition const*>, "Expected \"FunctionDefinition const*\" or \"EventDefinition const*\"");
|
||||
error = 5883_error;
|
||||
message = "Event with same name and arguments defined twice.";
|
||||
message = "Event with same name and parameter types defined twice.";
|
||||
}
|
||||
|
||||
ssl.limitSize(message);
|
||||
|
@ -514,7 +514,13 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr
|
||||
);
|
||||
|
||||
if (!_overriding.overrides())
|
||||
overrideError(_overriding, _super, 9456_error, "Overriding " + _overriding.astNodeName() + " is missing \"override\" specifier.");
|
||||
overrideError(
|
||||
_overriding,
|
||||
_super,
|
||||
9456_error,
|
||||
"Overriding " + _overriding.astNodeName() + " is missing \"override\" specifier.",
|
||||
"Overridden " + _overriding.astNodeName() + " is here:"
|
||||
);
|
||||
|
||||
if (_super.isVariable())
|
||||
overrideError(
|
||||
@ -536,7 +542,13 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr
|
||||
if (_overriding.isVariable())
|
||||
{
|
||||
if (_super.visibility() != Visibility::External)
|
||||
overrideError(_overriding, _super, 5225_error, "Public state variables can only override functions with external visibility.");
|
||||
overrideError(
|
||||
_overriding,
|
||||
_super,
|
||||
5225_error,
|
||||
"Public state variables can only override functions with external visibility.",
|
||||
"Overridden function is here:"
|
||||
);
|
||||
solAssert(_overriding.visibility() == Visibility::External, "");
|
||||
}
|
||||
else if (_overriding.visibility() != _super.visibility())
|
||||
@ -547,7 +559,13 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr
|
||||
_super.visibility() == Visibility::External &&
|
||||
_overriding.visibility() == Visibility::Public
|
||||
))
|
||||
overrideError(_overriding, _super, 9098_error, "Overriding " + _overriding.astNodeName() + " visibility differs.");
|
||||
overrideError(
|
||||
_overriding,
|
||||
_super,
|
||||
9098_error,
|
||||
"Overriding " + _overriding.astNodeName() + " visibility differs.",
|
||||
"Overridden " + _overriding.astNodeName() + " is here:"
|
||||
);
|
||||
}
|
||||
|
||||
if (_super.isFunction())
|
||||
@ -558,7 +576,13 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr
|
||||
solAssert(functionType->hasEqualParameterTypes(*superType), "Override doesn't have equal parameters!");
|
||||
|
||||
if (!functionType->hasEqualReturnTypes(*superType))
|
||||
overrideError(_overriding, _super, 4822_error, "Overriding " + _overriding.astNodeName() + " return types differ.");
|
||||
overrideError(
|
||||
_overriding,
|
||||
_super,
|
||||
4822_error,
|
||||
"Overriding " + _overriding.astNodeName() + " return types differ.",
|
||||
"Overridden " + _overriding.astNodeName() + " is here:"
|
||||
);
|
||||
|
||||
// This is only relevant for a function overriding a function.
|
||||
if (_overriding.isFunction())
|
||||
|
@ -146,7 +146,7 @@ void CompilerContext::callYulFunction(
|
||||
m_externallyUsedYulFunctions.insert(_name);
|
||||
auto const retTag = pushNewTag();
|
||||
CompilerUtils(*this).moveIntoStack(_inArgs);
|
||||
appendJumpTo(namedTag(_name));
|
||||
appendJumpTo(namedTag(_name), evmasm::AssemblyItem::JumpType::IntoFunction);
|
||||
adjustStackOffset(static_cast<int>(_outArgs) - 1 - static_cast<int>(_inArgs));
|
||||
*this << retTag.tag();
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ Json::Value Natspec::userDocumentation(ContractDefinition const& _contractDef)
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const& event: _contractDef.events())
|
||||
for (auto const& event: _contractDef.interfaceEvents())
|
||||
{
|
||||
string value = extractDoc(event->annotation().docTags, "notice");
|
||||
if (!value.empty())
|
||||
|
@ -167,6 +167,17 @@ void AsmAnalyzer::operator()(Assignment const& _assignment)
|
||||
size_t const numVariables = _assignment.variableNames.size();
|
||||
yulAssert(numVariables >= 1, "");
|
||||
|
||||
set<YulString> variables;
|
||||
for (auto const& _variableName: _assignment.variableNames)
|
||||
if (!variables.insert(_variableName.name).second)
|
||||
m_errorReporter.declarationError(
|
||||
9005_error,
|
||||
_assignment.location,
|
||||
"Variable " +
|
||||
_variableName.name.str() +
|
||||
" occurs multiple times on the left-hand side of the assignment."
|
||||
);
|
||||
|
||||
vector<YulString> types = std::visit(*this, *_assignment.value);
|
||||
|
||||
if (types.size() != numVariables)
|
||||
|
@ -297,20 +297,6 @@ Expression Parser::parseExpression()
|
||||
}
|
||||
}
|
||||
|
||||
std::map<evmasm::Instruction, string> const& Parser::instructionNames()
|
||||
{
|
||||
static map<evmasm::Instruction, string> s_instructionNames;
|
||||
if (s_instructionNames.empty())
|
||||
{
|
||||
for (auto const& instr: instructions())
|
||||
s_instructionNames[instr.second] = instr.first;
|
||||
// set the ambiguous instructions to a clear default
|
||||
s_instructionNames[evmasm::Instruction::SELFDESTRUCT] = "selfdestruct";
|
||||
s_instructionNames[evmasm::Instruction::KECCAK256] = "keccak256";
|
||||
}
|
||||
return s_instructionNames;
|
||||
}
|
||||
|
||||
Parser::ElementaryOperation Parser::parseElementaryOperation()
|
||||
{
|
||||
RecursionGuard recursionGuard(*this);
|
||||
|
@ -86,7 +86,6 @@ protected:
|
||||
ForLoop parseForLoop();
|
||||
/// Parses a functional expression that has to push exactly one stack element
|
||||
Expression parseExpression();
|
||||
static std::map<evmasm::Instruction, std::string> const& instructionNames();
|
||||
/// Parses an elementary operation, i.e. a literal, identifier, instruction or
|
||||
/// builtin functian call (only the name).
|
||||
ElementaryOperation parseElementaryOperation();
|
||||
|
@ -50,6 +50,7 @@ class AbstractAssembly
|
||||
public:
|
||||
using LabelID = size_t;
|
||||
using SubID = size_t;
|
||||
enum class JumpType { Ordinary, IntoFunction, OutOfFunction };
|
||||
|
||||
virtual ~AbstractAssembly() = default;
|
||||
|
||||
@ -78,13 +79,13 @@ public:
|
||||
/// Append a jump instruction.
|
||||
/// @param _stackDiffAfter the stack adjustment after this instruction.
|
||||
/// This is helpful to stack height analysis if there is no continuing control flow.
|
||||
virtual void appendJump(int _stackDiffAfter) = 0;
|
||||
virtual void appendJump(int _stackDiffAfter, JumpType _jumpType = JumpType::Ordinary) = 0;
|
||||
|
||||
/// Append a jump-to-immediate operation.
|
||||
/// @param _stackDiffAfter the stack adjustment after this instruction.
|
||||
virtual void appendJumpTo(LabelID _labelId, int _stackDiffAfter = 0) = 0;
|
||||
virtual void appendJumpTo(LabelID _labelId, int _stackDiffAfter = 0, JumpType _jumpType = JumpType::Ordinary) = 0;
|
||||
/// Append a jump-to-if-immediate operation.
|
||||
virtual void appendJumpToIf(LabelID _labelId) = 0;
|
||||
virtual void appendJumpToIf(LabelID _labelId, JumpType _jumpType = JumpType::Ordinary) = 0;
|
||||
/// Start a subroutine identified by @a _labelId that takes @a _arguments
|
||||
/// stack slots as arguments.
|
||||
virtual void appendBeginsub(LabelID _labelId, int _arguments) = 0;
|
||||
|
@ -98,22 +98,22 @@ void EthAssemblyAdapter::appendLinkerSymbol(std::string const& _linkerSymbol)
|
||||
m_assembly.appendLibraryAddress(_linkerSymbol);
|
||||
}
|
||||
|
||||
void EthAssemblyAdapter::appendJump(int _stackDiffAfter)
|
||||
void EthAssemblyAdapter::appendJump(int _stackDiffAfter, JumpType _jumpType)
|
||||
{
|
||||
appendInstruction(evmasm::Instruction::JUMP);
|
||||
appendJumpInstruction(evmasm::Instruction::JUMP, _jumpType);
|
||||
m_assembly.adjustDeposit(_stackDiffAfter);
|
||||
}
|
||||
|
||||
void EthAssemblyAdapter::appendJumpTo(LabelID _labelId, int _stackDiffAfter)
|
||||
void EthAssemblyAdapter::appendJumpTo(LabelID _labelId, int _stackDiffAfter, JumpType _jumpType)
|
||||
{
|
||||
appendLabelReference(_labelId);
|
||||
appendJump(_stackDiffAfter);
|
||||
appendJump(_stackDiffAfter, _jumpType);
|
||||
}
|
||||
|
||||
void EthAssemblyAdapter::appendJumpToIf(LabelID _labelId)
|
||||
void EthAssemblyAdapter::appendJumpToIf(LabelID _labelId, JumpType _jumpType)
|
||||
{
|
||||
appendLabelReference(_labelId);
|
||||
appendInstruction(evmasm::Instruction::JUMPI);
|
||||
appendJumpInstruction(evmasm::Instruction::JUMPI, _jumpType);
|
||||
}
|
||||
|
||||
void EthAssemblyAdapter::appendBeginsub(LabelID, int)
|
||||
@ -189,6 +189,25 @@ EthAssemblyAdapter::LabelID EthAssemblyAdapter::assemblyTagToIdentifier(evmasm::
|
||||
return LabelID(id);
|
||||
}
|
||||
|
||||
void EthAssemblyAdapter::appendJumpInstruction(evmasm::Instruction _instruction, JumpType _jumpType)
|
||||
{
|
||||
yulAssert(_instruction == evmasm::Instruction::JUMP || _instruction == evmasm::Instruction::JUMPI, "");
|
||||
evmasm::AssemblyItem jump(_instruction);
|
||||
switch (_jumpType)
|
||||
{
|
||||
case JumpType::Ordinary:
|
||||
yulAssert(jump.getJumpType() == evmasm::AssemblyItem::JumpType::Ordinary, "");
|
||||
break;
|
||||
case JumpType::IntoFunction:
|
||||
jump.setJumpType(evmasm::AssemblyItem::JumpType::IntoFunction);
|
||||
break;
|
||||
case JumpType::OutOfFunction:
|
||||
jump.setJumpType(evmasm::AssemblyItem::JumpType::OutOfFunction);
|
||||
break;
|
||||
}
|
||||
m_assembly.append(std::move(jump));
|
||||
}
|
||||
|
||||
void CodeGenerator::assemble(
|
||||
Block const& _parsedData,
|
||||
AsmAnalysisInfo& _analysisInfo,
|
||||
|
@ -49,9 +49,9 @@ public:
|
||||
size_t newLabelId() override;
|
||||
size_t namedLabel(std::string const& _name) override;
|
||||
void appendLinkerSymbol(std::string const& _linkerSymbol) override;
|
||||
void appendJump(int _stackDiffAfter) override;
|
||||
void appendJumpTo(LabelID _labelId, int _stackDiffAfter) override;
|
||||
void appendJumpToIf(LabelID _labelId) override;
|
||||
void appendJump(int _stackDiffAfter, JumpType _jumpType) override;
|
||||
void appendJumpTo(LabelID _labelId, int _stackDiffAfter, JumpType _jumpType) override;
|
||||
void appendJumpToIf(LabelID _labelId, JumpType _jumpType) override;
|
||||
void appendBeginsub(LabelID, int) override;
|
||||
void appendJumpsub(LabelID, int, int) override;
|
||||
void appendReturnsub(int, int) override;
|
||||
@ -66,6 +66,7 @@ public:
|
||||
|
||||
private:
|
||||
static LabelID assemblyTagToIdentifier(evmasm::AssemblyItem const& _tag);
|
||||
void appendJumpInstruction(evmasm::Instruction _instruction, JumpType _jumpType);
|
||||
|
||||
evmasm::Assembly& m_assembly;
|
||||
std::map<SubID, u256> m_dataHashBySubId;
|
||||
|
@ -91,14 +91,14 @@ void EVMAssembly::appendLinkerSymbol(string const&)
|
||||
yulAssert(false, "Linker symbols not yet implemented.");
|
||||
}
|
||||
|
||||
void EVMAssembly::appendJump(int _stackDiffAfter)
|
||||
void EVMAssembly::appendJump(int _stackDiffAfter, JumpType)
|
||||
{
|
||||
yulAssert(!m_evm15, "Plain JUMP used for EVM 1.5");
|
||||
appendInstruction(evmasm::Instruction::JUMP);
|
||||
m_stackHeight += _stackDiffAfter;
|
||||
}
|
||||
|
||||
void EVMAssembly::appendJumpTo(LabelID _labelId, int _stackDiffAfter)
|
||||
void EVMAssembly::appendJumpTo(LabelID _labelId, int _stackDiffAfter, JumpType _jumpType)
|
||||
{
|
||||
if (m_evm15)
|
||||
{
|
||||
@ -109,11 +109,11 @@ void EVMAssembly::appendJumpTo(LabelID _labelId, int _stackDiffAfter)
|
||||
else
|
||||
{
|
||||
appendLabelReference(_labelId);
|
||||
appendJump(_stackDiffAfter);
|
||||
appendJump(_stackDiffAfter, _jumpType);
|
||||
}
|
||||
}
|
||||
|
||||
void EVMAssembly::appendJumpToIf(LabelID _labelId)
|
||||
void EVMAssembly::appendJumpToIf(LabelID _labelId, JumpType)
|
||||
{
|
||||
if (m_evm15)
|
||||
{
|
||||
|
@ -64,11 +64,11 @@ public:
|
||||
|
||||
/// Append a jump instruction.
|
||||
/// @param _stackDiffAfter the stack adjustment after this instruction.
|
||||
void appendJump(int _stackDiffAfter) override;
|
||||
void appendJump(int _stackDiffAfter, JumpType _jumpType) override;
|
||||
/// Append a jump-to-immediate operation.
|
||||
void appendJumpTo(LabelID _labelId, int _stackDiffAfter) override;
|
||||
void appendJumpTo(LabelID _labelId, int _stackDiffAfter, JumpType _jumpType) override;
|
||||
/// Append a jump-to-if-immediate operation.
|
||||
void appendJumpToIf(LabelID _labelId) override;
|
||||
void appendJumpToIf(LabelID _labelId, JumpType _jumpType) override;
|
||||
/// Start a subroutine.
|
||||
void appendBeginsub(LabelID _labelId, int _arguments) override;
|
||||
/// Call a subroutine.
|
||||
|
@ -291,7 +291,8 @@ void CodeTransform::operator()(FunctionCall const& _call)
|
||||
{
|
||||
m_assembly.appendJumpTo(
|
||||
functionEntryID(_call.functionName.name, *function),
|
||||
static_cast<int>(function->returns.size() - function->arguments.size()) - 1
|
||||
static_cast<int>(function->returns.size() - function->arguments.size()) - 1,
|
||||
AbstractAssembly::JumpType::IntoFunction
|
||||
);
|
||||
m_assembly.appendLabel(returnLabel);
|
||||
}
|
||||
@ -511,7 +512,10 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
||||
if (m_evm15)
|
||||
m_assembly.appendReturnsub(static_cast<int>(_function.returnVariables.size()), stackHeightBefore);
|
||||
else
|
||||
m_assembly.appendJump(stackHeightBefore - static_cast<int>(_function.returnVariables.size()));
|
||||
m_assembly.appendJump(
|
||||
stackHeightBefore - static_cast<int>(_function.returnVariables.size()),
|
||||
AbstractAssembly::JumpType::OutOfFunction
|
||||
);
|
||||
m_assembly.setStackHeight(stackHeightBefore);
|
||||
}
|
||||
|
||||
|
@ -70,25 +70,25 @@ void NoOutputAssembly::appendLinkerSymbol(string const&)
|
||||
yulAssert(false, "Linker symbols not yet implemented.");
|
||||
}
|
||||
|
||||
void NoOutputAssembly::appendJump(int _stackDiffAfter)
|
||||
void NoOutputAssembly::appendJump(int _stackDiffAfter, JumpType)
|
||||
{
|
||||
yulAssert(!m_evm15, "Plain JUMP used for EVM 1.5");
|
||||
appendInstruction(evmasm::Instruction::JUMP);
|
||||
m_stackHeight += _stackDiffAfter;
|
||||
}
|
||||
|
||||
void NoOutputAssembly::appendJumpTo(LabelID _labelId, int _stackDiffAfter)
|
||||
void NoOutputAssembly::appendJumpTo(LabelID _labelId, int _stackDiffAfter, JumpType _jumpType)
|
||||
{
|
||||
if (m_evm15)
|
||||
m_stackHeight += _stackDiffAfter;
|
||||
else
|
||||
{
|
||||
appendLabelReference(_labelId);
|
||||
appendJump(_stackDiffAfter);
|
||||
appendJump(_stackDiffAfter, _jumpType);
|
||||
}
|
||||
}
|
||||
|
||||
void NoOutputAssembly::appendJumpToIf(LabelID _labelId)
|
||||
void NoOutputAssembly::appendJumpToIf(LabelID _labelId, JumpType)
|
||||
{
|
||||
if (m_evm15)
|
||||
m_stackHeight--;
|
||||
|
@ -58,9 +58,9 @@ public:
|
||||
LabelID namedLabel(std::string const& _name) override;
|
||||
void appendLinkerSymbol(std::string const& _name) override;
|
||||
|
||||
void appendJump(int _stackDiffAfter) override;
|
||||
void appendJumpTo(LabelID _labelId, int _stackDiffAfter) override;
|
||||
void appendJumpToIf(LabelID _labelId) override;
|
||||
void appendJump(int _stackDiffAfter, JumpType _jumpType) override;
|
||||
void appendJumpTo(LabelID _labelId, int _stackDiffAfter, JumpType _jumpType) override;
|
||||
void appendJumpToIf(LabelID _labelId, JumpType _jumpType) override;
|
||||
void appendBeginsub(LabelID _labelId, int _arguments) override;
|
||||
void appendJumpsub(LabelID _labelId, int _arguments, int _returns) override;
|
||||
void appendReturnsub(int _returns, int _stackDiffAfter) override;
|
||||
|
@ -36,7 +36,8 @@ Binary representation:
|
||||
Text representation:
|
||||
/* "yul_stack_opt/input.sol":495:500 */
|
||||
tag_1
|
||||
jump(tag_2)
|
||||
tag_2
|
||||
jump // in
|
||||
tag_1:
|
||||
/* "yul_stack_opt/input.sol":425:500 */
|
||||
pop
|
||||
@ -56,7 +57,8 @@ tag_1:
|
||||
pop
|
||||
/* "yul_stack_opt/input.sol":572:577 */
|
||||
tag_3
|
||||
jump(tag_2)
|
||||
tag_2
|
||||
jump // in
|
||||
tag_3:
|
||||
/* "yul_stack_opt/input.sol":502:577 */
|
||||
pop
|
||||
@ -198,5 +200,5 @@ tag_5:
|
||||
swap14
|
||||
swap15
|
||||
swap16
|
||||
jump
|
||||
jump // out
|
||||
tag_4:
|
||||
|
@ -182,6 +182,30 @@ BOOST_AUTO_TEST_CASE(location_test)
|
||||
checkAssemblyLocations(items, locations);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(jump_type)
|
||||
{
|
||||
auto sourceCode = make_shared<CharStream>(R"(
|
||||
contract C {
|
||||
function f(uint a) public pure returns (uint t) {
|
||||
assembly {
|
||||
function g(x) -> y { if x { leave } y := 8 }
|
||||
t := g(a)
|
||||
}
|
||||
}
|
||||
}
|
||||
)", "");
|
||||
AssemblyItems items = compileContract(sourceCode);
|
||||
|
||||
string jumpTypes;
|
||||
for (AssemblyItem const& item: items)
|
||||
if (item.getJumpType() != AssemblyItem::JumpType::Ordinary)
|
||||
jumpTypes += item.getJumpTypeAsString() + "\n";
|
||||
|
||||
BOOST_CHECK_EQUAL(jumpTypes, "[in]\n[out]\n[in]\n[out]\n");
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
} // end namespaces
|
||||
|
@ -0,0 +1,18 @@
|
||||
contract C {
|
||||
function f(bytes memory a, bytes calldata b, uint[] memory c)
|
||||
external
|
||||
pure
|
||||
returns (uint, byte, uint, byte, uint, uint)
|
||||
{
|
||||
return (a.length, a[1], b.length, b[2], c.length, c[3]);
|
||||
}
|
||||
function g() public returns (uint, byte, uint, byte, uint, uint) {
|
||||
uint[] memory x = new uint[](4);
|
||||
x[3] = 7;
|
||||
return this.f("abc", "def", x);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g() -> 3, 0x6200000000000000000000000000000000000000000000000000000000000000, 3, 0x6600000000000000000000000000000000000000000000000000000000000000, 4, 7
|
@ -0,0 +1,20 @@
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
contract C {
|
||||
function f(bytes memory a, bytes calldata b, uint[] memory c)
|
||||
external
|
||||
pure
|
||||
returns (uint, byte, uint, byte, uint, uint)
|
||||
{
|
||||
return (a.length, a[1], b.length, b[2], c.length, c[3]);
|
||||
}
|
||||
function g() public returns (uint, byte, uint, byte, uint, uint) {
|
||||
uint[] memory x = new uint[](4);
|
||||
x[3] = 7;
|
||||
return this.f("abc", "def", x);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g() -> 3, 0x6200000000000000000000000000000000000000000000000000000000000000, 3, 0x6600000000000000000000000000000000000000000000000000000000000000, 4, 7
|
@ -16,7 +16,7 @@ contract B is A {
|
||||
function i(uint[] memory) public override payable {}
|
||||
}
|
||||
// ----
|
||||
// DeclarationError 1686: (300-353): Function with same name and arguments defined twice.
|
||||
// DeclarationError 1686: (358-419): Function with same name and arguments defined twice.
|
||||
// DeclarationError 1686: (424-485): Function with same name and arguments defined twice.
|
||||
// DeclarationError 1686: (490-546): Function with same name and arguments defined twice.
|
||||
// DeclarationError 1686: (300-353): Function with same name and parameter types defined twice.
|
||||
// DeclarationError 1686: (358-419): Function with same name and parameter types defined twice.
|
||||
// DeclarationError 1686: (424-485): Function with same name and parameter types defined twice.
|
||||
// DeclarationError 1686: (490-546): Function with same name and parameter types defined twice.
|
||||
|
@ -3,4 +3,4 @@ contract A {
|
||||
function f(uint[] memory) internal pure {}
|
||||
}
|
||||
// ----
|
||||
// DeclarationError 1686: (17-61): Function with same name and arguments defined twice.
|
||||
// DeclarationError 1686: (17-61): Function with same name and parameter types defined twice.
|
||||
|
@ -3,4 +3,4 @@ contract test {
|
||||
event A(uint i);
|
||||
}
|
||||
// ----
|
||||
// DeclarationError 5883: (20-36): Event with same name and arguments defined twice.
|
||||
// DeclarationError 5883: (20-36): Event with same name and parameter types defined twice.
|
||||
|
@ -3,4 +3,4 @@ contract test {
|
||||
event A(uint i) anonymous;
|
||||
}
|
||||
// ----
|
||||
// DeclarationError 5883: (20-36): Event with same name and arguments defined twice.
|
||||
// DeclarationError 5883: (20-36): Event with same name and parameter types defined twice.
|
||||
|
@ -3,4 +3,4 @@ contract test {
|
||||
event A(uint indexed i);
|
||||
}
|
||||
// ----
|
||||
// DeclarationError 5883: (20-36): Event with same name and arguments defined twice.
|
||||
// DeclarationError 5883: (20-36): Event with same name and parameter types defined twice.
|
||||
|
@ -3,4 +3,4 @@ contract C {
|
||||
function test(uint a) external {}
|
||||
}
|
||||
// ----
|
||||
// DeclarationError 1686: (17-66): Function with same name and arguments defined twice.
|
||||
// DeclarationError 1686: (17-66): Function with same name and parameter types defined twice.
|
||||
|
@ -6,4 +6,4 @@ contract test {
|
||||
function fun(uint a) public returns(uint r) { return a; }
|
||||
}
|
||||
// ----
|
||||
// DeclarationError 1686: (189-246): Function with same name and arguments defined twice.
|
||||
// DeclarationError 1686: (189-246): Function with same name and parameter types defined twice.
|
||||
|
@ -3,4 +3,4 @@ contract test {
|
||||
function fun() public { }
|
||||
}
|
||||
// ----
|
||||
// DeclarationError 1686: (20-45): Function with same name and arguments defined twice.
|
||||
// DeclarationError 1686: (20-45): Function with same name and parameter types defined twice.
|
||||
|
@ -13,12 +13,12 @@ object "Contract" {
|
||||
// tag_2:
|
||||
// /* "source":46:48 */
|
||||
// tag_3:
|
||||
// jump
|
||||
// jump // out
|
||||
// /* "source":53:68 */
|
||||
// tag_4:
|
||||
// /* "source":66:68 */
|
||||
// tag_5:
|
||||
// jump
|
||||
// jump // out
|
||||
// tag_1:
|
||||
// /* "source":83:84 */
|
||||
// 0x01
|
||||
@ -28,4 +28,4 @@ object "Contract" {
|
||||
// sstore
|
||||
// Bytecode: 6009565b5b565b5b565b6001600055
|
||||
// Opcodes: PUSH1 0x9 JUMP JUMPDEST JUMPDEST JUMP JUMPDEST JUMPDEST JUMP JUMPDEST PUSH1 0x1 PUSH1 0x0 SSTORE
|
||||
// SourceMappings: 33:15:0:-:0;;;46:2;;53:15;66:2;;;83:1;80;73:12
|
||||
// SourceMappings: 33:15:0:-:0;;;46:2;:::o;53:15::-;66:2;:::o;:::-;83:1;80;73:12
|
||||
|
64
test/libyul/objectCompiler/jump_tags.yul
Normal file
64
test/libyul/objectCompiler/jump_tags.yul
Normal file
@ -0,0 +1,64 @@
|
||||
object "Contract" {
|
||||
code {
|
||||
function f() { g(1) }
|
||||
function g(x) { if x { leave } g(add(x, 2)) }
|
||||
g(1)
|
||||
}
|
||||
}
|
||||
|
||||
// ----
|
||||
// Assembly:
|
||||
// /* "source":33:54 */
|
||||
// jump(tag_1)
|
||||
// tag_2:
|
||||
// /* "source":48:52 */
|
||||
// tag_4
|
||||
// /* "source":50:51 */
|
||||
// 0x01
|
||||
// /* "source":48:52 */
|
||||
// tag_5
|
||||
// jump // in
|
||||
// tag_4:
|
||||
// /* "source":46:54 */
|
||||
// tag_3:
|
||||
// jump // out
|
||||
// /* "source":59:104 */
|
||||
// tag_5:
|
||||
// /* "source":78:79 */
|
||||
// dup1
|
||||
// /* "source":75:77 */
|
||||
// iszero
|
||||
// tag_7
|
||||
// jumpi
|
||||
// /* "source":82:87 */
|
||||
// jump(tag_6)
|
||||
// /* "source":75:77 */
|
||||
// tag_7:
|
||||
// /* "source":90:102 */
|
||||
// tag_8
|
||||
// /* "source":99:100 */
|
||||
// 0x02
|
||||
// /* "source":96:97 */
|
||||
// dup3
|
||||
// /* "source":92:101 */
|
||||
// add
|
||||
// /* "source":90:102 */
|
||||
// tag_5
|
||||
// jump // in
|
||||
// tag_8:
|
||||
// /* "source":73:104 */
|
||||
// tag_6:
|
||||
// pop
|
||||
// jump // out
|
||||
// tag_1:
|
||||
// /* "source":109:113 */
|
||||
// tag_9
|
||||
// /* "source":111:112 */
|
||||
// 0x01
|
||||
// /* "source":109:113 */
|
||||
// tag_5
|
||||
// jump // in
|
||||
// tag_9:
|
||||
// Bytecode: 6025565b600b6001600e565b5b565b80156017576022565b602160028201600e565b5b50565b602d6001600e565b
|
||||
// Opcodes: PUSH1 0x25 JUMP JUMPDEST PUSH1 0xB PUSH1 0x1 PUSH1 0xE JUMP JUMPDEST JUMPDEST JUMP JUMPDEST DUP1 ISZERO PUSH1 0x17 JUMPI PUSH1 0x22 JUMP JUMPDEST PUSH1 0x21 PUSH1 0x2 DUP3 ADD PUSH1 0xE JUMP JUMPDEST JUMPDEST POP JUMP JUMPDEST PUSH1 0x2D PUSH1 0x1 PUSH1 0xE JUMP JUMPDEST
|
||||
// SourceMappings: 33:21:0:-:0;;;48:4;50:1;48:4;:::i;:::-;46:8;:::o;59:45::-;78:1;75:2;;;82:5;;75:2;90:12;99:1;96;92:9;90:12;:::i;:::-;73:31;;:::o;:::-;109:4;111:1;109:4;:::i;:::-
|
10
test/libyul/yulSyntaxTests/assignment_duplicate_vars.yul
Normal file
10
test/libyul/yulSyntaxTests/assignment_duplicate_vars.yul
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
function f() -> a, b {}
|
||||
function g() -> a, b, c {}
|
||||
let x, y
|
||||
x, x := f()
|
||||
y, x, y := g()
|
||||
}
|
||||
// ----
|
||||
// DeclarationError 9005: (70-81): Variable x occurs multiple times on the left-hand side of the assignment.
|
||||
// DeclarationError 9005: (84-98): Variable y occurs multiple times on the left-hand side of the assignment.
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
function f() -> a, b {}
|
||||
let x, x := f()
|
||||
}
|
||||
// ----
|
||||
// DeclarationError 1395: (30-45): Variable name x already taken in this scope.
|
Loading…
Reference in New Issue
Block a user