mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #2504 from ethereum/inlineasm-decl-empty
Support variable declarations without an assignment in assembly
This commit is contained in:
commit
b5da5f6e42
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
Features:
|
Features:
|
||||||
* Inline Assembly: Show useful error message if trying to access calldata variables.
|
* Inline Assembly: Show useful error message if trying to access calldata variables.
|
||||||
|
* Inline Assembly: Support variable declaration without initial value (defaults to 0).
|
||||||
* Type Checker: Disallow value transfers to contracts without a payable fallback function
|
* Type Checker: Disallow value transfers to contracts without a payable fallback function
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
@ -110,7 +110,7 @@ these curly braces, the following can be used (see the later sections for more d
|
|||||||
- opcodes (in "instruction style"), e.g. ``mload sload dup1 sstore``, for a list see below
|
- opcodes (in "instruction style"), e.g. ``mload sload dup1 sstore``, for a list see below
|
||||||
- opcodes in functional style, e.g. ``add(1, mlod(0))``
|
- opcodes in functional style, e.g. ``add(1, mlod(0))``
|
||||||
- labels, e.g. ``name:``
|
- labels, e.g. ``name:``
|
||||||
- variable declarations, e.g. ``let x := 7`` or ``let x := add(y, 3)``
|
- variable declarations, e.g. ``let x := 7``, ``let x := add(y, 3)`` or ``let x`` (initial value of empty (0) is assigned)
|
||||||
- identifiers (labels or assembly-local variables and externals if used as inline assembly), e.g. ``jump(name)``, ``3 x add``
|
- identifiers (labels or assembly-local variables and externals if used as inline assembly), e.g. ``jump(name)``, ``3 x add``
|
||||||
- assignments (in "instruction style"), e.g. ``3 =: x``
|
- assignments (in "instruction style"), e.g. ``3 =: x``
|
||||||
- assignments in functional style, e.g. ``x := add(y, 3)``
|
- assignments in functional style, e.g. ``x := add(y, 3)``
|
||||||
|
@ -37,10 +37,19 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl)
|
|||||||
{
|
{
|
||||||
solAssert(m_scope, "");
|
solAssert(m_scope, "");
|
||||||
|
|
||||||
int expectedItems = _varDecl.variables.size();
|
int const numVariables = _varDecl.variables.size();
|
||||||
int height = m_assembly.stackHeight();
|
int height = m_assembly.stackHeight();
|
||||||
boost::apply_visitor(*this, *_varDecl.value);
|
if (_varDecl.value)
|
||||||
expectDeposit(expectedItems, height);
|
{
|
||||||
|
boost::apply_visitor(*this, *_varDecl.value);
|
||||||
|
expectDeposit(numVariables, height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int variablesLeft = numVariables;
|
||||||
|
while (variablesLeft--)
|
||||||
|
m_assembly.appendConstant(u256(0));
|
||||||
|
}
|
||||||
for (auto const& variable: _varDecl.variables)
|
for (auto const& variable: _varDecl.variables)
|
||||||
{
|
{
|
||||||
auto& var = boost::get<Scope::Variable>(m_scope->identifiers.at(variable.name));
|
auto& var = boost::get<Scope::Variable>(m_scope->identifiers.at(variable.name));
|
||||||
|
@ -174,14 +174,20 @@ bool AsmAnalyzer::operator()(assembly::Assignment const& _assignment)
|
|||||||
|
|
||||||
bool AsmAnalyzer::operator()(assembly::VariableDeclaration const& _varDecl)
|
bool AsmAnalyzer::operator()(assembly::VariableDeclaration const& _varDecl)
|
||||||
{
|
{
|
||||||
int const expectedItems = _varDecl.variables.size();
|
bool success = true;
|
||||||
int const stackHeight = m_stackHeight;
|
int const numVariables = _varDecl.variables.size();
|
||||||
bool success = boost::apply_visitor(*this, *_varDecl.value);
|
if (_varDecl.value)
|
||||||
if ((m_stackHeight - stackHeight) != expectedItems)
|
|
||||||
{
|
{
|
||||||
m_errorReporter.declarationError(_varDecl.location, "Variable count mismatch.");
|
int const stackHeight = m_stackHeight;
|
||||||
return false;
|
success = boost::apply_visitor(*this, *_varDecl.value);
|
||||||
|
if ((m_stackHeight - stackHeight) != numVariables)
|
||||||
|
{
|
||||||
|
m_errorReporter.declarationError(_varDecl.location, "Variable count mismatch.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
m_stackHeight += numVariables;
|
||||||
|
|
||||||
for (auto const& variable: _varDecl.variables)
|
for (auto const& variable: _varDecl.variables)
|
||||||
{
|
{
|
||||||
|
@ -347,10 +347,15 @@ assembly::VariableDeclaration Parser::parseVariableDeclaration()
|
|||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
expectToken(Token::Colon);
|
if (currentToken() == Token::Colon)
|
||||||
expectToken(Token::Assign);
|
{
|
||||||
varDecl.value.reset(new Statement(parseExpression()));
|
expectToken(Token::Colon);
|
||||||
varDecl.location.end = locationOf(*varDecl.value).end;
|
expectToken(Token::Assign);
|
||||||
|
varDecl.value.reset(new Statement(parseExpression()));
|
||||||
|
varDecl.location.end = locationOf(*varDecl.value).end;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
varDecl.location.end = varDecl.variables.back().location.end;
|
||||||
return varDecl;
|
return varDecl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,8 +128,11 @@ string AsmPrinter::operator()(assembly::VariableDeclaration const& _variableDecl
|
|||||||
),
|
),
|
||||||
", "
|
", "
|
||||||
);
|
);
|
||||||
out += " := ";
|
if (_variableDeclaration.value)
|
||||||
out += boost::apply_visitor(*this, *_variableDeclaration.value);
|
{
|
||||||
|
out += " := ";
|
||||||
|
out += boost::apply_visitor(*this, *_variableDeclaration.value);
|
||||||
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,6 +131,11 @@ BOOST_AUTO_TEST_CASE(vardecl_bool)
|
|||||||
BOOST_CHECK(successParse("{ let x:bool := false:bool }"));
|
BOOST_CHECK(successParse("{ let x:bool := false:bool }"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(vardecl_empty)
|
||||||
|
{
|
||||||
|
BOOST_CHECK(successParse("{ let x:u256 }"));
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(assignment)
|
BOOST_AUTO_TEST_CASE(assignment)
|
||||||
{
|
{
|
||||||
BOOST_CHECK(successParse("{ let x:u256 := 2:u256 let y:u256 := x }"));
|
BOOST_CHECK(successParse("{ let x:u256 := 2:u256 let y:u256 := x }"));
|
||||||
|
@ -195,6 +195,11 @@ BOOST_AUTO_TEST_CASE(vardecl_bool)
|
|||||||
CHECK_PARSE_ERROR("{ let x := false }", ParserError, "True and false are not valid literals.");
|
CHECK_PARSE_ERROR("{ let x := false }", ParserError, "True and false are not valid literals.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(vardecl_empty)
|
||||||
|
{
|
||||||
|
BOOST_CHECK(successParse("{ let x }"));
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(assignment)
|
BOOST_AUTO_TEST_CASE(assignment)
|
||||||
{
|
{
|
||||||
BOOST_CHECK(successParse("{ let x := 2 7 8 add =: x }"));
|
BOOST_CHECK(successParse("{ let x := 2 7 8 add =: x }"));
|
||||||
|
@ -9723,6 +9723,24 @@ BOOST_AUTO_TEST_CASE(multi_modifiers)
|
|||||||
BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(12)));
|
BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(12)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(inlineasm_empty_let)
|
||||||
|
{
|
||||||
|
char const* sourceCode = R"(
|
||||||
|
contract C {
|
||||||
|
function f() returns (uint a, uint b) {
|
||||||
|
assembly {
|
||||||
|
let x
|
||||||
|
let y, z
|
||||||
|
a := x
|
||||||
|
b := z
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
compileAndRun(sourceCode, 0, "C");
|
||||||
|
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(0), u256(0)));
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user