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 {
T(StrictWith, "Strict mode code may not include a with statement") \
T(TailCallInCatchBlock, \
"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(TemplateOctalLiteral, \
"Octal literals are not allowed in template strings.") \
......
......@@ -198,6 +198,15 @@ class ParserBase : public Traits {
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 {
public:
FunctionState(FunctionState** function_state_stack, Scope** scope_stack,
......@@ -259,16 +268,16 @@ class ParserBase : public Traits {
return expressions_in_tail_position_;
}
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));
}
}
bool collect_expressions_in_tail_position() const {
return collect_expressions_in_tail_position_;
ReturnExprContext return_expr_context() const {
return return_expr_context_;
}
void set_collect_expressions_in_tail_position(bool collect) {
collect_expressions_in_tail_position_ = collect;
void set_return_expr_context(ReturnExprContext context) {
return_expr_context_ = context;
}
ZoneList<ExpressionT>* non_patterns_to_rewrite() {
......@@ -324,7 +333,7 @@ class ParserBase : public Traits {
List<DestructuringAssignment> destructuring_assignments_to_rewrite_;
List<TailCallExpression> expressions_in_tail_position_;
bool collect_expressions_in_tail_position_;
ReturnExprContext return_expr_context_;
ZoneList<ExpressionT> non_patterns_to_rewrite_;
typename Traits::Type::Factory* factory_;
......@@ -342,22 +351,22 @@ class ParserBase : public Traits {
friend class Checkpoint;
};
// This scope disables collecting of expressions at tail call position.
class DontCollectExpressionsInTailPositionScope {
// This scope sets current ReturnExprContext to given value.
class ReturnExprScope {
public:
explicit DontCollectExpressionsInTailPositionScope(
FunctionState* function_state)
explicit ReturnExprScope(FunctionState* function_state,
ReturnExprContext return_expr_context)
: function_state_(function_state),
old_value_(function_state->collect_expressions_in_tail_position()) {
function_state->set_collect_expressions_in_tail_position(false);
sav_return_expr_context_(function_state->return_expr_context()) {
function_state->set_return_expr_context(return_expr_context);
}
~DontCollectExpressionsInTailPositionScope() {
function_state_->set_collect_expressions_in_tail_position(old_value_);
~ReturnExprScope() {
function_state_->set_return_expr_context(sav_return_expr_context_);
}
private:
FunctionState* function_state_;
bool old_value_;
ReturnExprContext sav_return_expr_context_;
};
// Collects all return expressions at tail call position in this scope
......@@ -633,6 +642,23 @@ class ParserBase : public Traits {
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(
Token::Value token, MessageTemplate::Template* message,
Scanner::Location* location, const char** arg,
......@@ -990,7 +1016,7 @@ ParserBase<Traits>::FunctionState::FunctionState(
outer_function_state_(*function_state_stack),
scope_stack_(scope_stack),
outer_scope_(*scope_stack),
collect_expressions_in_tail_position_(true),
return_expr_context_(ReturnExprContext::kNormal),
non_patterns_to_rewrite_(0, scope->zone()),
factory_(factory),
next_function_is_parenthesized_(false),
......
......@@ -2639,9 +2639,10 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
// TODO(ishell): update chapter number.
// ES8 XX.YY.ZZ
if (tail_call_position >= 0) {
if (!function_state_->collect_expressions_in_tail_position()) {
Scanner::Location loc(tail_call_position, tail_call_position + 1);
ReportMessageAt(loc, MessageTemplate::kTailCallInTryBlock);
ReturnExprContext return_expr_context =
function_state_->return_expr_context();
if (return_expr_context != ReturnExprContext::kNormal) {
ReportIllegalTailCallAt(tail_call_position, return_expr_context);
*ok = false;
return NULL;
}
......@@ -2848,7 +2849,8 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
Block* try_block;
{
DontCollectExpressionsInTailPositionScope no_tail_calls(function_state_);
ReturnExprScope no_tail_calls(function_state_,
ReturnExprContext::kInsideTryBlock);
try_block = ParseBlock(NULL, CHECK_OK);
}
......@@ -3555,8 +3557,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition);
{
DontCollectExpressionsInTailPositionScope no_tail_calls(
function_state_);
ReturnExprScope no_tail_calls(function_state_,
ReturnExprContext::kInsideForInOfBody);
BlockState block_state(&scope_, body_scope);
Statement* body = ParseScopedStatement(NULL, true, CHECK_OK);
......
......@@ -693,9 +693,10 @@ PreParser::Statement PreParser::ParseReturnStatement(bool* ok) {
tok != Token::EOS) {
ParseExpression(true, CHECK_OK);
if (tail_call_position >= 0) {
if (!function_state_->collect_expressions_in_tail_position()) {
Scanner::Location loc(tail_call_position, tail_call_position + 1);
ReportMessageAt(loc, MessageTemplate::kTailCallInTryBlock);
ReturnExprContext return_expr_context =
function_state_->return_expr_context();
if (return_expr_context != ReturnExprContext::kNormal) {
ReportIllegalTailCallAt(tail_call_position, return_expr_context);
*ok = false;
return Statement::Default();
}
......@@ -850,7 +851,11 @@ PreParser::Statement PreParser::ParseForStatement(bool* 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();
}
} else {
......@@ -953,7 +958,8 @@ PreParser::Statement PreParser::ParseTryStatement(bool* ok) {
Expect(Token::TRY, CHECK_OK);
{
DontCollectExpressionsInTailPositionScope no_tail_calls(function_state_);
ReturnExprScope no_tail_calls(function_state_,
ReturnExprContext::kInsideTryBlock);
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