Commit 26ffd5bf authored by Caitlin Potter's avatar Caitlin Potter Committed by Commit Bot

[parser] report early error when assigning to a tagged template call

Previously, Function("++f`...`) would not throw an exception until the
created function was called. Now, it throws an early ReferenceError.

This change matches the behaviour in JavaScriptCore and SpiderMonkey.

Ordinary calls such as Function("++f()") are still thrown at runtime,
also compatible with JavaScriptCore and SpiderMonkey.

BUG=v8:4480, v8:6910
R=marja@chromium.org, littledan@chromium.org

Change-Id: If31c6d360a0464744eff5d8dd377ebff184ae00e
Reviewed-on: https://chromium-review.googlesource.com/712794
Commit-Queue: Caitlin Potter <caitp@igalia.com>
Reviewed-by: 's avatarMarja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48553}
parent d953b2ab
...@@ -1662,6 +1662,10 @@ class Call final : public Expression { ...@@ -1662,6 +1662,10 @@ class Call final : public Expression {
return IsPossiblyEvalField::decode(bit_field_); return IsPossiblyEvalField::decode(bit_field_);
} }
bool is_tagged_template() const {
return IsTaggedTemplateField::decode(bit_field_);
}
bool only_last_arg_is_spread() { bool only_last_arg_is_spread() {
return !arguments_->is_empty() && arguments_->last()->IsSpread(); return !arguments_->is_empty() && arguments_->last()->IsSpread();
} }
...@@ -1685,6 +1689,8 @@ class Call final : public Expression { ...@@ -1685,6 +1689,8 @@ class Call final : public Expression {
// Helpers to determine how to handle the call. // Helpers to determine how to handle the call.
CallType GetCallType() const; CallType GetCallType() const;
enum class TaggedTemplateTag { kTrue };
private: private:
friend class AstNodeFactory; friend class AstNodeFactory;
...@@ -1694,11 +1700,21 @@ class Call final : public Expression { ...@@ -1694,11 +1700,21 @@ class Call final : public Expression {
expression_(expression), expression_(expression),
arguments_(arguments) { arguments_(arguments) {
bit_field_ |= bit_field_ |=
IsPossiblyEvalField::encode(possibly_eval == IS_POSSIBLY_EVAL); IsPossiblyEvalField::encode(possibly_eval == IS_POSSIBLY_EVAL) |
IsTaggedTemplateField::encode(false);
}
Call(Expression* expression, ZoneList<Expression*>* arguments, int pos,
TaggedTemplateTag tag)
: Expression(pos, kCall), expression_(expression), arguments_(arguments) {
bit_field_ |= IsPossiblyEvalField::encode(false) |
IsTaggedTemplateField::encode(true);
} }
class IsPossiblyEvalField class IsPossiblyEvalField
: public BitField<bool, Expression::kNextBitFieldIndex, 1> {}; : public BitField<bool, Expression::kNextBitFieldIndex, 1> {};
class IsTaggedTemplateField
: public BitField<bool, IsPossiblyEvalField::kNext, 1> {};
FeedbackSlot ic_slot_; FeedbackSlot ic_slot_;
Expression* expression_; Expression* expression_;
...@@ -3198,6 +3214,12 @@ class AstNodeFactory final BASE_EMBEDDED { ...@@ -3198,6 +3214,12 @@ class AstNodeFactory final BASE_EMBEDDED {
return new (zone_) Call(expression, arguments, pos, possibly_eval); return new (zone_) Call(expression, arguments, pos, possibly_eval);
} }
Call* NewTaggedTemplate(Expression* expression,
ZoneList<Expression*>* arguments, int pos) {
return new (zone_)
Call(expression, arguments, pos, Call::TaggedTemplateTag::kTrue);
}
CallNew* NewCallNew(Expression* expression, CallNew* NewCallNew(Expression* expression,
ZoneList<Expression*>* arguments, ZoneList<Expression*>* arguments,
int pos) { int pos) {
......
...@@ -4656,7 +4656,7 @@ ParserBase<Impl>::CheckAndRewriteReferenceExpression( ...@@ -4656,7 +4656,7 @@ ParserBase<Impl>::CheckAndRewriteReferenceExpression(
if (expression->IsValidReferenceExpression()) { if (expression->IsValidReferenceExpression()) {
return expression; return expression;
} }
if (expression->IsCall()) { if (expression->IsCall() && !expression->AsCall()->is_tagged_template()) {
// If it is a call, make it a runtime error for legacy web compatibility. // If it is a call, make it a runtime error for legacy web compatibility.
// Bug: https://bugs.chromium.org/p/v8/issues/detail?id=4480 // Bug: https://bugs.chromium.org/p/v8/issues/detail?id=4480
// Rewrite `expr' to `expr[throw ReferenceError]'. // Rewrite `expr' to `expr[throw ReferenceError]'.
......
...@@ -3469,7 +3469,7 @@ Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start, ...@@ -3469,7 +3469,7 @@ Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start,
new (zone()) ZoneList<Expression*>(expressions->length() + 1, zone()); new (zone()) ZoneList<Expression*>(expressions->length() + 1, zone());
call_args->Add(template_object, zone()); call_args->Add(template_object, zone());
call_args->AddAll(*expressions, zone()); call_args->AddAll(*expressions, zone());
return factory()->NewCall(tag, call_args, pos); return factory()->NewTaggedTemplate(tag, call_args, pos);
} }
} }
......
...@@ -192,6 +192,17 @@ class PreParserExpression { ...@@ -192,6 +192,17 @@ class PreParserExpression {
ExpressionTypeField::encode(kCallEvalExpression)); ExpressionTypeField::encode(kCallEvalExpression));
} }
static PreParserExpression CallTaggedTemplate() {
return PreParserExpression(
TypeField::encode(kExpression) |
ExpressionTypeField::encode(kCallTaggedTemplateExpression));
}
bool is_tagged_template() const {
DCHECK(IsCall());
return ExpressionTypeField::decode(code_) == kCallTaggedTemplateExpression;
}
static PreParserExpression SuperCallReference() { static PreParserExpression SuperCallReference() {
return PreParserExpression( return PreParserExpression(
TypeField::encode(kExpression) | TypeField::encode(kExpression) |
...@@ -255,7 +266,13 @@ class PreParserExpression { ...@@ -255,7 +266,13 @@ class PreParserExpression {
bool IsCall() const { bool IsCall() const {
return TypeField::decode(code_) == kExpression && return TypeField::decode(code_) == kExpression &&
(ExpressionTypeField::decode(code_) == kCallExpression || (ExpressionTypeField::decode(code_) == kCallExpression ||
ExpressionTypeField::decode(code_) == kCallEvalExpression); ExpressionTypeField::decode(code_) == kCallEvalExpression ||
ExpressionTypeField::decode(code_) ==
kCallTaggedTemplateExpression);
}
PreParserExpression* AsCall() {
if (IsCall()) return this;
return nullptr;
} }
bool IsSuperCallReference() const { bool IsSuperCallReference() const {
...@@ -304,6 +321,7 @@ class PreParserExpression { ...@@ -304,6 +321,7 @@ class PreParserExpression {
kPropertyExpression, kPropertyExpression,
kCallExpression, kCallExpression,
kCallEvalExpression, kCallEvalExpression,
kCallTaggedTemplateExpression,
kSuperCallReference, kSuperCallReference,
kAssignment kAssignment
}; };
...@@ -624,6 +642,11 @@ class PreParserFactory { ...@@ -624,6 +642,11 @@ class PreParserFactory {
} }
return PreParserExpression::Call(); return PreParserExpression::Call();
} }
PreParserExpression NewTaggedTemplate(
PreParserExpression expression, const PreParserExpressionList& arguments,
int pos) {
return PreParserExpression::CallTaggedTemplate();
}
PreParserExpression NewCallNew(const PreParserExpression& expression, PreParserExpression NewCallNew(const PreParserExpression& expression,
const PreParserExpressionList& arguments, const PreParserExpressionList& arguments,
int pos) { int pos) {
......
...@@ -716,3 +716,22 @@ var global = this; ...@@ -716,3 +716,22 @@ var global = this;
assertEquals(["a", "b"], result); assertEquals(["a", "b"], result);
assertSame(result, f()); assertSame(result, f());
})(); })();
(function testTaggedTemplateInvalidAssignmentTargetStrict() {
"use strict";
function f() {}
assertThrows(() => Function("++f`foo`"), ReferenceError);
assertThrows(() => Function("f`foo`++"), ReferenceError);
assertThrows(() => Function("--f`foo`"), ReferenceError);
assertThrows(() => Function("f`foo`--"), ReferenceError);
assertThrows(() => Function("f`foo` = 1"), ReferenceError);
})();
(function testTaggedTemplateInvalidAssignmentTargetSloppy() {
function f() {}
assertThrows(() => Function("++f`foo`"), ReferenceError);
assertThrows(() => Function("f`foo`++"), ReferenceError);
assertThrows(() => Function("--f`foo`"), ReferenceError);
assertThrows(() => Function("f`foo`--"), ReferenceError);
assertThrows(() => Function("f`foo` = 1"), ReferenceError);
})();
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