Commit 253d4e84 authored by adamk's avatar adamk Committed by Commit bot

Disallow 'await' in object literal shorthand position

Also lots of cleanup around the checking for 'await' as an identifier
throughout the parser and preparser.

R=caitp@igalia.com, littledan@chromium.org
BUG=v8:4483,v8:5298

Review-Url: https://codereview.chromium.org/2267493002
Cr-Commit-Position: refs/heads/master@{#38798}
parent 6ed87bfb
...@@ -1051,17 +1051,16 @@ class ParserBase : public Traits { ...@@ -1051,17 +1051,16 @@ class ParserBase : public Traits {
IdentifierT ParseAndClassifyIdentifier(ExpressionClassifier* classifier, IdentifierT ParseAndClassifyIdentifier(ExpressionClassifier* classifier,
bool* ok); bool* ok);
// Parses an identifier or a strict mode future reserved word, and indicate // Parses an identifier or a strict mode future reserved word, and indicate
// whether it is strict mode future reserved. Allows passing in is_generator // whether it is strict mode future reserved. Allows passing in function_kind
// for the case of parsing the identifier in a function expression, where the // for the case of parsing the identifier in a function expression, where the
// relevant "is_generator" bit is of the function being parsed, not the // relevant "function_kind" bit is of the function being parsed, not the
// containing // containing function.
// function. IdentifierT ParseIdentifierOrStrictReservedWord(FunctionKind function_kind,
IdentifierT ParseIdentifierOrStrictReservedWord(bool is_generator,
bool* is_strict_reserved, bool* is_strict_reserved,
bool* ok); bool* ok);
IdentifierT ParseIdentifierOrStrictReservedWord(bool* is_strict_reserved, IdentifierT ParseIdentifierOrStrictReservedWord(bool* is_strict_reserved,
bool* ok) { bool* ok) {
return ParseIdentifierOrStrictReservedWord(this->is_generator(), return ParseIdentifierOrStrictReservedWord(function_state_->kind(),
is_strict_reserved, ok); is_strict_reserved, ok);
} }
...@@ -1081,7 +1080,7 @@ class ParserBase : public Traits { ...@@ -1081,7 +1080,7 @@ class ParserBase : public Traits {
bool* ok); bool* ok);
ExpressionT ParseArrayLiteral(ExpressionClassifier* classifier, bool* ok); ExpressionT ParseArrayLiteral(ExpressionClassifier* classifier, bool* ok);
ExpressionT ParsePropertyName(IdentifierT* name, bool* is_get, bool* is_set, ExpressionT ParsePropertyName(IdentifierT* name, bool* is_get, bool* is_set,
bool* is_await, bool* is_computed_name, bool* is_computed_name,
ExpressionClassifier* classifier, bool* ok); ExpressionClassifier* classifier, bool* ok);
ExpressionT ParseObjectLiteral(ExpressionClassifier* classifier, bool* ok); ExpressionT ParseObjectLiteral(ExpressionClassifier* classifier, bool* ok);
ObjectLiteralPropertyT ParsePropertyDefinition( ObjectLiteralPropertyT ParsePropertyDefinition(
...@@ -1414,7 +1413,7 @@ ParserBase<Traits>::ParseAndClassifyIdentifier(ExpressionClassifier* classifier, ...@@ -1414,7 +1413,7 @@ ParserBase<Traits>::ParseAndClassifyIdentifier(ExpressionClassifier* classifier,
bool* ok) { bool* ok) {
Token::Value next = Next(); Token::Value next = Next();
if (next == Token::IDENTIFIER || next == Token::ASYNC || if (next == Token::IDENTIFIER || next == Token::ASYNC ||
(next == Token::AWAIT && !parsing_module_)) { (next == Token::AWAIT && !parsing_module_ && !is_async_function())) {
IdentifierT name = this->GetSymbol(scanner()); IdentifierT name = this->GetSymbol(scanner());
// When this function is used to read a formal parameter, we don't always // When this function is used to read a formal parameter, we don't always
// know whether the function is going to be strict or sloppy. Indeed for // know whether the function is going to be strict or sloppy. Indeed for
...@@ -1422,27 +1421,14 @@ ParserBase<Traits>::ParseAndClassifyIdentifier(ExpressionClassifier* classifier, ...@@ -1422,27 +1421,14 @@ ParserBase<Traits>::ParseAndClassifyIdentifier(ExpressionClassifier* classifier,
// is actually a formal parameter. Therefore besides the errors that we // is actually a formal parameter. Therefore besides the errors that we
// must detect because we know we're in strict mode, we also record any // must detect because we know we're in strict mode, we also record any
// error that we might make in the future once we know the language mode. // error that we might make in the future once we know the language mode.
if (this->IsEval(name)) { if (this->IsEvalOrArguments(name)) {
classifier->RecordStrictModeFormalParameterError( classifier->RecordStrictModeFormalParameterError(
scanner()->location(), MessageTemplate::kStrictEvalArguments); scanner()->location(), MessageTemplate::kStrictEvalArguments);
if (is_strict(language_mode())) { if (is_strict(language_mode())) {
classifier->RecordBindingPatternError( classifier->RecordBindingPatternError(
scanner()->location(), MessageTemplate::kStrictEvalArguments); scanner()->location(), MessageTemplate::kStrictEvalArguments);
} }
} } else if (next == Token::AWAIT) {
if (this->IsArguments(name)) {
classifier->RecordStrictModeFormalParameterError(
scanner()->location(), MessageTemplate::kStrictEvalArguments);
if (is_strict(language_mode())) {
classifier->RecordBindingPatternError(
scanner()->location(), MessageTemplate::kStrictEvalArguments);
}
}
if (this->IsAwait(name)) {
if (is_async_function()) {
classifier->RecordPatternError(
scanner()->location(), MessageTemplate::kAwaitBindingIdentifier);
}
classifier->RecordAsyncArrowFormalParametersError( classifier->RecordAsyncArrowFormalParametersError(
scanner()->location(), MessageTemplate::kAwaitBindingIdentifier); scanner()->location(), MessageTemplate::kAwaitBindingIdentifier);
} }
...@@ -1479,17 +1465,18 @@ ParserBase<Traits>::ParseAndClassifyIdentifier(ExpressionClassifier* classifier, ...@@ -1479,17 +1465,18 @@ ParserBase<Traits>::ParseAndClassifyIdentifier(ExpressionClassifier* classifier,
} }
} }
template <class Traits> template <class Traits>
typename ParserBase<Traits>::IdentifierT typename ParserBase<Traits>::IdentifierT
ParserBase<Traits>::ParseIdentifierOrStrictReservedWord( ParserBase<Traits>::ParseIdentifierOrStrictReservedWord(
bool is_generator, bool* is_strict_reserved, bool* ok) { FunctionKind function_kind, bool* is_strict_reserved, 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)) ||
next == Token::ASYNC) { next == Token::ASYNC) {
*is_strict_reserved = false; *is_strict_reserved = false;
} else if (next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET || } else if (next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET ||
next == Token::STATIC || (next == Token::YIELD && !is_generator)) { next == Token::STATIC ||
(next == Token::YIELD && !IsGeneratorFunction(function_kind))) {
*is_strict_reserved = true; *is_strict_reserved = true;
} else { } else {
ReportUnexpectedToken(next); ReportUnexpectedToken(next);
...@@ -1879,8 +1866,8 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral( ...@@ -1879,8 +1866,8 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral(
template <class Traits> template <class Traits>
typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParsePropertyName( typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParsePropertyName(
IdentifierT* name, bool* is_get, bool* is_set, bool* is_await, IdentifierT* name, bool* is_get, bool* is_set, bool* is_computed_name,
bool* is_computed_name, ExpressionClassifier* classifier, bool* ok) { ExpressionClassifier* classifier, bool* ok) {
Token::Value token = peek(); Token::Value token = peek();
int pos = peek_position(); int pos = peek_position();
...@@ -1925,9 +1912,6 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParsePropertyName( ...@@ -1925,9 +1912,6 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParsePropertyName(
default: default:
*name = ParseIdentifierName(CHECK_OK); *name = ParseIdentifierName(CHECK_OK);
scanner()->IsGetOrSet(is_get, is_set); scanner()->IsGetOrSet(is_get, is_set);
if (this->IsAwait(*name)) {
*is_await = true;
}
break; break;
} }
...@@ -1947,7 +1931,6 @@ ParserBase<Traits>::ParsePropertyDefinition( ...@@ -1947,7 +1931,6 @@ ParserBase<Traits>::ParsePropertyDefinition(
has_seen_constructor != nullptr); has_seen_constructor != nullptr);
bool is_get = false; bool is_get = false;
bool is_set = false; bool is_set = false;
bool is_await = false;
bool is_generator = Check(Token::MUL); bool is_generator = Check(Token::MUL);
bool is_async = false; bool is_async = false;
const bool is_static = IsStaticMethod(method_kind); const bool is_static = IsStaticMethod(method_kind);
...@@ -1964,9 +1947,9 @@ ParserBase<Traits>::ParsePropertyDefinition( ...@@ -1964,9 +1947,9 @@ ParserBase<Traits>::ParsePropertyDefinition(
int next_beg_pos = scanner()->peek_location().beg_pos; int next_beg_pos = scanner()->peek_location().beg_pos;
int next_end_pos = scanner()->peek_location().end_pos; int next_end_pos = scanner()->peek_location().end_pos;
ExpressionT name_expression = ParsePropertyName( ExpressionT name_expression =
name, &is_get, &is_set, &is_await, is_computed_name, classifier, ParsePropertyName(name, &is_get, &is_set, is_computed_name, classifier,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
if (fni_ != nullptr && !*is_computed_name) { if (fni_ != nullptr && !*is_computed_name) {
this->PushLiteralName(fni_, *name); this->PushLiteralName(fni_, *name);
...@@ -1994,7 +1977,7 @@ ParserBase<Traits>::ParsePropertyDefinition( ...@@ -1994,7 +1977,7 @@ ParserBase<Traits>::ParsePropertyDefinition(
} }
if (Token::IsIdentifier(name_token, language_mode(), this->is_generator(), if (Token::IsIdentifier(name_token, language_mode(), this->is_generator(),
parsing_module_) && parsing_module_ || is_async_function()) &&
(peek() == Token::COMMA || peek() == Token::RBRACE || (peek() == Token::COMMA || peek() == Token::RBRACE ||
peek() == Token::ASSIGN)) { peek() == Token::ASSIGN)) {
// PropertyDefinition // PropertyDefinition
...@@ -2017,16 +2000,11 @@ ParserBase<Traits>::ParsePropertyDefinition( ...@@ -2017,16 +2000,11 @@ ParserBase<Traits>::ParsePropertyDefinition(
classifier->RecordLetPatternError( classifier->RecordLetPatternError(
scanner()->location(), MessageTemplate::kLetInLexicalBinding); scanner()->location(), MessageTemplate::kLetInLexicalBinding);
} }
if (is_await) { if (name_token == Token::AWAIT) {
if (is_async_function()) { DCHECK(!is_async_function());
classifier->RecordPatternError( classifier->RecordAsyncArrowFormalParametersError(
Scanner::Location(next_beg_pos, next_end_pos), Scanner::Location(next_beg_pos, next_end_pos),
MessageTemplate::kAwaitBindingIdentifier); MessageTemplate::kAwaitBindingIdentifier);
} else {
classifier->RecordAsyncArrowFormalParametersError(
Scanner::Location(next_beg_pos, next_end_pos),
MessageTemplate::kAwaitBindingIdentifier);
}
} }
ExpressionT lhs = ExpressionT lhs =
this->ExpressionFromIdentifier(*name, next_beg_pos, next_end_pos); this->ExpressionFromIdentifier(*name, next_beg_pos, next_end_pos);
...@@ -2069,7 +2047,7 @@ ParserBase<Traits>::ParsePropertyDefinition( ...@@ -2069,7 +2047,7 @@ ParserBase<Traits>::ParsePropertyDefinition(
DCHECK(!is_set); DCHECK(!is_set);
bool dont_care; bool dont_care;
name_expression = ParsePropertyName( name_expression = ParsePropertyName(
name, &dont_care, &dont_care, &dont_care, is_computed_name, classifier, name, &dont_care, &dont_care, is_computed_name, classifier,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
method_kind |= MethodKind::kAsync; method_kind |= MethodKind::kAsync;
} }
...@@ -2126,7 +2104,7 @@ ParserBase<Traits>::ParsePropertyDefinition( ...@@ -2126,7 +2104,7 @@ ParserBase<Traits>::ParsePropertyDefinition(
name_token = peek(); name_token = peek();
name_expression = ParsePropertyName( name_expression = ParsePropertyName(
name, &dont_care, &dont_care, &dont_care, is_computed_name, classifier, name, &dont_care, &dont_care, is_computed_name, classifier,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
if (!*is_computed_name) { if (!*is_computed_name) {
...@@ -3103,7 +3081,9 @@ ParserBase<Traits>::ParseMemberExpression(ExpressionClassifier* classifier, ...@@ -3103,7 +3081,9 @@ ParserBase<Traits>::ParseMemberExpression(ExpressionClassifier* classifier,
return this->FunctionSentExpression(factory(), pos); return this->FunctionSentExpression(factory(), pos);
} }
bool is_generator = Check(Token::MUL); FunctionKind function_kind = Check(Token::MUL)
? FunctionKind::kGeneratorFunction
: FunctionKind::kNormalFunction;
IdentifierT name = this->EmptyIdentifier(); IdentifierT name = this->EmptyIdentifier();
bool is_strict_reserved_name = false; bool is_strict_reserved_name = false;
Scanner::Location function_name_location = Scanner::Location::invalid(); Scanner::Location function_name_location = Scanner::Location::invalid();
...@@ -3111,7 +3091,7 @@ ParserBase<Traits>::ParseMemberExpression(ExpressionClassifier* classifier, ...@@ -3111,7 +3091,7 @@ ParserBase<Traits>::ParseMemberExpression(ExpressionClassifier* classifier,
FunctionLiteral::kAnonymousExpression; FunctionLiteral::kAnonymousExpression;
if (peek_any_identifier()) { if (peek_any_identifier()) {
name = ParseIdentifierOrStrictReservedWord( name = ParseIdentifierOrStrictReservedWord(
is_generator, &is_strict_reserved_name, CHECK_OK); function_kind, &is_strict_reserved_name, CHECK_OK);
function_name_location = scanner()->location(); function_name_location = scanner()->location();
function_type = FunctionLiteral::kNamedExpression; function_type = FunctionLiteral::kNamedExpression;
} }
...@@ -3119,9 +3099,8 @@ ParserBase<Traits>::ParseMemberExpression(ExpressionClassifier* classifier, ...@@ -3119,9 +3099,8 @@ ParserBase<Traits>::ParseMemberExpression(ExpressionClassifier* classifier,
name, function_name_location, name, function_name_location,
is_strict_reserved_name ? kFunctionNameIsStrictReserved is_strict_reserved_name ? kFunctionNameIsStrictReserved
: kFunctionNameValidityUnknown, : kFunctionNameValidityUnknown,
is_generator ? FunctionKind::kGeneratorFunction function_kind, function_token_position, function_type, language_mode(),
: FunctionKind::kNormalFunction, CHECK_OK);
function_token_position, function_type, language_mode(), CHECK_OK);
} else if (peek() == Token::SUPER) { } else if (peek() == Token::SUPER) {
const bool is_new = false; const bool is_new = false;
result = ParseSuperExpression(is_new, CHECK_OK); result = ParseSuperExpression(is_new, CHECK_OK);
......
...@@ -313,10 +313,6 @@ bool ParserTraits::IsUndefined(const AstRawString* identifier) const { ...@@ -313,10 +313,6 @@ bool ParserTraits::IsUndefined(const AstRawString* identifier) const {
return identifier == parser_->ast_value_factory()->undefined_string(); return identifier == parser_->ast_value_factory()->undefined_string();
} }
bool ParserTraits::IsAwait(const AstRawString* identifier) const {
return identifier == parser_->ast_value_factory()->await_string();
}
bool ParserTraits::IsPrototype(const AstRawString* identifier) const { bool ParserTraits::IsPrototype(const AstRawString* identifier) const {
return identifier == parser_->ast_value_factory()->prototype_string(); return identifier == parser_->ast_value_factory()->prototype_string();
} }
...@@ -2090,13 +2086,6 @@ Statement* Parser::ParseHoistableDeclaration( ...@@ -2090,13 +2086,6 @@ Statement* Parser::ParseHoistableDeclaration(
variable_name = name; variable_name = name;
} }
if (V8_UNLIKELY(is_async_function() && this->IsAwait(name))) {
ReportMessageAt(scanner()->location(),
MessageTemplate::kAwaitBindingIdentifier);
*ok = false;
return nullptr;
}
FuncNameInferrer::State fni_state(fni_); FuncNameInferrer::State fni_state(fni_);
if (fni_ != NULL) fni_->PushEnclosingName(name); if (fni_ != NULL) fni_->PushEnclosingName(name);
FunctionLiteral* fun = ParseFunctionLiteral( FunctionLiteral* fun = ParseFunctionLiteral(
...@@ -4401,13 +4390,8 @@ Expression* Parser::ParseAsyncFunctionExpression(bool* ok) { ...@@ -4401,13 +4390,8 @@ Expression* Parser::ParseAsyncFunctionExpression(bool* ok) {
if (peek_any_identifier()) { if (peek_any_identifier()) {
type = FunctionLiteral::kNamedExpression; type = FunctionLiteral::kNamedExpression;
name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK); name = ParseIdentifierOrStrictReservedWord(FunctionKind::kAsyncFunction,
if (this->IsAwait(name)) { &is_strict_reserved, CHECK_OK);
ReportMessageAt(scanner()->location(),
MessageTemplate::kAwaitBindingIdentifier);
*ok = false;
return nullptr;
}
} }
return ParseFunctionLiteral(name, scanner()->location(), return ParseFunctionLiteral(name, scanner()->location(),
is_strict_reserved ? kFunctionNameIsStrictReserved is_strict_reserved ? kFunctionNameIsStrictReserved
......
...@@ -177,7 +177,6 @@ class ParserTraits { ...@@ -177,7 +177,6 @@ class ParserTraits {
bool IsArguments(const AstRawString* identifier) const; bool IsArguments(const AstRawString* identifier) const;
bool IsEvalOrArguments(const AstRawString* identifier) const; bool IsEvalOrArguments(const AstRawString* identifier) const;
bool IsUndefined(const AstRawString* identifier) const; bool IsUndefined(const AstRawString* identifier) const;
bool IsAwait(const AstRawString* identifier) const;
V8_INLINE bool IsFutureStrictReserved(const AstRawString* identifier) const; V8_INLINE bool IsFutureStrictReserved(const AstRawString* identifier) const;
// Returns true if the expression is of type "this.foo". // Returns true if the expression is of type "this.foo".
......
...@@ -404,13 +404,6 @@ PreParser::Statement PreParser::ParseHoistableDeclaration( ...@@ -404,13 +404,6 @@ PreParser::Statement PreParser::ParseHoistableDeclaration(
Identifier name = ParseIdentifierOrStrictReservedWord( Identifier name = ParseIdentifierOrStrictReservedWord(
&is_strict_reserved, CHECK_OK); &is_strict_reserved, CHECK_OK);
if (V8_UNLIKELY(is_async_function() && this->IsAwait(name))) {
ReportMessageAt(scanner()->location(),
MessageTemplate::kAwaitBindingIdentifier);
*ok = false;
return Statement::Default();
}
ParseFunctionLiteral(name, scanner()->location(), ParseFunctionLiteral(name, scanner()->location(),
is_strict_reserved ? kFunctionNameIsStrictReserved is_strict_reserved ? kFunctionNameIsStrictReserved
: kFunctionNameValidityUnknown, : kFunctionNameValidityUnknown,
...@@ -1163,13 +1156,8 @@ PreParser::Expression PreParser::ParseAsyncFunctionExpression(bool* ok) { ...@@ -1163,13 +1156,8 @@ PreParser::Expression PreParser::ParseAsyncFunctionExpression(bool* ok) {
if (peek_any_identifier()) { if (peek_any_identifier()) {
type = FunctionLiteral::kNamedExpression; type = FunctionLiteral::kNamedExpression;
name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK); name = ParseIdentifierOrStrictReservedWord(FunctionKind::kAsyncFunction,
if (this->IsAwait(name)) { &is_strict_reserved, CHECK_OK);
ReportMessageAt(scanner()->location(),
MessageTemplate::kAwaitBindingIdentifier);
*ok = false;
return Expression::Default();
}
} }
ParseFunctionLiteral(name, scanner()->location(), ParseFunctionLiteral(name, scanner()->location(),
......
...@@ -200,7 +200,7 @@ class Token { ...@@ -200,7 +200,7 @@ class Token {
} }
static bool IsIdentifier(Value tok, LanguageMode language_mode, static bool IsIdentifier(Value tok, LanguageMode language_mode,
bool is_generator, bool is_module) { bool is_generator, bool disallow_await) {
switch (tok) { switch (tok) {
case IDENTIFIER: case IDENTIFIER:
case ASYNC: case ASYNC:
...@@ -213,7 +213,7 @@ class Token { ...@@ -213,7 +213,7 @@ class Token {
case YIELD: case YIELD:
return !is_generator && is_sloppy(language_mode); return !is_generator && is_sloppy(language_mode);
case AWAIT: case AWAIT:
return !is_module; return !disallow_await;
default: default:
return false; return false;
} }
......
...@@ -7865,6 +7865,8 @@ TEST(AsyncAwaitErrors) { ...@@ -7865,6 +7865,8 @@ TEST(AsyncAwaitErrors) {
"var f = async() => await;", "var f = async() => await;",
"var f = async() => { await; };", "var f = async() => { await; };",
"async function f() { return {await} }",
"var asyncFn = async function*() {}", "var asyncFn = async function*() {}",
"async function* f() {}", "async function* f() {}",
"var O = { *async method() {} };", "var O = { *async method() {} };",
......
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