Commit ee15703e authored by Daniel Ehrenberg's avatar Daniel Ehrenberg Committed by Commit Bot

[parser] Prohibit async functions and generators in invalid contexts

Async functions and generator declarations are only permitted as
StatementListItems, not as ExpressionStatements, and therefore not
as the entire body of an if statement, etc. Previously, they were
incorrectly permitted. However, ChakraCore and SpiderMonkey seem
to ban them in this context, and the feature was introduced relatively
recently, so it is likely to be web-compatible to ship the prohibition.

This patch also unifies the error message wording of async functions
and generators to ordinary functions, explaining more clearly what
the issue is.

Bug: v8:4483
Cq-Include-Trybots: master.tryserver.v8:v8_linux_noi18n_rel_ng
Change-Id: I31ed7818d6ab3e7e325031bfabb933dbf4512143
Reviewed-on: https://chromium-review.googlesource.com/568979
Commit-Queue: Daniel Ehrenberg <littledan@chromium.org>
Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46770}
parent 2da7a9b1
......@@ -556,8 +556,11 @@ class ErrorUtils : public AllStatic {
"% loop variable declaration may not have an initializer.") \
T(ForInOfLoopMultiBindings, \
"Invalid left-hand side in % loop: Must have a single binding.") \
T(GeneratorInLegacyContext, \
"Generator declarations are not allowed in legacy contexts.") \
T(GeneratorInSingleStatementContext, \
"Generators can only be declared at the top level or inside a block.") \
T(AsyncFunctionInSingleStatementContext, \
"Async functions can only be declared at the top level or inside a " \
"block.") \
T(IllegalBreak, "Illegal break statement") \
T(NoIterationStatement, \
"Illegal continue statement: no surrounding iteration statement") \
......
......@@ -3804,8 +3804,9 @@ ParserBase<Impl>::ParseFunctionDeclaration(bool* ok) {
int pos = position();
ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
if (Check(Token::MUL)) {
impl()->ReportMessageAt(scanner()->location(),
MessageTemplate::kGeneratorInLegacyContext);
impl()->ReportMessageAt(
scanner()->location(),
MessageTemplate::kGeneratorInSingleStatementContext);
*ok = false;
return impl()->NullStatement();
}
......@@ -4853,6 +4854,16 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement(
return ParseDebuggerStatement(ok);
case Token::VAR:
return ParseVariableStatement(kStatement, nullptr, ok);
case Token::ASYNC:
if (!scanner()->HasAnyLineTerminatorAfterNext() &&
PeekAhead() == Token::FUNCTION) {
impl()->ReportMessageAt(
scanner()->peek_location(),
MessageTemplate::kAsyncFunctionInSingleStatementContext);
*ok = false;
return impl()->NullStatement();
}
// Falls through
default:
return ParseExpressionOrLabelledStatement(labels, allow_function, ok);
}
......
......@@ -8763,11 +8763,8 @@ TEST(FunctionDeclarationError) {
"if (true) {} else label: function f() {}",
"if (true) function* f() { }",
"label: function* f() { }",
// TODO(littledan, v8:4806): Ban duplicate generator declarations in
// a block, maybe by tracking whether a Variable is a generator declaration
// "{ function* f() {} function* f() {} }",
// "{ function f() {} function* f() {} }",
// "{ function* f() {} function f() {} }",
"if (true) async function f() { }",
"label: async function f() { }",
NULL
};
// Valid only in sloppy mode.
......@@ -8789,6 +8786,20 @@ TEST(FunctionDeclarationError) {
// In sloppy mode, sloppy_data is successful
RunParserSyncTest(sloppy_context, error_data, kError);
RunParserSyncTest(sloppy_context, sloppy_data, kSuccess);
// No single statement async iterators
// clang-format off
const char* async_iterator_data[] = {
"if (true) async function* f() { }",
"label: async function* f() { }",
NULL,
};
// clang-format on
static const ParserFlag flags[] = {kAllowHarmonyAsyncIteration};
RunParserSyncTest(sloppy_context, async_iterator_data, kError, NULL, 0, flags,
arraysize(flags));
RunParserSyncTest(strict_context, async_iterator_data, kError, NULL, 0, flags,
arraysize(flags));
}
TEST(ExponentiationOperator) {
......
......@@ -511,24 +511,6 @@
'built-ins/Number/prototype/toPrecision/range': [FAIL],
'built-ins/Number/prototype/toExponential/range': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=6540
'language/statements/for/decl-async-fun': [FAIL],
'language/statements/for/decl-async-gen': [FAIL],
'language/statements/for-in/decl-async-fun': [FAIL],
'language/statements/for-in/decl-async-gen': [FAIL],
'language/statements/for-of/decl-async-fun': [FAIL],
'language/statements/for-of/decl-async-gen': [FAIL],
'language/statements/if/if-async-fun-no-else': [FAIL],
'language/statements/if/if-async-gen-no-else': [FAIL],
'language/statements/if/if-stmt-else-async-fun': [FAIL],
'language/statements/if/if-stmt-else-async-gen': [FAIL],
'language/statements/labeled/decl-async-function': [FAIL],
'language/statements/labeled/decl-async-generator': [FAIL],
'language/statements/while/decl-async-fun': [FAIL],
'language/statements/while/decl-async-gen': [FAIL],
'language/statements/with/decl-async-fun': [FAIL],
'language/statements/with/decl-async-gen': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=5855
'language/expressions/async-generator/named-yield-promise-reject-next': [FAIL],
'language/expressions/async-generator/named-yield-promise-reject-next-catch': [FAIL],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment