Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (197946 => 197947)
--- trunk/Source/_javascript_Core/ChangeLog 2016-03-10 19:26:32 UTC (rev 197946)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-03-10 19:41:37 UTC (rev 197947)
@@ -1,3 +1,37 @@
+2016-03-10 Saam barati <[email protected]>
+
+ Assignment to new.target should be an early error
+ https://bugs.webkit.org/show_bug.cgi?id=151148
+
+ Reviewed by Mark Lam.
+
+ This patch makes it so that any form of assignment to new.target
+ is an early syntax error.
+
+ * parser/ASTBuilder.h:
+ (JSC::ASTBuilder::createNewTargetExpr):
+ (JSC::ASTBuilder::isNewTarget):
+ (JSC::ASTBuilder::createResolve):
+ * parser/Parser.cpp:
+ (JSC::Parser<LexerType>::parseAssignmentExpression):
+ (JSC::Parser<LexerType>::parseUnaryExpression):
+ * parser/SyntaxChecker.h:
+ (JSC::SyntaxChecker::createThisExpr):
+ (JSC::SyntaxChecker::createSuperExpr):
+ (JSC::SyntaxChecker::createNewTargetExpr):
+ (JSC::SyntaxChecker::isNewTarget):
+ (JSC::SyntaxChecker::createResolve):
+ (JSC::SyntaxChecker::createObjectLiteral):
+ * tests/es6.yaml:
+ * tests/stress/new-target-syntax-errors.js: Added.
+ (shouldBeSyntaxError):
+ (shouldNotBeSyntaxError):
+ * tests/stress/new-target.js:
+ (Constructor):
+ (doWeirdThings):
+ (noAssign): Deleted.
+ (catch): Deleted.
+
2016-03-08 Skachkov Oleksandr <[email protected]>
How we load new.target in arrow functions is broken
Modified: trunk/Source/_javascript_Core/parser/ASTBuilder.h (197946 => 197947)
--- trunk/Source/_javascript_Core/parser/ASTBuilder.h 2016-03-10 19:26:32 UTC (rev 197946)
+++ trunk/Source/_javascript_Core/parser/ASTBuilder.h 2016-03-10 19:41:37 UTC (rev 197947)
@@ -182,6 +182,7 @@
usesNewTarget();
return new (m_parserArena) NewTargetNode(location);
}
+ NO_RETURN_DUE_TO_CRASH bool isNewTarget(ExpressionNode*) { RELEASE_ASSERT_NOT_REACHED(); }
ExpressionNode* createResolve(const JSTokenLocation& location, const Identifier& ident, const JSTextPosition& start, const JSTextPosition& end)
{
if (m_vm->propertyNames->arguments == ident)
Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (197946 => 197947)
--- trunk/Source/_javascript_Core/parser/Parser.cpp 2016-03-10 19:26:32 UTC (rev 197946)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp 2016-03-10 19:41:37 UTC (rev 197947)
@@ -3040,6 +3040,10 @@
}
m_parserState.nonTrivialExpressionCount++;
hadAssignment = true;
+ if (!TreeBuilder::CreatesAST) { // We only need to do this check with the syntax checker.
+ if (UNLIKELY(context.isNewTarget(lhs)))
+ internalFailWithMessage(false, "new.target can't be the left hand side of an assignment _expression_");
+ }
context.assignmentStackAppend(assignmentStack, lhs, start, tokenStartPosition(), m_parserState.assignmentCount, op);
start = tokenStartPosition();
m_parserState.assignmentCount++;
@@ -4005,6 +4009,10 @@
failWithMessage("Cannot parse subexpression of ", operatorString(true, lastOperator), "operator");
failWithMessage("Cannot parse member _expression_");
}
+ if (!TreeBuilder::CreatesAST) { // We only need to do this check with the syntax checker.
+ if (UNLIKELY(lastOperator && context.isNewTarget(expr)))
+ internalFailWithMessage(false, "new.target can't come after a prefix operator");
+ }
bool isEvalOrArguments = false;
if (strictMode() && !m_syntaxAlreadyValidated) {
if (context.isResolve(expr))
@@ -4013,6 +4021,10 @@
failIfTrueIfStrict(isEvalOrArguments && modifiesExpr, "Cannot modify '", m_parserState.lastIdentifier->impl(), "' in strict mode");
switch (m_token.m_type) {
case PLUSPLUS:
+ if (!TreeBuilder::CreatesAST) { // We only need to do this check with the syntax checker.
+ if (UNLIKELY(context.isNewTarget(expr)))
+ internalFailWithMessage(false, "new.target can't come before a postfix operator");
+ }
m_parserState.nonTrivialExpressionCount++;
m_parserState.nonLHSCount++;
expr = context.makePostfixNode(location, expr, OpPlusPlus, subExprStart, lastTokenEndPosition(), tokenEndPosition());
@@ -4023,6 +4035,10 @@
next();
break;
case MINUSMINUS:
+ if (!TreeBuilder::CreatesAST) { // We only need to do this check with the syntax checker.
+ if (UNLIKELY(context.isNewTarget(expr)))
+ internalFailWithMessage(false, "new.target can't come before a postfix operator");
+ }
m_parserState.nonTrivialExpressionCount++;
m_parserState.nonLHSCount++;
expr = context.makePostfixNode(location, expr, OpMinusMinus, subExprStart, lastTokenEndPosition(), tokenEndPosition());
Modified: trunk/Source/_javascript_Core/parser/SyntaxChecker.h (197946 => 197947)
--- trunk/Source/_javascript_Core/parser/SyntaxChecker.h 2016-03-10 19:26:32 UTC (rev 197946)
+++ trunk/Source/_javascript_Core/parser/SyntaxChecker.h 2016-03-10 19:41:37 UTC (rev 197947)
@@ -160,6 +160,7 @@
ExpressionType createThisExpr(const JSTokenLocation&, ThisTDZMode) { return ThisExpr; }
ExpressionType createSuperExpr(const JSTokenLocation&) { return SuperExpr; }
ExpressionType createNewTargetExpr(const JSTokenLocation&) { return NewTargetExpr; }
+ ALWAYS_INLINE bool isNewTarget(ExpressionType type) { return type == NewTargetExpr; }
ExpressionType createResolve(const JSTokenLocation&, const Identifier&, int, int) { return ResolveExpr; }
ExpressionType createObjectLiteral(const JSTokenLocation&) { return ObjectLiteralExpr; }
ExpressionType createObjectLiteral(const JSTokenLocation&, int) { return ObjectLiteralExpr; }
Modified: trunk/Source/_javascript_Core/tests/es6.yaml (197946 => 197947)
--- trunk/Source/_javascript_Core/tests/es6.yaml 2016-03-10 19:26:32 UTC (rev 197946)
+++ trunk/Source/_javascript_Core/tests/es6.yaml 2016-03-10 19:41:37 UTC (rev 197947)
@@ -875,7 +875,7 @@
- path: es6/miscellaneous_RegExp_constructor_can_alter_flags.js
cmd: runES6 :fail
- path: es6/new.target_assignment_is_an_early_error.js
- cmd: runES6 :fail
+ cmd: runES6 :normal
- path: es6/non-strict_function_semantics_hoisted_block-level_function_declaration.js
cmd: runES6 :fail
- path: es6/Promise_is_subclassable_Promise.all.js
Added: trunk/Source/_javascript_Core/tests/stress/new-target-syntax-errors.js (0 => 197947)
--- trunk/Source/_javascript_Core/tests/stress/new-target-syntax-errors.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/new-target-syntax-errors.js 2016-03-10 19:41:37 UTC (rev 197947)
@@ -0,0 +1,86 @@
+function shouldBeSyntaxError(str) {
+ let failed = true;
+ try {
+ new Function(str);
+ } catch(e) {
+ if (e instanceof SyntaxError)
+ failed = false;
+ }
+
+ if (failed)
+ throw new Error("Did not throw syntax error: " + str);
+}
+
+function shouldNotBeSyntaxError(str) {
+ let failed = false;
+ try {
+ new Function(str);
+ } catch(e) {
+ if (e instanceof SyntaxError && e.message.indexOf("new.target") !== -1)
+ failed = true;
+ }
+
+ if (failed)
+ throw new Error("Did throw a syntax error: " + str);
+}
+
+
+let operators = ["=", "+=", "-=", "*=", "<<=", ">>=", ">>>=", "&=", "^=", "|=", "%="];
+for (let operator of operators) {
+ let functionBody = `new.target ${operator} 20`;
+ shouldBeSyntaxError(functionBody);
+
+ functionBody = `foo = new.target ${operator} 20`;
+ shouldBeSyntaxError(functionBody);
+
+ functionBody = `foo ${operator} new.target ${operator} 20`;
+ shouldBeSyntaxError(functionBody);
+
+ functionBody = `new.target ${operator} foo *= 40`;
+ shouldBeSyntaxError(functionBody);
+
+
+ // Make sure our tests cases our sound and they should not be syntax errors if new.target is replaced by foo
+ functionBody = `foo ${operator} 20`;
+ shouldNotBeSyntaxError(functionBody);
+
+ functionBody = `foo = foo ${operator} 20`;
+ shouldNotBeSyntaxError(functionBody);
+
+ functionBody = `foo ${operator} foo ${operator} 20`;
+ shouldNotBeSyntaxError(functionBody);
+
+ functionBody = `foo ${operator} foo *= 40`;
+ shouldNotBeSyntaxError(functionBody);
+}
+
+let prePostFixOperators = ["++", "--"];
+for (let operator of prePostFixOperators) {
+ let functionBody = `${operator}new.target`;
+ shouldBeSyntaxError(functionBody);
+
+ functionBody = `foo = ${operator}new.target`;
+ shouldBeSyntaxError(functionBody);
+
+ functionBody = `${operator}foo`;
+ shouldNotBeSyntaxError(functionBody);
+
+ functionBody = `foo = ${operator}foo`;
+ shouldNotBeSyntaxError(functionBody);
+}
+
+for (let operator of prePostFixOperators) {
+ let functionBody = `new.target${operator}`;
+ shouldBeSyntaxError(functionBody);
+
+ functionBody = `foo = new.target${operator}`;
+ shouldBeSyntaxError(functionBody);
+
+ functionBody = `foo${operator}`;
+ shouldNotBeSyntaxError(functionBody);
+
+ functionBody = `foo = foo${operator}`;
+ shouldNotBeSyntaxError(functionBody);
+}
+
+shouldBeSyntaxError(`({foo: new.target} = {foo:20})`);
Modified: trunk/Source/_javascript_Core/tests/stress/new-target.js (197946 => 197947)
--- trunk/Source/_javascript_Core/tests/stress/new-target.js 2016-03-10 19:26:32 UTC (rev 197946)
+++ trunk/Source/_javascript_Core/tests/stress/new-target.js 2016-03-10 19:41:37 UTC (rev 197947)
@@ -33,21 +33,6 @@
}
new Constructor();
-function noAssign() {
- new.target = 1;
-}
-
-try {
- new noAssign();
- passed = false;
-} catch(e) { }
-try {
- noAssign();
- passed = false;
-} catch(e) { }
-
-test(passed, true, "new.target should not be a reference");
-
// This is mostly to test that calling new on new.target deos the right thing.
function doWeirdThings(arg) {
if (new.target) {