Disallow Yul function definitions inside for loop init blocks.

This commit is contained in:
chriseth 2019-04-18 18:10:45 +02:00
parent 5d93c492fe
commit f26cdea6ca
5 changed files with 55 additions and 1 deletions

View File

@ -7,6 +7,7 @@ Important Bugfixes:
Language Features:
* Code Generation: Implement copying recursive structs from storage to memory.
* ABIEncoderV2: Implement encoding of calldata arrays and structs.
* Yul: Disallow function definitions inside for-loop init blocks.
Compiler Features:

View File

@ -167,6 +167,7 @@ The ``continue`` and ``break`` statements can only be used inside loop bodies
and have to be in the same function as the loop (or both have to be at the
top level).
The condition part of the for-loop has to evaluate to exactly one value.
Functions cannot be defined inside for loop init blocks.
Literals cannot be larger than the their type. The largest type defined is 256-bit wide.

View File

@ -479,6 +479,13 @@ VariableDeclaration Parser::parseVariableDeclaration()
FunctionDefinition Parser::parseFunctionDefinition()
{
RecursionGuard recursionGuard(*this);
if (m_currentForLoopComponent == ForLoopComponent::ForLoopPre)
m_errorReporter.syntaxError(
location(),
"Functions cannot be defined inside a for-loop init block."
);
ForLoopComponent outerForLoopComponent = m_currentForLoopComponent;
m_currentForLoopComponent = ForLoopComponent::None;

View File

@ -82,8 +82,8 @@ BOOST_AUTO_TEST_CASE(simple_inside_structures)
"}"
"}"), "g,f");
BOOST_CHECK_EQUAL(inlinableFunctions("{"
"function g(a:u256) -> b:u256 { b := a }"
"for {"
"function g(a:u256) -> b:u256 { b := a }"
"} 1:u256 {"
"function f() -> x:u256 { x := g(2:u256) }"
"}"

View File

@ -390,6 +390,17 @@ BOOST_AUTO_TEST_CASE(for_statement_continue_fail_post)
);
}
BOOST_AUTO_TEST_CASE(for_statement_nested_continue)
{
auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople());
CHECK_ERROR_DIALECT(
"{ for {let i := 0} iszero(eq(i, 10)) {} { function f() { continue } } }",
SyntaxError,
"Keyword \"continue\" needs to be inside a for-loop body.",
dialect
);
}
BOOST_AUTO_TEST_CASE(for_statement_continue_nested_init_in_body)
{
auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople());
@ -425,6 +436,40 @@ BOOST_AUTO_TEST_CASE(for_statement_break_nested_body_in_post)
BOOST_CHECK(successParse("{ for {} 1 {let x for {} x {} { break }} {} }", dialect));
}
BOOST_AUTO_TEST_CASE(function_defined_in_init_block)
{
auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion{});
BOOST_CHECK(successParse("{ for { } 1 { function f() {} } {} }", dialect));
BOOST_CHECK(successParse("{ for { } 1 {} { function f() {} } }", dialect));
CHECK_ERROR_DIALECT(
"{ for { function f() {} } 1 {} {} }",
SyntaxError,
"Functions cannot be defined inside a for-loop init block.",
dialect
);
}
BOOST_AUTO_TEST_CASE(function_defined_in_init_nested)
{
auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion{});
BOOST_CHECK(successParse(
"{ for {"
"for { } 1 { function f() {} } {}"
"} 1 {} {} }", dialect));
CHECK_ERROR_DIALECT(
"{ for { for {function foo() {}} 1 {} {} } 1 {} {} }",
SyntaxError,
"Functions cannot be defined inside a for-loop init block.",
dialect
);
CHECK_ERROR_DIALECT(
"{ for {} 1 {for {function foo() {}} 1 {} {} } {} }",
SyntaxError,
"Functions cannot be defined inside a for-loop init block.",
dialect
);
}
BOOST_AUTO_TEST_CASE(if_statement_invalid)
{
CHECK_ERROR("{ if let x:u256 {} }", ParserError, "Literal or identifier expected.");