Commit fe44df32 authored by Marja Hölttä's avatar Marja Hölttä Committed by Commit Bot

[parser] Fix: forbid await as class name in async arrow function formal params.

The bug was that we didn't track using await as a class name inside
arrow function formal parameters, and hence didn't recognize the error
in this case:

async(x = class await {}) => {}

BUG=v8:6714

Change-Id: Iabe6c947a4f621fb72361671d77f4765ba1a9578
Reviewed-on: https://chromium-review.googlesource.com/616776Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Commit-Queue: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47407}
parent d52010e0
...@@ -1027,11 +1027,11 @@ class ParserBase { ...@@ -1027,11 +1027,11 @@ class ParserBase {
// containing function. // containing function.
IdentifierT ParseIdentifierOrStrictReservedWord(FunctionKind function_kind, IdentifierT ParseIdentifierOrStrictReservedWord(FunctionKind function_kind,
bool* is_strict_reserved, bool* is_strict_reserved,
bool* ok); bool* is_await, bool* ok);
IdentifierT ParseIdentifierOrStrictReservedWord(bool* is_strict_reserved, IdentifierT ParseIdentifierOrStrictReservedWord(bool* is_strict_reserved,
bool* ok) { bool* is_await, bool* ok) {
return ParseIdentifierOrStrictReservedWord(function_state_->kind(), return ParseIdentifierOrStrictReservedWord(
is_strict_reserved, ok); function_state_->kind(), is_strict_reserved, is_await, ok);
} }
IdentifierT ParseIdentifierName(bool* ok); IdentifierT ParseIdentifierName(bool* ok);
...@@ -1675,12 +1675,14 @@ ParserBase<Impl>::ParseAndClassifyIdentifier(bool* ok) { ...@@ -1675,12 +1675,14 @@ ParserBase<Impl>::ParseAndClassifyIdentifier(bool* ok) {
template <class Impl> template <class Impl>
typename ParserBase<Impl>::IdentifierT typename ParserBase<Impl>::IdentifierT
ParserBase<Impl>::ParseIdentifierOrStrictReservedWord( ParserBase<Impl>::ParseIdentifierOrStrictReservedWord(
FunctionKind function_kind, bool* is_strict_reserved, bool* ok) { FunctionKind function_kind, bool* is_strict_reserved, bool* is_await,
bool* ok) {
Token::Value next = Next(); Token::Value next = Next();
if (next == Token::IDENTIFIER || (next == Token::AWAIT && !parsing_module_ && if (next == Token::IDENTIFIER || (next == Token::AWAIT && !parsing_module_ &&
!IsAsyncFunction(function_kind)) || !IsAsyncFunction(function_kind)) ||
next == Token::ASYNC) { next == Token::ASYNC) {
*is_strict_reserved = false; *is_strict_reserved = false;
*is_await = next == Token::AWAIT;
} else if (next == Token::ESCAPED_STRICT_RESERVED_WORD || } else if (next == Token::ESCAPED_STRICT_RESERVED_WORD ||
next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET || next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET ||
next == Token::STATIC || next == Token::STATIC ||
...@@ -1852,9 +1854,14 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression( ...@@ -1852,9 +1854,14 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
bool is_strict_reserved_name = false; bool is_strict_reserved_name = false;
Scanner::Location class_name_location = Scanner::Location::invalid(); Scanner::Location class_name_location = Scanner::Location::invalid();
if (peek_any_identifier()) { if (peek_any_identifier()) {
bool is_await = false;
name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved_name, name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved_name,
CHECK_OK); &is_await, CHECK_OK);
class_name_location = scanner()->location(); class_name_location = scanner()->location();
if (is_await) {
classifier()->RecordAsyncArrowFormalParametersError(
scanner()->location(), MessageTemplate::kAwaitBindingIdentifier);
}
} }
return ParseClassLiteral(name, class_name_location, return ParseClassLiteral(name, class_name_location,
is_strict_reserved_name, class_token_pos, ok); is_strict_reserved_name, class_token_pos, ok);
...@@ -3442,8 +3449,9 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberExpression( ...@@ -3442,8 +3449,9 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberExpression(
Consume(Token::IDENTIFIER); Consume(Token::IDENTIFIER);
DCHECK(scanner()->CurrentMatchesContextual(Token::ANONYMOUS)); DCHECK(scanner()->CurrentMatchesContextual(Token::ANONYMOUS));
} else if (peek_any_identifier()) { } else if (peek_any_identifier()) {
bool is_await = false;
name = ParseIdentifierOrStrictReservedWord( name = ParseIdentifierOrStrictReservedWord(
function_kind, &is_strict_reserved_name, CHECK_OK); function_kind, &is_strict_reserved_name, &is_await, CHECK_OK);
function_name_location = scanner()->location(); function_name_location = scanner()->location();
function_type = FunctionLiteral::kNamedExpression; function_type = FunctionLiteral::kNamedExpression;
} }
...@@ -3904,7 +3912,8 @@ ParserBase<Impl>::ParseHoistableDeclaration( ...@@ -3904,7 +3912,8 @@ ParserBase<Impl>::ParseHoistableDeclaration(
name_validity = kSkipFunctionNameCheck; name_validity = kSkipFunctionNameCheck;
} else { } else {
bool is_strict_reserved; bool is_strict_reserved;
name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, bool is_await = false;
name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, &is_await,
CHECK_OK_CUSTOM(NullStatement)); CHECK_OK_CUSTOM(NullStatement));
name_validity = is_strict_reserved ? kFunctionNameIsStrictReserved name_validity = is_strict_reserved ? kFunctionNameIsStrictReserved
: kFunctionNameValidityUnknown; : kFunctionNameValidityUnknown;
...@@ -3967,7 +3976,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseClassDeclaration( ...@@ -3967,7 +3976,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseClassDeclaration(
if (default_export && (peek() == Token::EXTENDS || peek() == Token::LBRACE)) { if (default_export && (peek() == Token::EXTENDS || peek() == Token::LBRACE)) {
impl()->GetDefaultStrings(&name, &variable_name); impl()->GetDefaultStrings(&name, &variable_name);
} else { } else {
name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, bool is_await = false;
name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, &is_await,
CHECK_OK_CUSTOM(NullStatement)); CHECK_OK_CUSTOM(NullStatement));
variable_name = name; variable_name = name;
} }
...@@ -4478,8 +4488,12 @@ ParserBase<Impl>::ParseAsyncFunctionLiteral(bool* ok) { ...@@ -4478,8 +4488,12 @@ ParserBase<Impl>::ParseAsyncFunctionLiteral(bool* ok) {
DCHECK(scanner()->CurrentMatchesContextual(Token::ANONYMOUS)); DCHECK(scanner()->CurrentMatchesContextual(Token::ANONYMOUS));
} else if (peek_any_identifier()) { } else if (peek_any_identifier()) {
type = FunctionLiteral::kNamedExpression; type = FunctionLiteral::kNamedExpression;
bool is_await = false;
name = ParseIdentifierOrStrictReservedWord(kind, &is_strict_reserved, name = ParseIdentifierOrStrictReservedWord(kind, &is_strict_reserved,
CHECK_OK); &is_await, CHECK_OK);
// If the function name is "await", ParseIdentifierOrStrictReservedWord
// recognized the error.
DCHECK(!is_await);
} }
return impl()->ParseFunctionLiteral( return impl()->ParseFunctionLiteral(
name, scanner()->location(), name, scanner()->location(),
......
...@@ -811,9 +811,14 @@ FunctionLiteral* Parser::DoParseFunction(ParseInfo* info) { ...@@ -811,9 +811,14 @@ FunctionLiteral* Parser::DoParseFunction(ParseInfo* info) {
impl()->GetDefaultStrings(&raw_name, &variable_name); impl()->GetDefaultStrings(&raw_name, &variable_name);
} else { } else {
bool is_strict_reserved = true; bool is_strict_reserved = true;
raw_name = ParseIdentifierOrStrictReservedWord(info->function_kind(), bool is_await = false;
&is_strict_reserved, &ok); raw_name = ParseIdentifierOrStrictReservedWord(
info->function_kind(), &is_strict_reserved, &is_await, &ok);
if (!ok) return nullptr; if (!ok) return nullptr;
// If the function name is "await", ParseIdentifierOrStrictReservedWord
// recognized the error.
DCHECK(!is_await);
function_name_validity = is_strict_reserved function_name_validity = is_strict_reserved
? kFunctionNameIsStrictReserved ? kFunctionNameIsStrictReserved
: kFunctionNameValidityUnknown; : kFunctionNameValidityUnknown;
......
...@@ -9088,41 +9088,8 @@ TEST(AsyncAwaitErrors) { ...@@ -9088,41 +9088,8 @@ TEST(AsyncAwaitErrors) {
NULL NULL
}; };
const char* formal_parameters_data[] = {
"var f = async({ await }) => 1;",
"var f = async({ await = 1 }) => 1;",
"var f = async({ await } = {}) => 1;",
"var f = async({ await = 1 } = {}) => 1;",
"var f = async([await]) => 1;",
"var f = async([await] = []) => 1;",
"var f = async([await = 1]) => 1;",
"var f = async([await = 1] = []) => 1;",
"var f = async(...await) => 1;",
"var f = async(await) => 1;",
"var f = async(await = 1) => 1;",
"var f = async(...[await]) => 1;",
"var f = async(x = await) => 1;",
// v8:5190
"var f = async(1) => 1",
"var f = async('str') => 1",
"var f = async(/foo/) => 1",
"var f = async({ foo = async(1) => 1 }) => 1",
"var f = async({ foo = async(a) => 1 })",
"var f = async(x = async(await)) => 1;",
"var f = async(x = { [await]: 1 }) => 1;",
"var f = async(x = class extends (await) { }) => 1;",
"var f = async(x = class { static [await]() {} }) => 1;",
"var f = async({ x = await }) => 1;",
NULL
};
// clang-format on
RunParserSyncTest(context_data, error_data, kError); RunParserSyncTest(context_data, error_data, kError);
RunParserSyncTest(strict_context_data, strict_error_data, kError); RunParserSyncTest(strict_context_data, strict_error_data, kError);
RunParserSyncTest(context_data, formal_parameters_data, kError);
// clang-format off // clang-format off
const char* async_body_context_data[][2] = { const char* async_body_context_data[][2] = {
...@@ -9166,6 +9133,69 @@ TEST(AsyncAwaitErrors) { ...@@ -9166,6 +9133,69 @@ TEST(AsyncAwaitErrors) {
RunParserSyncTest(async_body_context_data, async_body_error_data, kError); RunParserSyncTest(async_body_context_data, async_body_error_data, kError);
} }
TEST(AsyncAwaitFormalParameters) {
// clang-format off
const char* context_for_formal_parameters[][2] = {
{ "async function f(", ") {}" },
{ "var f = async function f(", ") {}" },
{ "var f = async(", ") => {}" },
{ "'use strict'; async function f(", ") {}" },
{ "'use strict'; var f = async function f(", ") {}" },
{ "'use strict'; var f = async(", ") => {}" },
{ nullptr, nullptr }
};
const char* good_formal_parameters[] = {
"x = function await() {}",
"x = function *await() {}",
"x = function() { let await = 0; }",
"x = () => { let await = 0; }",
nullptr
};
const char* bad_formal_parameters[] = {
"{ await }",
"{ await = 1 }",
"{ await } = {}",
"{ await = 1 } = {}",
"[await]",
"[await] = []",
"[await = 1]",
"[await = 1] = []",
"...await",
"await",
"await = 1",
"...[await]",
"x = await",
// v8:5190
"1) => 1",
"'str') => 1",
"/foo/) => 1",
"{ foo = async(1) => 1 }) => 1",
"{ foo = async(a) => 1 })",
"x = async(await)",
"x = { [await]: 1 }",
"x = class extends (await) { }",
"x = class { static [await]() {} }",
"{ x = await }",
// v8:6714
"x = class await {}",
"x = 1 ? class await {} : 0",
"x = async function await() {}",
nullptr
};
// clang-format on
RunParserSyncTest(context_for_formal_parameters, good_formal_parameters,
kSuccess);
RunParserSyncTest(context_for_formal_parameters, bad_formal_parameters,
kError);
}
TEST(AsyncAwaitModule) { TEST(AsyncAwaitModule) {
// clang-format off // clang-format off
const char* context_data[][2] = { const char* context_data[][2] = {
......
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