зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1243858
- Disallow unary expression on left-hand side of exponentiation operator. r=arai
This commit is contained in:
Родитель
4c4210c697
Коммит
96a41c3380
|
@ -1877,7 +1877,7 @@ ASTSerializer::unop(ParseNodeKind kind, JSOp op)
|
|||
if (IsDeleteKind(kind))
|
||||
return UNOP_DELETE;
|
||||
|
||||
if (kind == PNK_TYPEOFNAME || kind == PNK_TYPEOFEXPR)
|
||||
if (IsTypeofKind(kind))
|
||||
return UNOP_TYPEOF;
|
||||
|
||||
switch (op) {
|
||||
|
|
|
@ -226,6 +226,21 @@ class FullParseHandler
|
|||
return new_<UnaryNode>(kind, op, pos, kid);
|
||||
}
|
||||
|
||||
ParseNode* newUpdate(ParseNodeKind kind, uint32_t begin, ParseNode* kid) {
|
||||
TokenPos pos(begin, kid->pn_pos.end);
|
||||
return new_<UnaryNode>(kind, JSOP_NOP, pos, kid);
|
||||
}
|
||||
|
||||
ParseNode* newSpread(uint32_t begin, ParseNode* kid) {
|
||||
TokenPos pos(begin, kid->pn_pos.end);
|
||||
return new_<UnaryNode>(PNK_SPREAD, JSOP_NOP, pos, kid);
|
||||
}
|
||||
|
||||
ParseNode* newArrayPush(uint32_t begin, ParseNode* kid) {
|
||||
TokenPos pos(begin, kid->pn_pos.end);
|
||||
return new_<UnaryNode>(PNK_ARRAYPUSH, JSOP_ARRAYPUSH, pos, kid);
|
||||
}
|
||||
|
||||
ParseNode* newBinary(ParseNodeKind kind, JSOp op = JSOP_NOP) {
|
||||
return new_<BinaryNode>(kind, op, pos(), (ParseNode*) nullptr, (ParseNode*) nullptr);
|
||||
}
|
||||
|
@ -707,6 +722,15 @@ class FullParseHandler
|
|||
return false;
|
||||
}
|
||||
|
||||
bool isUnparenthesizedUnaryExpression(ParseNode* node) {
|
||||
if (!node->isInParens()) {
|
||||
ParseNodeKind kind = node->getKind();
|
||||
return kind == PNK_VOID || kind == PNK_NOT || kind == PNK_BITNOT || kind == PNK_POS ||
|
||||
kind == PNK_NEG || IsTypeofKind(kind) || IsDeleteKind(kind);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isReturnStatement(ParseNode* node) {
|
||||
return node->isKind(PNK_RETURN);
|
||||
}
|
||||
|
|
|
@ -194,6 +194,12 @@ IsDeleteKind(ParseNodeKind kind)
|
|||
return PNK_DELETENAME <= kind && kind <= PNK_DELETEEXPR;
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsTypeofKind(ParseNodeKind kind)
|
||||
{
|
||||
return PNK_TYPEOFNAME <= kind && kind <= PNK_TYPEOFEXPR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Label Variant Members
|
||||
* ----- ------- -------
|
||||
|
@ -357,7 +363,6 @@ IsDeleteKind(ParseNodeKind kind)
|
|||
* PNK_DELETENAME unary pn_kid: PNK_NAME expr
|
||||
* PNK_DELETEPROP unary pn_kid: PNK_DOT expr
|
||||
* PNK_DELETEELEM unary pn_kid: PNK_ELEM expr
|
||||
* PNK_DELETESUPERELEM unary pn_kid: PNK_SUPERELEM expr
|
||||
* PNK_DELETEEXPR unary pn_kid: MEMBER expr that's evaluated, then the
|
||||
* overall delete evaluates to true; can't be a kind
|
||||
* for a more-specific PNK_DELETE* unless constant
|
||||
|
|
|
@ -7096,6 +7096,11 @@ Parser<ParseHandler>::orExpr1(InHandling inHandling, YieldHandling yieldHandling
|
|||
// Destructuring defaults are an error in this context
|
||||
if (possibleError && !possibleError->checkForExprErrors())
|
||||
return null();
|
||||
// Report an error for unary expressions on the LHS of **.
|
||||
if (tok == TOK_POW && handler.isUnparenthesizedUnaryExpression(pn)) {
|
||||
report(ParseError, false, null(), JSMSG_BAD_POW_LEFTSIDE);
|
||||
return null();
|
||||
}
|
||||
pnk = BinaryOpTokenKindToParseNodeKind(tok);
|
||||
} else {
|
||||
tok = TOK_EOF;
|
||||
|
@ -7603,10 +7608,9 @@ Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, TripledotHandling t
|
|||
AssignmentFlavor flavor = (tt == TOK_INC) ? IncrementAssignment : DecrementAssignment;
|
||||
if (!checkAndMarkAsIncOperand(pn2, flavor))
|
||||
return null();
|
||||
return handler.newUnary((tt == TOK_INC) ? PNK_PREINCREMENT : PNK_PREDECREMENT,
|
||||
JSOP_NOP,
|
||||
begin,
|
||||
pn2);
|
||||
return handler.newUpdate((tt == TOK_INC) ? PNK_PREINCREMENT : PNK_PREDECREMENT,
|
||||
begin,
|
||||
pn2);
|
||||
}
|
||||
|
||||
case TOK_DELETE: {
|
||||
|
@ -7639,10 +7643,9 @@ Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, TripledotHandling t
|
|||
AssignmentFlavor flavor = (tt == TOK_INC) ? IncrementAssignment : DecrementAssignment;
|
||||
if (!checkAndMarkAsIncOperand(pn, flavor))
|
||||
return null();
|
||||
return handler.newUnary((tt == TOK_INC) ? PNK_POSTINCREMENT : PNK_POSTDECREMENT,
|
||||
JSOP_NOP,
|
||||
begin,
|
||||
pn);
|
||||
return handler.newUpdate((tt == TOK_INC) ? PNK_POSTINCREMENT : PNK_POSTDECREMENT,
|
||||
begin,
|
||||
pn);
|
||||
}
|
||||
return pn;
|
||||
}
|
||||
|
@ -7873,7 +7876,7 @@ Parser<ParseHandler>::comprehensionTail(GeneratorKind comprehensionKind)
|
|||
return null();
|
||||
|
||||
if (comprehensionKind == NotGenerator)
|
||||
return handler.newUnary(PNK_ARRAYPUSH, JSOP_ARRAYPUSH, begin, bodyExpr);
|
||||
return handler.newArrayPush(begin, bodyExpr);
|
||||
|
||||
MOZ_ASSERT(comprehensionKind == StarGenerator);
|
||||
Node yieldExpr = newYieldExpression(begin, bodyExpr);
|
||||
|
@ -7994,7 +7997,7 @@ Parser<ParseHandler>::argumentList(YieldHandling yieldHandling, Node listNode, b
|
|||
if (!argNode)
|
||||
return false;
|
||||
if (spread) {
|
||||
argNode = handler.newUnary(PNK_SPREAD, JSOP_NOP, begin, argNode);
|
||||
argNode = handler.newSpread(begin, argNode);
|
||||
if (!argNode)
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -127,6 +127,11 @@ class SyntaxParseHandler
|
|||
// eventually enforce extraWarnings and will require this then.)
|
||||
NodeUnparenthesizedAssignment,
|
||||
|
||||
// This node is necessary to determine if the base operand in an
|
||||
// exponentiation operation is an unparenthesized unary expression.
|
||||
// We want to reject |-2 ** 3|, but still need to allow |(-2) ** 3|.
|
||||
NodeUnparenthesizedUnary,
|
||||
|
||||
// This node is necessary to determine if the LHS of a property access is
|
||||
// super related.
|
||||
NodeSuperBase
|
||||
|
@ -220,14 +225,26 @@ class SyntaxParseHandler
|
|||
Node newElision() { return NodeGeneric; }
|
||||
|
||||
Node newDelete(uint32_t begin, Node expr) {
|
||||
return NodeGeneric;
|
||||
return NodeUnparenthesizedUnary;
|
||||
}
|
||||
|
||||
Node newTypeof(uint32_t begin, Node kid) {
|
||||
return NodeGeneric;
|
||||
return NodeUnparenthesizedUnary;
|
||||
}
|
||||
|
||||
Node newUnary(ParseNodeKind kind, JSOp op, uint32_t begin, Node kid) {
|
||||
return NodeUnparenthesizedUnary;
|
||||
}
|
||||
|
||||
Node newUpdate(ParseNodeKind kind, uint32_t begin, Node kid) {
|
||||
return NodeGeneric;
|
||||
}
|
||||
|
||||
Node newSpread(uint32_t begin, Node kid) {
|
||||
return NodeGeneric;
|
||||
}
|
||||
|
||||
Node newArrayPush(uint32_t begin, Node kid) {
|
||||
return NodeGeneric;
|
||||
}
|
||||
|
||||
|
@ -441,6 +458,10 @@ class SyntaxParseHandler
|
|||
return node == NodeUnparenthesizedAssignment;
|
||||
}
|
||||
|
||||
bool isUnparenthesizedUnaryExpression(Node node) {
|
||||
return node == NodeUnparenthesizedUnary;
|
||||
}
|
||||
|
||||
bool isReturnStatement(Node node) {
|
||||
return node == NodeReturn;
|
||||
}
|
||||
|
@ -478,7 +499,8 @@ class SyntaxParseHandler
|
|||
// them to a generic node.
|
||||
if (node == NodeUnparenthesizedString ||
|
||||
node == NodeUnparenthesizedCommaExpr ||
|
||||
node == NodeUnparenthesizedAssignment)
|
||||
node == NodeUnparenthesizedAssignment ||
|
||||
node == NodeUnparenthesizedUnary)
|
||||
{
|
||||
return NodeGeneric;
|
||||
}
|
||||
|
|
|
@ -179,7 +179,7 @@ MSG_DEF(JSMSG_UNKNOWN_FORMAT, 1, JSEXN_INTERNALERR, "unknown bytecode f
|
|||
// Frontend
|
||||
MSG_DEF(JSMSG_ACCESSOR_WRONG_ARGS, 3, JSEXN_SYNTAXERR, "{0} functions must have {1} argument{2}")
|
||||
MSG_DEF(JSMSG_ARRAY_COMP_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid array comprehension left-hand side")
|
||||
MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG, 0, JSEXN_INTERNALERR, "array initialiser too large")
|
||||
MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG, 0, JSEXN_INTERNALERR, "array initializer too large")
|
||||
MSG_DEF(JSMSG_AS_AFTER_IMPORT_STAR, 0, JSEXN_SYNTAXERR, "missing keyword 'as' after import *")
|
||||
MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD, 1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'")
|
||||
MSG_DEF(JSMSG_BAD_ANON_GENERATOR_RETURN, 0, JSEXN_TYPEERR, "anonymous generator function returns a value")
|
||||
|
@ -202,6 +202,7 @@ MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 0, JSEXN_REFERENCEERR, "invalid increment
|
|||
MSG_DEF(JSMSG_BAD_METHOD_DEF, 0, JSEXN_SYNTAXERR, "bad method definition")
|
||||
MSG_DEF(JSMSG_BAD_OCTAL, 1, JSEXN_SYNTAXERR, "{0} is not a legal ECMA-262 octal constant")
|
||||
MSG_DEF(JSMSG_BAD_OPERAND, 1, JSEXN_SYNTAXERR, "invalid {0} operand")
|
||||
MSG_DEF(JSMSG_BAD_POW_LEFTSIDE, 0, JSEXN_SYNTAXERR, "unparenthesized unary expression can't appear on the left-hand side of '**'")
|
||||
MSG_DEF(JSMSG_BAD_PROP_ID, 0, JSEXN_SYNTAXERR, "invalid property id")
|
||||
MSG_DEF(JSMSG_BAD_RETURN_OR_YIELD, 1, JSEXN_SYNTAXERR, "{0} not in function")
|
||||
MSG_DEF(JSMSG_BAD_STRICT_ASSIGN, 1, JSEXN_SYNTAXERR, "'{0}' can't be defined or assigned to in strict mode code")
|
||||
|
|
|
@ -53,6 +53,28 @@ assertEq(a**/**b**/c/**/**/**d**/e, 16);
|
|||
// Two stars separated should not parse as exp operator
|
||||
assertThrows(function() { return Reflect.parse("2 * * 3"); }, SyntaxError);
|
||||
|
||||
// Left-hand side expression must not be a unary expression.
|
||||
for (let unaryOp of ["delete", "typeof", "void", "+", "-", "!", "~"]) {
|
||||
assertThrowsInstanceOf(() => eval(unaryOp + " a ** 2"), SyntaxError);
|
||||
assertThrowsInstanceOf(() => eval(unaryOp + " " + unaryOp + " a ** 2"), SyntaxError);
|
||||
}
|
||||
|
||||
// Test the other |delete| operators (DELETENAME and DELETEEXPR are already tested above).
|
||||
assertThrowsInstanceOf(() => eval("delete a.name ** 2"), SyntaxError);
|
||||
assertThrowsInstanceOf(() => eval("delete a[0] ** 2"), SyntaxError);
|
||||
|
||||
// Unary expression lhs is valid if parenthesized.
|
||||
for (let unaryOp of ["delete", "void", "+", "-", "!", "~"]) {
|
||||
let a = 0;
|
||||
eval("(" + unaryOp + " a) ** 2");
|
||||
eval("(" + unaryOp + " " + unaryOp + " a) ** 2");
|
||||
}
|
||||
{
|
||||
let a = {};
|
||||
(delete a.name) ** 2;
|
||||
(delete a[0]) ** 2;
|
||||
}
|
||||
|
||||
// Check if error propagation works
|
||||
var thrower = {
|
||||
get value() {
|
||||
|
|
Загрузка…
Ссылка в новой задаче