Commit f95e130b authored by ishell's avatar ishell Committed by Commit bot

[es8] Report proper syntax error for tail call expressions in for-in and for-of bodies.

BUG=v8:4915
LOG=Y

Review URL: https://codereview.chromium.org/1914423002

Cr-Commit-Position: refs/heads/master@{#35822}
parent 3ef2f7a8
...@@ -425,6 +425,7 @@ class CallSite { ...@@ -425,6 +425,7 @@ class CallSite {
T(StrictWith, "Strict mode code may not include a with statement") \ T(StrictWith, "Strict mode code may not include a with statement") \
T(TailCallInCatchBlock, \ T(TailCallInCatchBlock, \
"Tail call expression in catch block when finally block is also present.") \ "Tail call expression in catch block when finally block is also present.") \
T(TailCallInForInOf, "Tail call expression in for-in/of body.") \
T(TailCallInTryBlock, "Tail call expression in try block.") \ T(TailCallInTryBlock, "Tail call expression in try block.") \
T(TemplateOctalLiteral, \ T(TemplateOctalLiteral, \
"Octal literals are not allowed in template strings.") \ "Octal literals are not allowed in template strings.") \
......
...@@ -198,6 +198,15 @@ class ParserBase : public Traits { ...@@ -198,6 +198,15 @@ class ParserBase : public Traits {
int pos; int pos;
}; };
// Defines whether tail call expressions are allowed or not.
enum class ReturnExprContext {
// Tail call expressions are allowed.
kNormal,
// Tail call expressions are not allowed.
kInsideTryBlock,
kInsideForInOfBody,
};
class FunctionState BASE_EMBEDDED { class FunctionState BASE_EMBEDDED {
public: public:
FunctionState(FunctionState** function_state_stack, Scope** scope_stack, FunctionState(FunctionState** function_state_stack, Scope** scope_stack,
...@@ -259,16 +268,16 @@ class ParserBase : public Traits { ...@@ -259,16 +268,16 @@ class ParserBase : public Traits {
return expressions_in_tail_position_; return expressions_in_tail_position_;
} }
void AddExpressionInTailPosition(ExpressionT expression, int pos) { void AddExpressionInTailPosition(ExpressionT expression, int pos) {
if (collect_expressions_in_tail_position_) { if (return_expr_context() == ReturnExprContext::kNormal) {
expressions_in_tail_position_.Add(TailCallExpression(expression, pos)); expressions_in_tail_position_.Add(TailCallExpression(expression, pos));
} }
} }
bool collect_expressions_in_tail_position() const { ReturnExprContext return_expr_context() const {
return collect_expressions_in_tail_position_; return return_expr_context_;
} }
void set_collect_expressions_in_tail_position(bool collect) { void set_return_expr_context(ReturnExprContext context) {
collect_expressions_in_tail_position_ = collect; return_expr_context_ = context;
} }
ZoneList<ExpressionT>* non_patterns_to_rewrite() { ZoneList<ExpressionT>* non_patterns_to_rewrite() {
...@@ -324,7 +333,7 @@ class ParserBase : public Traits { ...@@ -324,7 +333,7 @@ class ParserBase : public Traits {
List<DestructuringAssignment> destructuring_assignments_to_rewrite_; List<DestructuringAssignment> destructuring_assignments_to_rewrite_;
List<TailCallExpression> expressions_in_tail_position_; List<TailCallExpression> expressions_in_tail_position_;
bool collect_expressions_in_tail_position_; ReturnExprContext return_expr_context_;
ZoneList<ExpressionT> non_patterns_to_rewrite_; ZoneList<ExpressionT> non_patterns_to_rewrite_;
typename Traits::Type::Factory* factory_; typename Traits::Type::Factory* factory_;
...@@ -342,22 +351,22 @@ class ParserBase : public Traits { ...@@ -342,22 +351,22 @@ class ParserBase : public Traits {
friend class Checkpoint; friend class Checkpoint;
}; };
// This scope disables collecting of expressions at tail call position. // This scope sets current ReturnExprContext to given value.
class DontCollectExpressionsInTailPositionScope { class ReturnExprScope {
public: public:
explicit DontCollectExpressionsInTailPositionScope( explicit ReturnExprScope(FunctionState* function_state,
FunctionState* function_state) ReturnExprContext return_expr_context)
: function_state_(function_state), : function_state_(function_state),
old_value_(function_state->collect_expressions_in_tail_position()) { sav_return_expr_context_(function_state->return_expr_context()) {
function_state->set_collect_expressions_in_tail_position(false); function_state->set_return_expr_context(return_expr_context);
} }
~DontCollectExpressionsInTailPositionScope() { ~ReturnExprScope() {
function_state_->set_collect_expressions_in_tail_position(old_value_); function_state_->set_return_expr_context(sav_return_expr_context_);
} }
private: private:
FunctionState* function_state_; FunctionState* function_state_;
bool old_value_; ReturnExprContext sav_return_expr_context_;
}; };
// Collects all return expressions at tail call position in this scope // Collects all return expressions at tail call position in this scope
...@@ -633,6 +642,23 @@ class ParserBase : public Traits { ...@@ -633,6 +642,23 @@ class ParserBase : public Traits {
error_type); error_type);
} }
void ReportIllegalTailCallAt(int pos, ReturnExprContext return_expr_context) {
Scanner::Location loc(pos, pos + 1);
MessageTemplate::Template msg = MessageTemplate::kNone;
switch (return_expr_context) {
case ReturnExprContext::kNormal:
UNREACHABLE();
return;
case ReturnExprContext::kInsideTryBlock:
msg = MessageTemplate::kTailCallInTryBlock;
break;
case ReturnExprContext::kInsideForInOfBody:
msg = MessageTemplate::kTailCallInForInOf;
break;
}
ReportMessageAt(loc, msg);
}
void GetUnexpectedTokenMessage( void GetUnexpectedTokenMessage(
Token::Value token, MessageTemplate::Template* message, Token::Value token, MessageTemplate::Template* message,
Scanner::Location* location, const char** arg, Scanner::Location* location, const char** arg,
...@@ -990,7 +1016,7 @@ ParserBase<Traits>::FunctionState::FunctionState( ...@@ -990,7 +1016,7 @@ ParserBase<Traits>::FunctionState::FunctionState(
outer_function_state_(*function_state_stack), outer_function_state_(*function_state_stack),
scope_stack_(scope_stack), scope_stack_(scope_stack),
outer_scope_(*scope_stack), outer_scope_(*scope_stack),
collect_expressions_in_tail_position_(true), return_expr_context_(ReturnExprContext::kNormal),
non_patterns_to_rewrite_(0, scope->zone()), non_patterns_to_rewrite_(0, scope->zone()),
factory_(factory), factory_(factory),
next_function_is_parenthesized_(false), next_function_is_parenthesized_(false),
......
...@@ -2639,9 +2639,10 @@ Statement* Parser::ParseReturnStatement(bool* ok) { ...@@ -2639,9 +2639,10 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
// TODO(ishell): update chapter number. // TODO(ishell): update chapter number.
// ES8 XX.YY.ZZ // ES8 XX.YY.ZZ
if (tail_call_position >= 0) { if (tail_call_position >= 0) {
if (!function_state_->collect_expressions_in_tail_position()) { ReturnExprContext return_expr_context =
Scanner::Location loc(tail_call_position, tail_call_position + 1); function_state_->return_expr_context();
ReportMessageAt(loc, MessageTemplate::kTailCallInTryBlock); if (return_expr_context != ReturnExprContext::kNormal) {
ReportIllegalTailCallAt(tail_call_position, return_expr_context);
*ok = false; *ok = false;
return NULL; return NULL;
} }
...@@ -2848,7 +2849,8 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { ...@@ -2848,7 +2849,8 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
Block* try_block; Block* try_block;
{ {
DontCollectExpressionsInTailPositionScope no_tail_calls(function_state_); ReturnExprScope no_tail_calls(function_state_,
ReturnExprContext::kInsideTryBlock);
try_block = ParseBlock(NULL, CHECK_OK); try_block = ParseBlock(NULL, CHECK_OK);
} }
...@@ -3555,8 +3557,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, ...@@ -3555,8 +3557,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition); factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition);
{ {
DontCollectExpressionsInTailPositionScope no_tail_calls( ReturnExprScope no_tail_calls(function_state_,
function_state_); ReturnExprContext::kInsideForInOfBody);
BlockState block_state(&scope_, body_scope); BlockState block_state(&scope_, body_scope);
Statement* body = ParseScopedStatement(NULL, true, CHECK_OK); Statement* body = ParseScopedStatement(NULL, true, CHECK_OK);
......
...@@ -693,9 +693,10 @@ PreParser::Statement PreParser::ParseReturnStatement(bool* ok) { ...@@ -693,9 +693,10 @@ PreParser::Statement PreParser::ParseReturnStatement(bool* ok) {
tok != Token::EOS) { tok != Token::EOS) {
ParseExpression(true, CHECK_OK); ParseExpression(true, CHECK_OK);
if (tail_call_position >= 0) { if (tail_call_position >= 0) {
if (!function_state_->collect_expressions_in_tail_position()) { ReturnExprContext return_expr_context =
Scanner::Location loc(tail_call_position, tail_call_position + 1); function_state_->return_expr_context();
ReportMessageAt(loc, MessageTemplate::kTailCallInTryBlock); if (return_expr_context != ReturnExprContext::kNormal) {
ReportIllegalTailCallAt(tail_call_position, return_expr_context);
*ok = false; *ok = false;
return Statement::Default(); return Statement::Default();
} }
...@@ -850,7 +851,11 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) { ...@@ -850,7 +851,11 @@ PreParser::Statement PreParser::ParseForStatement(bool* ok) {
} }
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
ParseScopedStatement(true, CHECK_OK); {
ReturnExprScope no_tail_calls(function_state_,
ReturnExprContext::kInsideForInOfBody);
ParseScopedStatement(true, CHECK_OK);
}
return Statement::Default(); return Statement::Default();
} }
} else { } else {
...@@ -953,7 +958,8 @@ PreParser::Statement PreParser::ParseTryStatement(bool* ok) { ...@@ -953,7 +958,8 @@ PreParser::Statement PreParser::ParseTryStatement(bool* ok) {
Expect(Token::TRY, CHECK_OK); Expect(Token::TRY, CHECK_OK);
{ {
DontCollectExpressionsInTailPositionScope no_tail_calls(function_state_); ReturnExprScope no_tail_calls(function_state_,
ReturnExprContext::kInsideTryBlock);
ParseBlock(CHECK_OK); ParseBlock(CHECK_OK);
} }
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-explicit-tailcalls
function f() {
return 1;
}
function g() {
for (var v in {a:0}) {
return continue f();
}
}
*%(basename)s:13: SyntaxError: Tail call expression in for-in/of body.
return continue f();
^
SyntaxError: Tail call expression in for-in/of body.
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-explicit-tailcalls
function f() {
return 1;
}
function g() {
for (var v of [1, 2, 3]) {
return continue f();
}
}
*%(basename)s:13: SyntaxError: Tail call expression in for-in/of body.
return continue f();
^
SyntaxError: Tail call expression in for-in/of body.
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