Commit 260af115 authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

[parsing] Fix detection of invalid continue targets.

In order to know which labels are valid continue targets, we must
track the labels that immediately prefix an iteration statement.

Also document some things that I had to figure out.

Bug: v8:8033
Change-Id: Ia8288fd0e553a547aa0f9d1b4381bb103325bc3a
Reviewed-on: https://chromium-review.googlesource.com/1172292Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Commit-Queue: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55110}
parent 4c98815a
...@@ -249,7 +249,23 @@ class Expression : public AstNode { ...@@ -249,7 +249,23 @@ class Expression : public AstNode {
static const uint8_t kNextBitFieldIndex = AstNode::kNextBitFieldIndex; static const uint8_t kNextBitFieldIndex = AstNode::kNextBitFieldIndex;
}; };
// V8's notion of BreakableStatement does not correspond to the notion of
// BreakableStatement in ECMAScript. In V8, the idea is that a
// BreakableStatement is a statement that can be the target of a break
// statement. The BreakableStatement AST node carries a list of labels, any of
// which can be used as an argument to the break statement in order to target
// it.
//
// Since we don't want to attach a list of labels to all kinds of statements, we
// only declare switchs, loops, and blocks as BreakableStatements. This means
// that we implement breaks targeting other statement forms as breaks targeting
// a substatement thereof. For instance, in "foo: if (b) { f(); break foo; }" we
// pretend that foo is the label of the inner block. That's okay because one
// can't observe the difference.
//
// This optimization makes it harder to detect invalid continue labels, see the
// need for own_labels in IterationStatement.
//
class BreakableStatement : public Statement { class BreakableStatement : public Statement {
public: public:
enum BreakableType { enum BreakableType {
...@@ -257,6 +273,13 @@ class BreakableStatement : public Statement { ...@@ -257,6 +273,13 @@ class BreakableStatement : public Statement {
TARGET_FOR_NAMED_ONLY TARGET_FOR_NAMED_ONLY
}; };
// A list of all labels declared on the path up to the previous
// BreakableStatement (if any).
//
// Example: "l1: for (;;) l2: l3: { l4: if (b) l5: { s } }"
// labels() of the ForStatement will be l1.
// labels() of the Block { l4: ... } will be l2, l3.
// labels() of the Block { s } will be l4, l5.
ZonePtrList<const AstRawString>* labels() const; ZonePtrList<const AstRawString>* labels() const;
// Testers. // Testers.
...@@ -441,11 +464,23 @@ class IterationStatement : public BreakableStatement { ...@@ -441,11 +464,23 @@ class IterationStatement : public BreakableStatement {
ZonePtrList<const AstRawString>* labels() const { return labels_; } ZonePtrList<const AstRawString>* labels() const { return labels_; }
// A list of all labels that the iteration statement is directly prefixed
// with, i.e. all the labels that a continue statement in the body can use to
// continue this iteration statement. This is always a subset of {labels}.
//
// Example: "l1: { l2: if (b) l3: l4: for (;;) s }"
// labels() of the Block will be l1.
// labels() of the ForStatement will be l2, l3, l4.
// own_labels() of the ForStatement will be l3, l4.
ZonePtrList<const AstRawString>* own_labels() const { return own_labels_; }
protected: protected:
IterationStatement(ZonePtrList<const AstRawString>* labels, int pos, IterationStatement(ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels, int pos,
NodeType type) NodeType type)
: BreakableStatement(TARGET_FOR_ANONYMOUS, pos, type), : BreakableStatement(TARGET_FOR_ANONYMOUS, pos, type),
labels_(labels), labels_(labels),
own_labels_(own_labels),
body_(nullptr) {} body_(nullptr) {}
void Initialize(Statement* body) { body_ = body; } void Initialize(Statement* body) { body_ = body; }
...@@ -454,6 +489,7 @@ class IterationStatement : public BreakableStatement { ...@@ -454,6 +489,7 @@ class IterationStatement : public BreakableStatement {
private: private:
ZonePtrList<const AstRawString>* labels_; ZonePtrList<const AstRawString>* labels_;
ZonePtrList<const AstRawString>* own_labels_;
Statement* body_; Statement* body_;
}; };
...@@ -470,8 +506,10 @@ class DoWhileStatement final : public IterationStatement { ...@@ -470,8 +506,10 @@ class DoWhileStatement final : public IterationStatement {
private: private:
friend class AstNodeFactory; friend class AstNodeFactory;
DoWhileStatement(ZonePtrList<const AstRawString>* labels, int pos) DoWhileStatement(ZonePtrList<const AstRawString>* labels,
: IterationStatement(labels, pos, kDoWhileStatement), cond_(nullptr) {} ZonePtrList<const AstRawString>* own_labels, int pos)
: IterationStatement(labels, own_labels, pos, kDoWhileStatement),
cond_(nullptr) {}
Expression* cond_; Expression* cond_;
}; };
...@@ -489,8 +527,10 @@ class WhileStatement final : public IterationStatement { ...@@ -489,8 +527,10 @@ class WhileStatement final : public IterationStatement {
private: private:
friend class AstNodeFactory; friend class AstNodeFactory;
WhileStatement(ZonePtrList<const AstRawString>* labels, int pos) WhileStatement(ZonePtrList<const AstRawString>* labels,
: IterationStatement(labels, pos, kWhileStatement), cond_(nullptr) {} ZonePtrList<const AstRawString>* own_labels, int pos)
: IterationStatement(labels, own_labels, pos, kWhileStatement),
cond_(nullptr) {}
Expression* cond_; Expression* cond_;
}; };
...@@ -513,8 +553,9 @@ class ForStatement final : public IterationStatement { ...@@ -513,8 +553,9 @@ class ForStatement final : public IterationStatement {
private: private:
friend class AstNodeFactory; friend class AstNodeFactory;
ForStatement(ZonePtrList<const AstRawString>* labels, int pos) ForStatement(ZonePtrList<const AstRawString>* labels,
: IterationStatement(labels, pos, kForStatement), ZonePtrList<const AstRawString>* own_labels, int pos)
: IterationStatement(labels, own_labels, pos, kForStatement),
init_(nullptr), init_(nullptr),
cond_(nullptr), cond_(nullptr),
next_(nullptr) {} next_(nullptr) {}
...@@ -539,9 +580,10 @@ class ForEachStatement : public IterationStatement { ...@@ -539,9 +580,10 @@ class ForEachStatement : public IterationStatement {
} }
protected: protected:
ForEachStatement(ZonePtrList<const AstRawString>* labels, int pos, ForEachStatement(ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels, int pos,
NodeType type) NodeType type)
: IterationStatement(labels, pos, type) {} : IterationStatement(labels, own_labels, pos, type) {}
}; };
...@@ -566,8 +608,9 @@ class ForInStatement final : public ForEachStatement { ...@@ -566,8 +608,9 @@ class ForInStatement final : public ForEachStatement {
private: private:
friend class AstNodeFactory; friend class AstNodeFactory;
ForInStatement(ZonePtrList<const AstRawString>* labels, int pos) ForInStatement(ZonePtrList<const AstRawString>* labels,
: ForEachStatement(labels, pos, kForInStatement), ZonePtrList<const AstRawString>* own_labels, int pos)
: ForEachStatement(labels, own_labels, pos, kForInStatement),
each_(nullptr), each_(nullptr),
subject_(nullptr) { subject_(nullptr) {
bit_field_ = ForInTypeField::update(bit_field_, SLOW_FOR_IN); bit_field_ = ForInTypeField::update(bit_field_, SLOW_FOR_IN);
...@@ -632,8 +675,9 @@ class ForOfStatement final : public ForEachStatement { ...@@ -632,8 +675,9 @@ class ForOfStatement final : public ForEachStatement {
private: private:
friend class AstNodeFactory; friend class AstNodeFactory;
ForOfStatement(ZonePtrList<const AstRawString>* labels, int pos) ForOfStatement(ZonePtrList<const AstRawString>* labels,
: ForEachStatement(labels, pos, kForOfStatement), ZonePtrList<const AstRawString>* own_labels, int pos)
: ForEachStatement(labels, own_labels, pos, kForOfStatement),
iterator_(nullptr), iterator_(nullptr),
assign_iterator_(nullptr), assign_iterator_(nullptr),
next_result_(nullptr), next_result_(nullptr),
...@@ -2810,9 +2854,11 @@ class AstNodeFactory final BASE_EMBEDDED { ...@@ -2810,9 +2854,11 @@ class AstNodeFactory final BASE_EMBEDDED {
Block(zone_, labels, capacity, ignore_completion_value); Block(zone_, labels, capacity, ignore_completion_value);
} }
#define STATEMENT_WITH_LABELS(NodeType) \ #define STATEMENT_WITH_LABELS(NodeType) \
NodeType* New##NodeType(ZonePtrList<const AstRawString>* labels, int pos) { \ NodeType* New##NodeType(ZonePtrList<const AstRawString>* labels, \
return new (zone_) NodeType(labels, pos); \ ZonePtrList<const AstRawString>* own_labels, \
int pos) { \
return new (zone_) NodeType(labels, own_labels, pos); \
} }
STATEMENT_WITH_LABELS(DoWhileStatement) STATEMENT_WITH_LABELS(DoWhileStatement)
STATEMENT_WITH_LABELS(WhileStatement) STATEMENT_WITH_LABELS(WhileStatement)
...@@ -2824,23 +2870,25 @@ class AstNodeFactory final BASE_EMBEDDED { ...@@ -2824,23 +2870,25 @@ class AstNodeFactory final BASE_EMBEDDED {
return new (zone_) SwitchStatement(zone_, labels, tag, pos); return new (zone_) SwitchStatement(zone_, labels, tag, pos);
} }
ForEachStatement* NewForEachStatement(ForEachStatement::VisitMode visit_mode, ForEachStatement* NewForEachStatement(
ZonePtrList<const AstRawString>* labels, ForEachStatement::VisitMode visit_mode,
int pos) { ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels, int pos) {
switch (visit_mode) { switch (visit_mode) {
case ForEachStatement::ENUMERATE: { case ForEachStatement::ENUMERATE: {
return new (zone_) ForInStatement(labels, pos); return new (zone_) ForInStatement(labels, own_labels, pos);
} }
case ForEachStatement::ITERATE: { case ForEachStatement::ITERATE: {
return new (zone_) ForOfStatement(labels, pos); return new (zone_) ForOfStatement(labels, own_labels, pos);
} }
} }
UNREACHABLE(); UNREACHABLE();
} }
ForOfStatement* NewForOfStatement(ZonePtrList<const AstRawString>* labels, ForOfStatement* NewForOfStatement(ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels,
int pos) { int pos) {
return new (zone_) ForOfStatement(labels, pos); return new (zone_) ForOfStatement(labels, own_labels, pos);
} }
ExpressionStatement* NewExpressionStatement(Expression* expression, int pos) { ExpressionStatement* NewExpressionStatement(Expression* expression, int pos) {
......
...@@ -749,9 +749,11 @@ void AstPrinter::PrintLiteralWithModeIndented(const char* info, Variable* var, ...@@ -749,9 +749,11 @@ void AstPrinter::PrintLiteralWithModeIndented(const char* info, Variable* var,
} }
} }
void AstPrinter::PrintLabelsIndented(ZonePtrList<const AstRawString>* labels) { void AstPrinter::PrintLabelsIndented(ZonePtrList<const AstRawString>* labels,
const char* prefix) {
if (labels == nullptr || labels->length() == 0) return; if (labels == nullptr || labels->length() == 0) return;
PrintIndented("LABELS "); PrintIndented(prefix);
Print("LABELS ");
PrintLabels(labels); PrintLabels(labels);
Print("\n"); Print("\n");
} }
...@@ -922,6 +924,7 @@ void AstPrinter::VisitSwitchStatement(SwitchStatement* node) { ...@@ -922,6 +924,7 @@ void AstPrinter::VisitSwitchStatement(SwitchStatement* node) {
void AstPrinter::VisitDoWhileStatement(DoWhileStatement* node) { void AstPrinter::VisitDoWhileStatement(DoWhileStatement* node) {
IndentedScope indent(this, "DO", node->position()); IndentedScope indent(this, "DO", node->position());
PrintLabelsIndented(node->labels()); PrintLabelsIndented(node->labels());
PrintLabelsIndented(node->own_labels(), "OWN ");
PrintIndentedVisit("BODY", node->body()); PrintIndentedVisit("BODY", node->body());
PrintIndentedVisit("COND", node->cond()); PrintIndentedVisit("COND", node->cond());
} }
...@@ -930,6 +933,7 @@ void AstPrinter::VisitDoWhileStatement(DoWhileStatement* node) { ...@@ -930,6 +933,7 @@ void AstPrinter::VisitDoWhileStatement(DoWhileStatement* node) {
void AstPrinter::VisitWhileStatement(WhileStatement* node) { void AstPrinter::VisitWhileStatement(WhileStatement* node) {
IndentedScope indent(this, "WHILE", node->position()); IndentedScope indent(this, "WHILE", node->position());
PrintLabelsIndented(node->labels()); PrintLabelsIndented(node->labels());
PrintLabelsIndented(node->own_labels(), "OWN ");
PrintIndentedVisit("COND", node->cond()); PrintIndentedVisit("COND", node->cond());
PrintIndentedVisit("BODY", node->body()); PrintIndentedVisit("BODY", node->body());
} }
...@@ -938,6 +942,7 @@ void AstPrinter::VisitWhileStatement(WhileStatement* node) { ...@@ -938,6 +942,7 @@ void AstPrinter::VisitWhileStatement(WhileStatement* node) {
void AstPrinter::VisitForStatement(ForStatement* node) { void AstPrinter::VisitForStatement(ForStatement* node) {
IndentedScope indent(this, "FOR", node->position()); IndentedScope indent(this, "FOR", node->position());
PrintLabelsIndented(node->labels()); PrintLabelsIndented(node->labels());
PrintLabelsIndented(node->own_labels(), "OWN ");
if (node->init()) PrintIndentedVisit("INIT", node->init()); if (node->init()) PrintIndentedVisit("INIT", node->init());
if (node->cond()) PrintIndentedVisit("COND", node->cond()); if (node->cond()) PrintIndentedVisit("COND", node->cond());
PrintIndentedVisit("BODY", node->body()); PrintIndentedVisit("BODY", node->body());
...@@ -947,6 +952,8 @@ void AstPrinter::VisitForStatement(ForStatement* node) { ...@@ -947,6 +952,8 @@ void AstPrinter::VisitForStatement(ForStatement* node) {
void AstPrinter::VisitForInStatement(ForInStatement* node) { void AstPrinter::VisitForInStatement(ForInStatement* node) {
IndentedScope indent(this, "FOR IN", node->position()); IndentedScope indent(this, "FOR IN", node->position());
PrintLabelsIndented(node->labels());
PrintLabelsIndented(node->own_labels(), "OWN ");
PrintIndentedVisit("FOR", node->each()); PrintIndentedVisit("FOR", node->each());
PrintIndentedVisit("IN", node->enumerable()); PrintIndentedVisit("IN", node->enumerable());
PrintIndentedVisit("BODY", node->body()); PrintIndentedVisit("BODY", node->body());
...@@ -955,6 +962,8 @@ void AstPrinter::VisitForInStatement(ForInStatement* node) { ...@@ -955,6 +962,8 @@ void AstPrinter::VisitForInStatement(ForInStatement* node) {
void AstPrinter::VisitForOfStatement(ForOfStatement* node) { void AstPrinter::VisitForOfStatement(ForOfStatement* node) {
IndentedScope indent(this, "FOR OF", node->position()); IndentedScope indent(this, "FOR OF", node->position());
PrintLabelsIndented(node->labels());
PrintLabelsIndented(node->own_labels(), "OWN ");
PrintIndentedVisit("INIT", node->assign_iterator()); PrintIndentedVisit("INIT", node->assign_iterator());
PrintIndentedVisit("NEXT", node->next_result()); PrintIndentedVisit("NEXT", node->next_result());
PrintIndentedVisit("DONE", node->result_done()); PrintIndentedVisit("DONE", node->result_done());
......
...@@ -110,7 +110,8 @@ class AstPrinter final : public AstVisitor<AstPrinter> { ...@@ -110,7 +110,8 @@ class AstPrinter final : public AstVisitor<AstPrinter> {
bool quote); bool quote);
void PrintLiteralWithModeIndented(const char* info, Variable* var, void PrintLiteralWithModeIndented(const char* info, Variable* var,
const AstRawString* value); const AstRawString* value);
void PrintLabelsIndented(ZonePtrList<const AstRawString>* labels); void PrintLabelsIndented(ZonePtrList<const AstRawString>* labels,
const char* prefix = "");
void PrintObjectProperties(ZonePtrList<ObjectLiteral::Property>* properties); void PrintObjectProperties(ZonePtrList<ObjectLiteral::Property>* properties);
void PrintClassProperties(ZonePtrList<ClassLiteral::Property>* properties); void PrintClassProperties(ZonePtrList<ClassLiteral::Property>* properties);
......
...@@ -1235,10 +1235,15 @@ class ParserBase { ...@@ -1235,10 +1235,15 @@ class ParserBase {
Token::Value end_token, bool may_abort, Token::Value end_token, bool may_abort,
bool* ok); bool* ok);
StatementT ParseStatementListItem(bool* ok); StatementT ParseStatementListItem(bool* ok);
StatementT ParseStatement(ZonePtrList<const AstRawString>* labels, bool* ok) {
return ParseStatement(labels, kDisallowLabelledFunctionStatement, ok); StatementT ParseStatement(ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels,
bool* ok) {
return ParseStatement(labels, own_labels,
kDisallowLabelledFunctionStatement, ok);
} }
StatementT ParseStatement(ZonePtrList<const AstRawString>* labels, StatementT ParseStatement(ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels,
AllowLabelledFunctionStatement allow_function, AllowLabelledFunctionStatement allow_function,
bool* ok); bool* ok);
BlockT ParseBlock(ZonePtrList<const AstRawString>* labels, bool* ok); BlockT ParseBlock(ZonePtrList<const AstRawString>* labels, bool* ok);
...@@ -1262,6 +1267,7 @@ class ParserBase { ...@@ -1262,6 +1267,7 @@ class ParserBase {
StatementT ParseExpressionOrLabelledStatement( StatementT ParseExpressionOrLabelledStatement(
ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels,
AllowLabelledFunctionStatement allow_function, bool* ok); AllowLabelledFunctionStatement allow_function, bool* ok);
StatementT ParseIfStatement(ZonePtrList<const AstRawString>* labels, StatementT ParseIfStatement(ZonePtrList<const AstRawString>* labels,
bool* ok); bool* ok);
...@@ -1272,34 +1278,41 @@ class ParserBase { ...@@ -1272,34 +1278,41 @@ class ParserBase {
StatementT ParseWithStatement(ZonePtrList<const AstRawString>* labels, StatementT ParseWithStatement(ZonePtrList<const AstRawString>* labels,
bool* ok); bool* ok);
StatementT ParseDoWhileStatement(ZonePtrList<const AstRawString>* labels, StatementT ParseDoWhileStatement(ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels,
bool* ok); bool* ok);
StatementT ParseWhileStatement(ZonePtrList<const AstRawString>* labels, StatementT ParseWhileStatement(ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels,
bool* ok); bool* ok);
StatementT ParseThrowStatement(bool* ok); StatementT ParseThrowStatement(bool* ok);
StatementT ParseSwitchStatement(ZonePtrList<const AstRawString>* labels, StatementT ParseSwitchStatement(ZonePtrList<const AstRawString>* labels,
bool* ok); bool* ok);
StatementT ParseTryStatement(bool* ok); StatementT ParseTryStatement(bool* ok);
StatementT ParseForStatement(ZonePtrList<const AstRawString>* labels, StatementT ParseForStatement(ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels,
bool* ok); bool* ok);
StatementT ParseForEachStatementWithDeclarations( StatementT ParseForEachStatementWithDeclarations(
int stmt_pos, ForInfo* for_info, ZonePtrList<const AstRawString>* labels, int stmt_pos, ForInfo* for_info, ZonePtrList<const AstRawString>* labels,
Scope* inner_block_scope, bool* ok); ZonePtrList<const AstRawString>* own_labels, Scope* inner_block_scope,
bool* ok);
StatementT ParseForEachStatementWithoutDeclarations( StatementT ParseForEachStatementWithoutDeclarations(
int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos, int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos,
ForInfo* for_info, ZonePtrList<const AstRawString>* labels, bool* ok); ForInfo* for_info, ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels, bool* ok);
// Parse a C-style for loop: 'for (<init>; <cond>; <next>) { ... }' // Parse a C-style for loop: 'for (<init>; <cond>; <next>) { ... }'
// "for (<init>;" is assumed to have been parser already. // "for (<init>;" is assumed to have been parser already.
ForStatementT ParseStandardForLoop(int stmt_pos, ForStatementT ParseStandardForLoop(
ZonePtrList<const AstRawString>* labels, int stmt_pos, ZonePtrList<const AstRawString>* labels,
ExpressionT* cond, StatementT* next, ZonePtrList<const AstRawString>* own_labels, ExpressionT* cond,
StatementT* body, bool* ok); StatementT* next, StatementT* body, bool* ok);
// Same as the above, but handles those cases where <init> is a // Same as the above, but handles those cases where <init> is a
// lexical variable declaration. // lexical variable declaration.
StatementT ParseStandardForLoopWithLexicalDeclarations( StatementT ParseStandardForLoopWithLexicalDeclarations(
int stmt_pos, StatementT init, ForInfo* for_info, int stmt_pos, StatementT init, ForInfo* for_info,
ZonePtrList<const AstRawString>* labels, bool* ok); ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels, bool* ok);
StatementT ParseForAwaitStatement(ZonePtrList<const AstRawString>* labels, StatementT ParseForAwaitStatement(ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels,
bool* ok); bool* ok);
bool IsNextLetKeyword(); bool IsNextLetKeyword();
...@@ -4983,12 +4996,13 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatementListItem( ...@@ -4983,12 +4996,13 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatementListItem(
default: default:
break; break;
} }
return ParseStatement(nullptr, kAllowLabelledFunctionStatement, ok); return ParseStatement(nullptr, nullptr, kAllowLabelledFunctionStatement, ok);
} }
template <typename Impl> template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement( typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement(
ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels,
AllowLabelledFunctionStatement allow_function, bool* ok) { AllowLabelledFunctionStatement allow_function, bool* ok) {
// Statement :: // Statement ::
// Block // Block
...@@ -5007,6 +5021,9 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement( ...@@ -5007,6 +5021,9 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement(
// TryStatement // TryStatement
// DebuggerStatement // DebuggerStatement
// {own_labels} is always a subset of {labels}.
DCHECK_IMPLIES(labels == nullptr, own_labels == nullptr);
// Note: Since labels can only be used by 'break' and 'continue' // Note: Since labels can only be used by 'break' and 'continue'
// statements, which themselves are only valid within blocks, // statements, which themselves are only valid within blocks,
// iterations or 'switch' statements (i.e., BreakableStatements), // iterations or 'switch' statements (i.e., BreakableStatements),
...@@ -5022,14 +5039,14 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement( ...@@ -5022,14 +5039,14 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement(
case Token::IF: case Token::IF:
return ParseIfStatement(labels, ok); return ParseIfStatement(labels, ok);
case Token::DO: case Token::DO:
return ParseDoWhileStatement(labels, ok); return ParseDoWhileStatement(labels, own_labels, ok);
case Token::WHILE: case Token::WHILE:
return ParseWhileStatement(labels, ok); return ParseWhileStatement(labels, own_labels, ok);
case Token::FOR: case Token::FOR:
if (V8_UNLIKELY(is_async_function() && PeekAhead() == Token::AWAIT)) { if (V8_UNLIKELY(is_async_function() && PeekAhead() == Token::AWAIT)) {
return ParseForAwaitStatement(labels, ok); return ParseForAwaitStatement(labels, own_labels, ok);
} }
return ParseForStatement(labels, ok); return ParseForStatement(labels, own_labels, ok);
case Token::CONTINUE: case Token::CONTINUE:
return ParseContinueStatement(ok); return ParseContinueStatement(ok);
case Token::BREAK: case Token::BREAK:
...@@ -5082,7 +5099,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement( ...@@ -5082,7 +5099,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement(
} }
V8_FALLTHROUGH; V8_FALLTHROUGH;
default: default:
return ParseExpressionOrLabelledStatement(labels, allow_function, ok); return ParseExpressionOrLabelledStatement(labels, own_labels,
allow_function, ok);
} }
} }
...@@ -5122,7 +5140,7 @@ template <typename Impl> ...@@ -5122,7 +5140,7 @@ template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseScopedStatement( typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseScopedStatement(
ZonePtrList<const AstRawString>* labels, bool* ok) { ZonePtrList<const AstRawString>* labels, bool* ok) {
if (is_strict(language_mode()) || peek() != Token::FUNCTION) { if (is_strict(language_mode()) || peek() != Token::FUNCTION) {
return ParseStatement(labels, ok); return ParseStatement(labels, nullptr, ok);
} else { } else {
// Make a block around the statement for a lexical binding // Make a block around the statement for a lexical binding
// is introduced by a FunctionDeclaration. // is introduced by a FunctionDeclaration.
...@@ -5182,6 +5200,7 @@ template <typename Impl> ...@@ -5182,6 +5200,7 @@ template <typename Impl>
typename ParserBase<Impl>::StatementT typename ParserBase<Impl>::StatementT
ParserBase<Impl>::ParseExpressionOrLabelledStatement( ParserBase<Impl>::ParseExpressionOrLabelledStatement(
ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels,
AllowLabelledFunctionStatement allow_function, bool* ok) { AllowLabelledFunctionStatement allow_function, bool* ok) {
// ExpressionStatement | LabelledStatement :: // ExpressionStatement | LabelledStatement ::
// Expression ';' // Expression ';'
...@@ -5225,15 +5244,15 @@ ParserBase<Impl>::ParseExpressionOrLabelledStatement( ...@@ -5225,15 +5244,15 @@ ParserBase<Impl>::ParseExpressionOrLabelledStatement(
impl()->IsIdentifier(expr)) { impl()->IsIdentifier(expr)) {
// The whole expression was a single identifier, and not, e.g., // The whole expression was a single identifier, and not, e.g.,
// something starting with an identifier or a parenthesized identifier. // something starting with an identifier or a parenthesized identifier.
labels = impl()->DeclareLabel(labels, impl()->AsIdentifierExpression(expr), impl()->DeclareLabel(&labels, &own_labels,
CHECK_OK); impl()->AsIdentifierExpression(expr), CHECK_OK);
Consume(Token::COLON); Consume(Token::COLON);
// ES#sec-labelled-function-declarations Labelled Function Declarations // ES#sec-labelled-function-declarations Labelled Function Declarations
if (peek() == Token::FUNCTION && is_sloppy(language_mode()) && if (peek() == Token::FUNCTION && is_sloppy(language_mode()) &&
allow_function == kAllowLabelledFunctionStatement) { allow_function == kAllowLabelledFunctionStatement) {
return ParseFunctionDeclaration(ok); return ParseFunctionDeclaration(ok);
} }
return ParseStatement(labels, allow_function, ok); return ParseStatement(labels, own_labels, allow_function, ok);
} }
// If we have an extension, we allow a native function declaration. // If we have an extension, we allow a native function declaration.
...@@ -5425,7 +5444,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWithStatement( ...@@ -5425,7 +5444,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWithStatement(
{ {
BlockState block_state(&scope_, with_scope); BlockState block_state(&scope_, with_scope);
with_scope->set_start_position(scanner()->peek_location().beg_pos); with_scope->set_start_position(scanner()->peek_location().beg_pos);
body = ParseStatement(labels, CHECK_OK); body = ParseStatement(labels, nullptr, CHECK_OK);
with_scope->set_end_position(scanner()->location().end_pos); with_scope->set_end_position(scanner()->location().end_pos);
} }
return factory()->NewWithStatement(with_scope, expr, body, pos); return factory()->NewWithStatement(with_scope, expr, body, pos);
...@@ -5433,11 +5452,13 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWithStatement( ...@@ -5433,11 +5452,13 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWithStatement(
template <typename Impl> template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDoWhileStatement( typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDoWhileStatement(
ZonePtrList<const AstRawString>* labels, bool* ok) { ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels, bool* ok) {
// DoStatement :: // DoStatement ::
// 'do' Statement 'while' '(' Expression ')' ';' // 'do' Statement 'while' '(' Expression ')' ';'
auto loop = factory()->NewDoWhileStatement(labels, peek_position()); auto loop =
factory()->NewDoWhileStatement(labels, own_labels, peek_position());
typename Types::Target target(this, loop); typename Types::Target target(this, loop);
SourceRange body_range; SourceRange body_range;
...@@ -5446,7 +5467,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDoWhileStatement( ...@@ -5446,7 +5467,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDoWhileStatement(
Expect(Token::DO, CHECK_OK); Expect(Token::DO, CHECK_OK);
{ {
SourceRangeScope range_scope(scanner(), &body_range); SourceRangeScope range_scope(scanner(), &body_range);
body = ParseStatement(nullptr, CHECK_OK); body = ParseStatement(nullptr, nullptr, CHECK_OK);
} }
Expect(Token::WHILE, CHECK_OK); Expect(Token::WHILE, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK); Expect(Token::LPAREN, CHECK_OK);
...@@ -5468,11 +5489,12 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDoWhileStatement( ...@@ -5468,11 +5489,12 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDoWhileStatement(
template <typename Impl> template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWhileStatement( typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWhileStatement(
ZonePtrList<const AstRawString>* labels, bool* ok) { ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels, bool* ok) {
// WhileStatement :: // WhileStatement ::
// 'while' '(' Expression ')' Statement // 'while' '(' Expression ')' Statement
auto loop = factory()->NewWhileStatement(labels, peek_position()); auto loop = factory()->NewWhileStatement(labels, own_labels, peek_position());
typename Types::Target target(this, loop); typename Types::Target target(this, loop);
SourceRange body_range; SourceRange body_range;
...@@ -5484,7 +5506,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWhileStatement( ...@@ -5484,7 +5506,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWhileStatement(
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
{ {
SourceRangeScope range_scope(scanner(), &body_range); SourceRangeScope range_scope(scanner(), &body_range);
body = ParseStatement(nullptr, CHECK_OK); body = ParseStatement(nullptr, nullptr, CHECK_OK);
} }
loop->Initialize(cond, body); loop->Initialize(cond, body);
...@@ -5683,7 +5705,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement( ...@@ -5683,7 +5705,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement(
template <typename Impl> template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
ZonePtrList<const AstRawString>* labels, bool* ok) { ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels, bool* ok) {
// Either a standard for loop // Either a standard for loop
// for (<init>; <cond>; <next>) { ... } // for (<init>; <cond>; <next>) { ... }
// or a for-each loop // or a for-each loop
...@@ -5723,8 +5746,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( ...@@ -5723,8 +5746,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
if (CheckInOrOf(&for_info.mode)) { if (CheckInOrOf(&for_info.mode)) {
scope()->set_is_hidden(); scope()->set_is_hidden();
return ParseForEachStatementWithDeclarations(stmt_pos, &for_info, labels, return ParseForEachStatementWithDeclarations(
inner_block_scope, ok); stmt_pos, &for_info, labels, own_labels, inner_block_scope, ok);
} }
Expect(Token::SEMICOLON, CHECK_OK); Expect(Token::SEMICOLON, CHECK_OK);
...@@ -5736,8 +5759,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( ...@@ -5736,8 +5759,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
// No variable declarations will have been created in inner_block_scope. // No variable declarations will have been created in inner_block_scope.
DCHECK_NULL(finalized); DCHECK_NULL(finalized);
USE(finalized); USE(finalized);
return ParseStandardForLoopWithLexicalDeclarations(stmt_pos, init, return ParseStandardForLoopWithLexicalDeclarations(
&for_info, labels, ok); stmt_pos, init, &for_info, labels, own_labels, ok);
} }
StatementT init = impl()->NullStatement(); StatementT init = impl()->NullStatement();
...@@ -5749,7 +5772,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( ...@@ -5749,7 +5772,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
if (CheckInOrOf(&for_info.mode)) { if (CheckInOrOf(&for_info.mode)) {
return ParseForEachStatementWithDeclarations(stmt_pos, &for_info, labels, return ParseForEachStatementWithDeclarations(stmt_pos, &for_info, labels,
nullptr, ok); own_labels, nullptr, ok);
} }
init = impl()->BuildInitializationBlock(&for_info.parsing_result, nullptr, init = impl()->BuildInitializationBlock(&for_info.parsing_result, nullptr,
...@@ -5772,9 +5795,9 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( ...@@ -5772,9 +5795,9 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
} }
if (is_for_each) { if (is_for_each) {
return ParseForEachStatementWithoutDeclarations(stmt_pos, expression, return ParseForEachStatementWithoutDeclarations(
lhs_beg_pos, lhs_end_pos, stmt_pos, expression, lhs_beg_pos, lhs_end_pos, &for_info, labels,
&for_info, labels, ok); own_labels, ok);
} }
// Initializer is just an expression. // Initializer is just an expression.
init = factory()->NewExpressionStatement(expression, lhs_beg_pos); init = factory()->NewExpressionStatement(expression, lhs_beg_pos);
...@@ -5786,8 +5809,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( ...@@ -5786,8 +5809,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
ExpressionT cond = impl()->NullExpression(); ExpressionT cond = impl()->NullExpression();
StatementT next = impl()->NullStatement(); StatementT next = impl()->NullStatement();
StatementT body = impl()->NullStatement(); StatementT body = impl()->NullStatement();
ForStatementT loop = ForStatementT loop = ParseStandardForLoop(stmt_pos, labels, own_labels, &cond,
ParseStandardForLoop(stmt_pos, labels, &cond, &next, &body, CHECK_OK); &next, &body, CHECK_OK);
loop->Initialize(init, cond, next, body); loop->Initialize(init, cond, next, body);
return loop; return loop;
} }
...@@ -5796,7 +5819,8 @@ template <typename Impl> ...@@ -5796,7 +5819,8 @@ template <typename Impl>
typename ParserBase<Impl>::StatementT typename ParserBase<Impl>::StatementT
ParserBase<Impl>::ParseForEachStatementWithDeclarations( ParserBase<Impl>::ParseForEachStatementWithDeclarations(
int stmt_pos, ForInfo* for_info, ZonePtrList<const AstRawString>* labels, int stmt_pos, ForInfo* for_info, ZonePtrList<const AstRawString>* labels,
Scope* inner_block_scope, bool* ok) { ZonePtrList<const AstRawString>* own_labels, Scope* inner_block_scope,
bool* ok) {
// Just one declaration followed by in/of. // Just one declaration followed by in/of.
if (for_info->parsing_result.declarations.size() != 1) { if (for_info->parsing_result.declarations.size() != 1) {
impl()->ReportMessageAt(for_info->parsing_result.bindings_loc, impl()->ReportMessageAt(for_info->parsing_result.bindings_loc,
...@@ -5824,7 +5848,8 @@ ParserBase<Impl>::ParseForEachStatementWithDeclarations( ...@@ -5824,7 +5848,8 @@ ParserBase<Impl>::ParseForEachStatementWithDeclarations(
BlockT init_block = impl()->RewriteForVarInLegacy(*for_info); BlockT init_block = impl()->RewriteForVarInLegacy(*for_info);
auto loop = factory()->NewForEachStatement(for_info->mode, labels, stmt_pos); auto loop = factory()->NewForEachStatement(for_info->mode, labels, own_labels,
stmt_pos);
typename Types::Target target(this, loop); typename Types::Target target(this, loop);
ExpressionT enumerable = impl()->NullExpression(); ExpressionT enumerable = impl()->NullExpression();
...@@ -5854,7 +5879,7 @@ ParserBase<Impl>::ParseForEachStatementWithDeclarations( ...@@ -5854,7 +5879,7 @@ ParserBase<Impl>::ParseForEachStatementWithDeclarations(
SourceRange body_range; SourceRange body_range;
SourceRangeScope range_scope(scanner(), &body_range); SourceRangeScope range_scope(scanner(), &body_range);
StatementT body = ParseStatement(nullptr, CHECK_OK); StatementT body = ParseStatement(nullptr, nullptr, CHECK_OK);
impl()->RecordIterationStatementSourceRange(loop, range_scope.Finalize()); impl()->RecordIterationStatementSourceRange(loop, range_scope.Finalize());
impl()->DesugarBindingInForEachStatement(for_info, &body_block, impl()->DesugarBindingInForEachStatement(for_info, &body_block,
...@@ -5892,7 +5917,8 @@ template <typename Impl> ...@@ -5892,7 +5917,8 @@ template <typename Impl>
typename ParserBase<Impl>::StatementT typename ParserBase<Impl>::StatementT
ParserBase<Impl>::ParseForEachStatementWithoutDeclarations( ParserBase<Impl>::ParseForEachStatementWithoutDeclarations(
int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos, int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos,
ForInfo* for_info, ZonePtrList<const AstRawString>* labels, bool* ok) { ForInfo* for_info, ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels, bool* ok) {
// Initializer is reference followed by in/of. // Initializer is reference followed by in/of.
if (!expression->IsArrayLiteral() && !expression->IsObjectLiteral()) { if (!expression->IsArrayLiteral() && !expression->IsObjectLiteral()) {
expression = CheckAndRewriteReferenceExpression( expression = CheckAndRewriteReferenceExpression(
...@@ -5900,7 +5926,8 @@ ParserBase<Impl>::ParseForEachStatementWithoutDeclarations( ...@@ -5900,7 +5926,8 @@ ParserBase<Impl>::ParseForEachStatementWithoutDeclarations(
kSyntaxError, CHECK_OK); kSyntaxError, CHECK_OK);
} }
auto loop = factory()->NewForEachStatement(for_info->mode, labels, stmt_pos); auto loop = factory()->NewForEachStatement(for_info->mode, labels, own_labels,
stmt_pos);
typename Types::Target target(this, loop); typename Types::Target target(this, loop);
ExpressionT enumerable = impl()->NullExpression(); ExpressionT enumerable = impl()->NullExpression();
...@@ -5919,7 +5946,7 @@ ParserBase<Impl>::ParseForEachStatementWithoutDeclarations( ...@@ -5919,7 +5946,7 @@ ParserBase<Impl>::ParseForEachStatementWithoutDeclarations(
SourceRange body_range; SourceRange body_range;
SourceRangeScope range_scope(scanner(), &body_range); SourceRangeScope range_scope(scanner(), &body_range);
body = ParseStatement(nullptr, CHECK_OK); body = ParseStatement(nullptr, nullptr, CHECK_OK);
impl()->RecordIterationStatementSourceRange(loop, range_scope.Finalize()); impl()->RecordIterationStatementSourceRange(loop, range_scope.Finalize());
} }
return impl()->InitializeForEachStatement(loop, expression, enumerable, body); return impl()->InitializeForEachStatement(loop, expression, enumerable, body);
...@@ -5929,7 +5956,8 @@ template <typename Impl> ...@@ -5929,7 +5956,8 @@ template <typename Impl>
typename ParserBase<Impl>::StatementT typename ParserBase<Impl>::StatementT
ParserBase<Impl>::ParseStandardForLoopWithLexicalDeclarations( ParserBase<Impl>::ParseStandardForLoopWithLexicalDeclarations(
int stmt_pos, StatementT init, ForInfo* for_info, int stmt_pos, StatementT init, ForInfo* for_info,
ZonePtrList<const AstRawString>* labels, bool* ok) { ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels, bool* ok) {
// The condition and the next statement of the for loop must be parsed // The condition and the next statement of the for loop must be parsed
// in a new scope. // in a new scope.
Scope* inner_scope = NewScope(BLOCK_SCOPE); Scope* inner_scope = NewScope(BLOCK_SCOPE);
...@@ -5940,8 +5968,8 @@ ParserBase<Impl>::ParseStandardForLoopWithLexicalDeclarations( ...@@ -5940,8 +5968,8 @@ ParserBase<Impl>::ParseStandardForLoopWithLexicalDeclarations(
{ {
BlockState block_state(&scope_, inner_scope); BlockState block_state(&scope_, inner_scope);
scope()->set_start_position(scanner()->location().beg_pos); scope()->set_start_position(scanner()->location().beg_pos);
loop = loop = ParseStandardForLoop(stmt_pos, labels, own_labels, &cond, &next,
ParseStandardForLoop(stmt_pos, labels, &cond, &next, &body, CHECK_OK); &body, CHECK_OK);
scope()->set_end_position(scanner()->location().end_pos); scope()->set_end_position(scanner()->location().end_pos);
} }
...@@ -5984,9 +6012,10 @@ ParserBase<Impl>::ParseStandardForLoopWithLexicalDeclarations( ...@@ -5984,9 +6012,10 @@ ParserBase<Impl>::ParseStandardForLoopWithLexicalDeclarations(
template <typename Impl> template <typename Impl>
typename ParserBase<Impl>::ForStatementT ParserBase<Impl>::ParseStandardForLoop( typename ParserBase<Impl>::ForStatementT ParserBase<Impl>::ParseStandardForLoop(
int stmt_pos, ZonePtrList<const AstRawString>* labels, ExpressionT* cond, int stmt_pos, ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels, ExpressionT* cond,
StatementT* next, StatementT* body, bool* ok) { StatementT* next, StatementT* body, bool* ok) {
ForStatementT loop = factory()->NewForStatement(labels, stmt_pos); ForStatementT loop = factory()->NewForStatement(labels, own_labels, stmt_pos);
typename Types::Target target(this, loop); typename Types::Target target(this, loop);
if (peek() != Token::SEMICOLON) { if (peek() != Token::SEMICOLON) {
...@@ -6003,7 +6032,7 @@ typename ParserBase<Impl>::ForStatementT ParserBase<Impl>::ParseStandardForLoop( ...@@ -6003,7 +6032,7 @@ typename ParserBase<Impl>::ForStatementT ParserBase<Impl>::ParseStandardForLoop(
SourceRange body_range; SourceRange body_range;
{ {
SourceRangeScope range_scope(scanner(), &body_range); SourceRangeScope range_scope(scanner(), &body_range);
*body = ParseStatement(nullptr, CHECK_OK); *body = ParseStatement(nullptr, nullptr, CHECK_OK);
} }
impl()->RecordIterationStatementSourceRange(loop, body_range); impl()->RecordIterationStatementSourceRange(loop, body_range);
...@@ -6023,7 +6052,8 @@ void ParserBase<Impl>::MarkLoopVariableAsAssigned( ...@@ -6023,7 +6052,8 @@ void ParserBase<Impl>::MarkLoopVariableAsAssigned(
template <typename Impl> template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
ZonePtrList<const AstRawString>* labels, bool* ok) { ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels, bool* ok) {
// for await '(' ForDeclaration of AssignmentExpression ')' // for await '(' ForDeclaration of AssignmentExpression ')'
DCHECK(is_async_function()); DCHECK(is_async_function());
...@@ -6040,7 +6070,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( ...@@ -6040,7 +6070,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
scope()->set_start_position(scanner()->location().beg_pos); scope()->set_start_position(scanner()->location().beg_pos);
scope()->set_is_hidden(); scope()->set_is_hidden();
auto loop = factory()->NewForOfStatement(labels, stmt_pos); auto loop = factory()->NewForOfStatement(labels, own_labels, stmt_pos);
typename Types::Target target(this, loop); typename Types::Target target(this, loop);
ExpressionT each_variable = impl()->NullExpression(); ExpressionT each_variable = impl()->NullExpression();
...@@ -6123,7 +6153,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( ...@@ -6123,7 +6153,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
SourceRange body_range; SourceRange body_range;
SourceRangeScope range_scope(scanner(), &body_range); SourceRangeScope range_scope(scanner(), &body_range);
body = ParseStatement(nullptr, CHECK_OK); body = ParseStatement(nullptr, nullptr, CHECK_OK);
scope()->set_end_position(scanner()->location().end_pos); scope()->set_end_position(scanner()->location().end_pos);
impl()->RecordIterationStatementSourceRange(loop, range_scope.Finalize()); impl()->RecordIterationStatementSourceRange(loop, range_scope.Finalize());
......
...@@ -1470,29 +1470,40 @@ Statement* Parser::DeclareNative(const AstRawString* name, int pos, bool* ok) { ...@@ -1470,29 +1470,40 @@ Statement* Parser::DeclareNative(const AstRawString* name, int pos, bool* ok) {
pos); pos);
} }
ZonePtrList<const AstRawString>* Parser::DeclareLabel( void Parser::DeclareLabel(ZonePtrList<const AstRawString>** labels,
ZonePtrList<const AstRawString>* labels, VariableProxy* var, bool* ok) { ZonePtrList<const AstRawString>** own_labels,
VariableProxy* var, bool* ok) {
DCHECK(IsIdentifier(var)); DCHECK(IsIdentifier(var));
const AstRawString* label = var->raw_name(); const AstRawString* label = var->raw_name();
// TODO(1240780): We don't check for redeclaration of labels // TODO(1240780): We don't check for redeclaration of labels
// during preparsing since keeping track of the set of active // during preparsing since keeping track of the set of active
// labels requires nontrivial changes to the way scopes are // labels requires nontrivial changes to the way scopes are
// structured. However, these are probably changes we want to // structured. However, these are probably changes we want to
// make later anyway so we should go back and fix this then. // make later anyway so we should go back and fix this then.
if (ContainsLabel(labels, label) || TargetStackContainsLabel(label)) { if (ContainsLabel(*labels, label) || TargetStackContainsLabel(label)) {
ReportMessage(MessageTemplate::kLabelRedeclaration, label); ReportMessage(MessageTemplate::kLabelRedeclaration, label);
*ok = false; *ok = false;
return nullptr; return;
} }
if (labels == nullptr) {
labels = new (zone()) ZonePtrList<const AstRawString>(1, zone()); // Add {label} to both {labels} and {own_labels}.
if (*labels == nullptr) {
DCHECK_NULL(*own_labels);
*labels = new (zone()) ZonePtrList<const AstRawString>(1, zone());
*own_labels = new (zone()) ZonePtrList<const AstRawString>(1, zone());
} else {
if (*own_labels == nullptr) {
*own_labels = new (zone()) ZonePtrList<const AstRawString>(1, zone());
}
} }
labels->Add(label, zone()); (*labels)->Add(label, zone());
(*own_labels)->Add(label, zone());
// Remove the "ghost" variable that turned out to be a label // Remove the "ghost" variable that turned out to be a label
// from the top scope. This way, we don't try to resolve it // from the top scope. This way, we don't try to resolve it
// during the scope processing. // during the scope processing.
scope()->RemoveUnresolved(var); scope()->RemoveUnresolved(var);
return labels;
} }
bool Parser::ContainsLabel(ZonePtrList<const AstRawString>* labels, bool Parser::ContainsLabel(ZonePtrList<const AstRawString>* labels,
...@@ -2191,7 +2202,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( ...@@ -2191,7 +2202,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
// need to know about it. This should be safe because we don't run any code // need to know about it. This should be safe because we don't run any code
// in this function that looks up break targets. // in this function that looks up break targets.
ForStatement* outer_loop = ForStatement* outer_loop =
factory()->NewForStatement(nullptr, kNoSourcePosition); factory()->NewForStatement(nullptr, nullptr, kNoSourcePosition);
outer_block->statements()->Add(outer_loop, zone()); outer_block->statements()->Add(outer_loop, zone());
outer_block->set_scope(scope()); outer_block->set_scope(scope());
...@@ -3393,9 +3404,10 @@ IterationStatement* Parser::LookupContinueTarget(const AstRawString* label, ...@@ -3393,9 +3404,10 @@ IterationStatement* Parser::LookupContinueTarget(const AstRawString* label,
if (stat == nullptr) continue; if (stat == nullptr) continue;
DCHECK(stat->is_target_for_anonymous()); DCHECK(stat->is_target_for_anonymous());
if (anonymous || ContainsLabel(stat->labels(), label)) { if (anonymous || ContainsLabel(stat->own_labels(), label)) {
return stat; return stat;
} }
if (ContainsLabel(stat->labels(), label)) break;
} }
return nullptr; return nullptr;
} }
......
...@@ -284,8 +284,9 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -284,8 +284,9 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
Block* BuildInitializationBlock(DeclarationParsingResult* parsing_result, Block* BuildInitializationBlock(DeclarationParsingResult* parsing_result,
ZonePtrList<const AstRawString>* names, ZonePtrList<const AstRawString>* names,
bool* ok); bool* ok);
ZonePtrList<const AstRawString>* DeclareLabel( void DeclareLabel(ZonePtrList<const AstRawString>** labels,
ZonePtrList<const AstRawString>* labels, VariableProxy* expr, bool* ok); ZonePtrList<const AstRawString>** own_labels,
VariableProxy* expr, bool* ok);
bool ContainsLabel(ZonePtrList<const AstRawString>* labels, bool ContainsLabel(ZonePtrList<const AstRawString>* labels,
const AstRawString* label); const AstRawString* label);
Expression* RewriteReturn(Expression* return_value, int pos); Expression* RewriteReturn(Expression* return_value, int pos);
......
...@@ -671,7 +671,8 @@ void PatternRewriter::VisitArrayLiteral(ArrayLiteral* node, ...@@ -671,7 +671,8 @@ void PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
// #maybe_store_and_unset_done; // #maybe_store_and_unset_done;
// #increment_index; // #increment_index;
// } // }
WhileStatement* loop = factory()->NewWhileStatement(nullptr, nopos); WhileStatement* loop =
factory()->NewWhileStatement(nullptr, nullptr, nopos);
{ {
Expression* condition = factory()->NewUnaryOperation( Expression* condition = factory()->NewUnaryOperation(
Token::NOT, factory()->NewVariableProxy(done), nopos); Token::NOT, factory()->NewVariableProxy(done), nopos);
......
...@@ -788,12 +788,14 @@ class PreParserFactory { ...@@ -788,12 +788,14 @@ class PreParserFactory {
} }
PreParserStatement NewDoWhileStatement( PreParserStatement NewDoWhileStatement(
ZonePtrList<const AstRawString>* labels, int pos) { ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels, int pos) {
return PreParserStatement::Default(); return PreParserStatement::Default();
} }
PreParserStatement NewWhileStatement(ZonePtrList<const AstRawString>* labels, PreParserStatement NewWhileStatement(
int pos) { ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels, int pos) {
return PreParserStatement::Default(); return PreParserStatement::Default();
} }
...@@ -808,19 +810,22 @@ class PreParserFactory { ...@@ -808,19 +810,22 @@ class PreParserFactory {
return PreParserStatement::Default(); return PreParserStatement::Default();
} }
PreParserStatement NewForStatement(ZonePtrList<const AstRawString>* labels, PreParserStatement NewForStatement(
int pos) { ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels, int pos) {
return PreParserStatement::Default(); return PreParserStatement::Default();
} }
PreParserStatement NewForEachStatement( PreParserStatement NewForEachStatement(
ForEachStatement::VisitMode visit_mode, ForEachStatement::VisitMode visit_mode,
ZonePtrList<const AstRawString>* labels, int pos) { ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels, int pos) {
return PreParserStatement::Default(); return PreParserStatement::Default();
} }
PreParserStatement NewForOfStatement(ZonePtrList<const AstRawString>* labels, PreParserStatement NewForOfStatement(
int pos) { ZonePtrList<const AstRawString>* labels,
ZonePtrList<const AstRawString>* own_labels, int pos) {
return PreParserStatement::Default(); return PreParserStatement::Default();
} }
...@@ -1071,12 +1076,11 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1071,12 +1076,11 @@ class PreParser : public ParserBase<PreParser> {
const DeclarationParsingResult::Declaration* declaration, const DeclarationParsingResult::Declaration* declaration,
ZonePtrList<const AstRawString>* names, bool* ok); ZonePtrList<const AstRawString>* names, bool* ok);
V8_INLINE ZonePtrList<const AstRawString>* DeclareLabel( V8_INLINE void DeclareLabel(ZonePtrList<const AstRawString>** labels,
ZonePtrList<const AstRawString>* labels, const PreParserExpression& expr, ZonePtrList<const AstRawString>** own_labels,
bool* ok) { const PreParserExpression& expr, bool* ok) {
DCHECK(!parsing_module_ || !expr.AsIdentifier().IsAwait()); DCHECK(!parsing_module_ || !expr.AsIdentifier().IsAwait());
DCHECK(IsIdentifier(expr)); DCHECK(IsIdentifier(expr));
return labels;
} }
// TODO(nikolaos): The preparser currently does not keep track of labels. // TODO(nikolaos): The preparser currently does not keep track of labels.
......
// Copyright 2018 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.
assertThrows("foo: if (true) do { continue foo } while (false)", SyntaxError);
assertThrows("foo: if (true) while (false) { continue foo }", SyntaxError);
assertThrows("foo: if (true) for (; false; ) { continue foo }", SyntaxError);
assertThrows("foo: if (true) for (let x of []) { continue foo }", SyntaxError);
assertThrows("foo: if (true) for (let x in []) { continue foo }", SyntaxError);
assertThrows("foo: if (true) { do { continue foo } while (false) }", SyntaxError);
assertThrows("foo: if (true) { while (false) { continue foo } }", SyntaxError);
assertThrows("foo: if (true) { for (; false; ) { continue foo } }", SyntaxError);
assertThrows("foo: if (true) { for (let x of []) { continue foo } }", SyntaxError);
assertThrows("foo: if (true) { for (let x in []) { continue foo } }", SyntaxError);
assertThrows("foo: goo: if (true) do { continue foo } while (false)", SyntaxError);
assertThrows("foo: goo: if (true) while (false) { continue foo }", SyntaxError);
assertThrows("foo: goo: if (true) for (; false; ) { continue foo }", SyntaxError);
assertThrows("foo: goo: if (true) for (let x of []) { continue foo }", SyntaxError);
assertThrows("foo: goo: if (true) for (let x in []) { continue foo }", SyntaxError);
assertThrows("foo: goo: if (true) { do { continue foo } while (false) }", SyntaxError);
assertThrows("foo: goo: if (true) { while (false) { continue foo } }", SyntaxError);
assertThrows("foo: goo: if (true) { for (; false; ) { continue foo } }", SyntaxError);
assertThrows("foo: goo: if (true) { for (let x of []) { continue foo } }", SyntaxError);
assertThrows("foo: goo: if (true) { for (let x in []) { continue foo } }", SyntaxError);
assertDoesNotThrow("if (true) foo: goo: do { continue foo } while (false)");
assertDoesNotThrow("if (true) foo: goo: while (false) { continue foo }");
assertDoesNotThrow("if (true) foo: goo: for (; false; ) { continue foo }");
assertDoesNotThrow("if (true) foo: goo: for (let x of []) { continue foo }");
assertDoesNotThrow("if (true) foo: goo: for (let x in []) { continue foo }");
assertThrows("if (true) foo: goo: { do { continue foo } while (false) }", SyntaxError);
assertThrows("if (true) foo: goo: { while (false) { continue foo } }", SyntaxError);
assertThrows("if (true) foo: goo: { for (; false; ) { continue foo } }", SyntaxError);
assertThrows("if (true) foo: goo: { for (let x of []) { continue foo } }", SyntaxError);
assertThrows("if (true) foo: goo: { for (let x in []) { continue foo } }", SyntaxError);
assertDoesNotThrow("if (true) { foo: goo: do { continue foo } while (false) }");
assertDoesNotThrow("if (true) { foo: goo: while (false) { continue foo } }");
assertDoesNotThrow("if (true) { foo: goo: for (; false; ) { continue foo } }");
assertDoesNotThrow("if (true) { foo: goo: for (let x of []) { continue foo } }");
assertDoesNotThrow("if (true) { foo: goo: for (let x in []) { continue foo } }");
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