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);
......
This diff is collapsed.
...@@ -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