Make strict more error messages about "eval" and "arguments" less specific.
authormarja@chromium.org <marja@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 5 Feb 2014 16:26:48 +0000 (16:26 +0000)
committermarja@chromium.org <marja@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 5 Feb 2014 16:26:48 +0000 (16:26 +0000)
We used to have error messages which provide context, like "Variable name may
not be eval or arguments in strict mode", but for other illegal words we only
have non-context specific error messages like "Unexpected reserved word".

Providing the context makes the code unnecessarily complex, since every
individual place must remember to check for eval or arguments. This CL produces
a unified error message ("Unexpected eval or arguments in strict mode"), and puts
the error reporting to (Pre)Parser::ParseIdentifier.

Notes:

- The module feature is so experimental, that I decided to not allow "eval" or
"arguments" as module-related identifiers in the strict mode (even though this
check wasn't there before).

- Unfortunately, there were some inconsistencies, since it was the
responsibility of the caller of ParseIdentifier to check "eval" and "arguments"
and some places didn't have the check for no good reason. This CL is supposed to
keep backward compatibility and *not* introduce any new errors.

- ECMA allows "eval" and "arguments" as labels even in strict mode. (Syntax:
"LabelledStatement: Identifier : Statement", and no strict mode restrictions on
Identifier are listed.)

- Tests which compare error message strings will fail, and need to be updated.

BUG=3126
LOG=N
R=ulan@chromium.org

Review URL: https://codereview.chromium.org/152813005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19112 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/messages.js
src/parser.cc
src/parser.h
src/preparser.cc
src/preparser.h
test/webkit/fast/js/basic-strict-mode-expected.txt

index 85351fb..08cb723 100644 (file)
@@ -155,21 +155,15 @@ var kMessages = {
   illegal_access:                ["Illegal access"],
   invalid_preparser_data:        ["Invalid preparser data for function ", "%0"],
   strict_mode_with:              ["Strict mode code may not include a with statement"],
-  strict_catch_variable:         ["Catch variable may not be eval or arguments in strict mode"],
+  strict_eval_arguments:         ["Unexpected eval or arguments in strict mode"],
   too_many_arguments:            ["Too many arguments in function call (only 32766 allowed)"],
   too_many_parameters:           ["Too many parameters in function definition (only 32766 allowed)"],
   too_many_variables:            ["Too many variables declared (only 131071 allowed)"],
-  strict_param_name:             ["Parameter name eval or arguments is not allowed in strict mode"],
   strict_param_dupe:             ["Strict mode function may not have duplicate parameter names"],
-  strict_var_name:               ["Variable name may not be eval or arguments in strict mode"],
-  strict_function_name:          ["Function name may not be eval or arguments in strict mode"],
   strict_octal_literal:          ["Octal literals are not allowed in strict mode."],
   strict_duplicate_property:     ["Duplicate data property in object literal not allowed in strict mode"],
   accessor_data_property:        ["Object literal may not have data and accessor property with the same name"],
   accessor_get_set:              ["Object literal may not have multiple get/set accessors with the same name"],
-  strict_lhs_assignment:         ["Assignment to eval or arguments is not allowed in strict mode"],
-  strict_lhs_postfix:            ["Postfix increment/decrement may not have eval or arguments operand in strict mode"],
-  strict_lhs_prefix:             ["Prefix increment/decrement may not have eval or arguments operand in strict mode"],
   strict_delete:                 ["Delete of an unqualified identifier in strict mode."],
   strict_delete_property:        ["Cannot delete property '", "%0", "' of ", "%1"],
   strict_const:                  ["Use of const in strict mode."],
index 50551ea..211f737 100644 (file)
@@ -983,7 +983,7 @@ Statement* Parser::ParseModuleDeclaration(ZoneStringList* names, bool* ok) {
   //    'module' Identifier Module
 
   int pos = peek_position();
-  Handle<String> name = ParseIdentifier(CHECK_OK);
+  Handle<String> name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
 
 #ifdef DEBUG
   if (FLAG_print_interface_details)
@@ -1136,7 +1136,7 @@ Module* Parser::ParseModuleVariable(bool* ok) {
   //    Identifier
 
   int pos = peek_position();
-  Handle<String> name = ParseIdentifier(CHECK_OK);
+  Handle<String> name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
 #ifdef DEBUG
   if (FLAG_print_interface_details)
     PrintF("# Module variable %s ", name->ToAsciiArray());
@@ -1261,13 +1261,14 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
   switch (peek()) {
     case Token::IDENTIFIER: {
       int pos = position();
-      Handle<String> name = ParseIdentifier(CHECK_OK);
+      Handle<String> name =
+          ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
       // Handle 'module' as a context-sensitive keyword.
       if (!name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("module"))) {
         names.Add(name, zone());
         while (peek() == Token::COMMA) {
           Consume(Token::COMMA);
-          name = ParseIdentifier(CHECK_OK);
+          name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
           names.Add(name, zone());
         }
         ExpectSemicolon(CHECK_OK);
@@ -1632,11 +1633,12 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
 Statement* Parser::ParseNativeDeclaration(bool* ok) {
   int pos = peek_position();
   Expect(Token::FUNCTION, CHECK_OK);
-  Handle<String> name = ParseIdentifier(CHECK_OK);
+  // Allow "eval" or "arguments" for backward compatibility.
+  Handle<String> name = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
   Expect(Token::LPAREN, CHECK_OK);
   bool done = (peek() == Token::RPAREN);
   while (!done) {
-    ParseIdentifier(CHECK_OK);
+    ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
     done = (peek() == Token::RPAREN);
     if (!done) {
       Expect(Token::COMMA, CHECK_OK);
@@ -1900,16 +1902,9 @@ Block* Parser::ParseVariableDeclarations(
 
     // Parse variable name.
     if (nvars > 0) Consume(Token::COMMA);
-    name = ParseIdentifier(CHECK_OK);
+    name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
     if (fni_ != NULL) fni_->PushVariableName(name);
 
-    // Strict mode variables may not be named eval or arguments
-    if (!declaration_scope->is_classic_mode() && IsEvalOrArguments(name)) {
-      ReportMessage("strict_var_name", Vector<const char*>::empty());
-      *ok = false;
-      return NULL;
-    }
-
     // Declare variable.
     // Note that we *always* must treat the initial value via a separate init
     // assignment for variables and constants because the value must be assigned
@@ -2224,7 +2219,8 @@ Statement* Parser::ParseContinueStatement(bool* ok) {
   Token::Value tok = peek();
   if (!scanner().HasAnyLineTerminatorBeforeNext() &&
       tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
-    label = ParseIdentifier(CHECK_OK);
+    // ECMA allows "eval" or "arguments" as labels even in strict mode.
+    label = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
   }
   IterationStatement* target = NULL;
   target = LookupContinueTarget(label, CHECK_OK);
@@ -2255,7 +2251,8 @@ Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) {
   Token::Value tok = peek();
   if (!scanner().HasAnyLineTerminatorBeforeNext() &&
       tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
-    label = ParseIdentifier(CHECK_OK);
+    // ECMA allows "eval" or "arguments" as labels even in strict mode.
+    label = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
   }
   // Parse labeled break statements that target themselves into
   // empty statements, e.g. 'l1: l2: l3: break l2;'
@@ -2485,13 +2482,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
     Expect(Token::LPAREN, CHECK_OK);
     catch_scope = NewScope(top_scope_, CATCH_SCOPE);
     catch_scope->set_start_position(scanner().location().beg_pos);
-    name = ParseIdentifier(CHECK_OK);
-
-    if (!top_scope_->is_classic_mode() && IsEvalOrArguments(name)) {
-      ReportMessage("strict_catch_variable", Vector<const char*>::empty());
-      *ok = false;
-      return NULL;
-    }
+    name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
 
     Expect(Token::RPAREN, CHECK_OK);
 
@@ -2939,7 +2930,7 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
 
   if (!top_scope_->is_classic_mode()) {
     // Assignment to eval or arguments is disallowed in strict mode.
-    CheckStrictModeLValue(expression, "strict_lhs_assignment", CHECK_OK);
+    CheckStrictModeLValue(expression, CHECK_OK);
   }
   MarkAsLValue(expression);
 
@@ -3219,7 +3210,7 @@ Expression* Parser::ParseUnaryExpression(bool* ok) {
 
     if (!top_scope_->is_classic_mode()) {
       // Prefix expression operand in strict mode may not be eval or arguments.
-      CheckStrictModeLValue(expression, "strict_lhs_prefix", CHECK_OK);
+      CheckStrictModeLValue(expression, CHECK_OK);
     }
     MarkAsLValue(expression);
 
@@ -3253,7 +3244,7 @@ Expression* Parser::ParsePostfixExpression(bool* ok) {
 
     if (!top_scope_->is_classic_mode()) {
       // Postfix expression operand in strict mode may not be eval or arguments.
-      CheckStrictModeLValue(expression, "strict_lhs_postfix", CHECK_OK);
+      CheckStrictModeLValue(expression, CHECK_OK);
     }
     MarkAsLValue(expression);
 
@@ -3563,7 +3554,8 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) {
     case Token::IDENTIFIER:
     case Token::YIELD:
     case Token::FUTURE_STRICT_RESERVED_WORD: {
-      Handle<String> name = ParseIdentifier(CHECK_OK);
+      // Using eval or arguments in this context is OK even in strict mode.
+      Handle<String> name = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
       if (fni_ != NULL) fni_->PushVariableName(name);
       // The name may refer to a module instance object, so its type is unknown.
 #ifdef DEBUG
@@ -4303,13 +4295,13 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
     if (!top_scope_->is_classic_mode()) {
       if (IsEvalOrArguments(function_name)) {
         ReportMessageAt(function_name_location,
-                        "strict_function_name",
+                        "strict_eval_arguments",
                         Vector<const char*>::empty());
         *ok = false;
         return NULL;
       }
       if (name_loc.IsValid()) {
-        ReportMessageAt(name_loc, "strict_param_name",
+        ReportMessageAt(name_loc, "strict_eval_arguments",
                         Vector<const char*>::empty());
         *ok = false;
         return NULL;
@@ -4398,7 +4390,8 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) {
 
   int pos = peek_position();
   Expect(Token::MOD, CHECK_OK);
-  Handle<String> name = ParseIdentifier(CHECK_OK);
+  // Allow "eval" or "arguments" for backward compatibility.
+  Handle<String> name = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
   ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
 
   if (extension_ != NULL) {
@@ -4505,13 +4498,25 @@ Literal* Parser::GetLiteralTheHole(int position) {
 
 
 // Parses an identifier that is valid for the current scope, in particular it
-// fails on strict mode future reserved keywords in a strict scope.
-Handle<String> Parser::ParseIdentifier(bool* ok) {
+// fails on strict mode future reserved keywords in a strict scope. If
+// allow_eval_or_arguments is kAllowEvalOrArguments, we allow "eval" or
+// "arguments" as identifier even in strict mode (this is needed in cases like
+// "var foo = eval;").
+Handle<String> Parser::ParseIdentifier(
+    AllowEvalOrArgumentsAsIdentifier allow_eval_or_arguments,
+    bool* ok) {
   Token::Value next = Next();
-  if (next == Token::IDENTIFIER ||
-      (top_scope_->is_classic_mode() &&
-       (next == Token::FUTURE_STRICT_RESERVED_WORD ||
-        (next == Token::YIELD && !is_generator())))) {
+  if (next == Token::IDENTIFIER) {
+    Handle<String> name = GetSymbol();
+    if (allow_eval_or_arguments == kDontAllowEvalOrArguments &&
+        !top_scope_->is_classic_mode() && IsEvalOrArguments(name)) {
+      ReportMessage("strict_eval_arguments", Vector<const char*>::empty());
+      *ok = false;
+    }
+    return name;
+  } else if (top_scope_->is_classic_mode() &&
+             (next == Token::FUTURE_STRICT_RESERVED_WORD ||
+              (next == Token::YIELD && !is_generator()))) {
     return GetSymbol();
   } else {
     ReportUnexpectedToken(next);
@@ -4566,7 +4571,6 @@ void Parser::MarkAsLValue(Expression* expression) {
 // Checks LHS expression for assignment and prefix/postfix increment/decrement
 // in strict mode.
 void Parser::CheckStrictModeLValue(Expression* expression,
-                                   const char* error,
                                    bool* ok) {
   ASSERT(!top_scope_->is_classic_mode());
   VariableProxy* lhs = expression != NULL
@@ -4574,7 +4578,7 @@ void Parser::CheckStrictModeLValue(Expression* expression,
       : NULL;
 
   if (lhs != NULL && !lhs->is_this() && IsEvalOrArguments(lhs->name())) {
-    ReportMessage(error, Vector<const char*>::empty());
+    ReportMessage("strict_eval_arguments", Vector<const char*>::empty());
     *ok = false;
   }
 }
index d415539..f3c5e61 100644 (file)
@@ -687,7 +687,7 @@ class Parser : public ParserBase {
   Literal* GetLiteralUndefined(int position);
   Literal* GetLiteralTheHole(int position);
 
-  Handle<String> ParseIdentifier(bool* ok);
+  Handle<String> ParseIdentifier(AllowEvalOrArgumentsAsIdentifier, bool* ok);
   Handle<String> ParseIdentifierOrStrictReservedWord(
       bool* is_strict_reserved, bool* ok);
   Handle<String> ParseIdentifierName(bool* ok);
@@ -702,7 +702,6 @@ class Parser : public ParserBase {
 
   // Strict mode validation of LValue expressions
   void CheckStrictModeLValue(Expression* expression,
-                             const char* error,
                              bool* ok);
 
   // For harmony block scoping mode: Check if the scope has conflicting var/let
index c14d141..7d48dd8 100644 (file)
@@ -296,16 +296,19 @@ PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) {
   Expect(Token::FUNCTION, CHECK_OK);
 
   bool is_generator = allow_generators() && Check(Token::MUL);
-  Identifier identifier = ParseIdentifier(CHECK_OK);
+  Identifier identifier = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
   Scanner::Location location = scanner()->location();
 
   Expression function_value = ParseFunctionLiteral(is_generator, CHECK_OK);
 
+  // If we're in strict mode, ParseIdentifier will catch using eval, arguments
+  // or a strict reserved word as function name. However, if only the function
+  // is strict, we need to do an extra check.
   if (function_value.IsStrictFunction() &&
       !identifier.IsValidStrictVariable()) {
     // Strict mode violation, using either reserved word or eval/arguments
     // as name of strict function.
-    const char* type = "strict_function_name";
+    const char* type = "strict_eval_arguments";
     if (identifier.IsFutureStrictReserved() || identifier.IsYield()) {
       type = "unexpected_strict_reserved";
     }
@@ -446,14 +449,7 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
   do {
     // Parse variable name.
     if (nvars > 0) Consume(Token::COMMA);
-    Identifier identifier  = ParseIdentifier(CHECK_OK);
-    if (!is_classic_mode() && !identifier.IsValidStrictVariable()) {
-      StrictModeIdentifierViolation(scanner()->location(),
-                                    "strict_var_name",
-                                    identifier,
-                                    ok);
-      return Statement::Default();
-    }
+    ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
     nvars++;
     if (peek() == Token::ASSIGN || require_initializer) {
       Expect(Token::ASSIGN, CHECK_OK);
@@ -519,7 +515,8 @@ PreParser::Statement PreParser::ParseContinueStatement(bool* ok) {
       tok != Token::SEMICOLON &&
       tok != Token::RBRACE &&
       tok != Token::EOS) {
-    ParseIdentifier(CHECK_OK);
+    // ECMA allows "eval" or "arguments" as labels even in strict mode.
+    ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
   }
   ExpectSemicolon(CHECK_OK);
   return Statement::Default();
@@ -536,7 +533,8 @@ PreParser::Statement PreParser::ParseBreakStatement(bool* ok) {
       tok != Token::SEMICOLON &&
       tok != Token::RBRACE &&
       tok != Token::EOS) {
-    ParseIdentifier(CHECK_OK);
+    // ECMA allows "eval" or "arguments" as labels even in strict mode.
+    ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
   }
   ExpectSemicolon(CHECK_OK);
   return Statement::Default();
@@ -753,14 +751,7 @@ PreParser::Statement PreParser::ParseTryStatement(bool* ok) {
   if (peek() == Token::CATCH) {
     Consume(Token::CATCH);
     Expect(Token::LPAREN, CHECK_OK);
-    Identifier id = ParseIdentifier(CHECK_OK);
-    if (!is_classic_mode() && !id.IsValidStrictVariable()) {
-      StrictModeIdentifierViolation(scanner()->location(),
-                                    "strict_catch_variable",
-                                    id,
-                                    ok);
-      return Statement::Default();
-    }
+    ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
     Expect(Token::RPAREN, CHECK_OK);
     { Scope::InsideWith iw(scope_);
       ParseBlock(CHECK_OK);
@@ -841,7 +832,7 @@ PreParser::Expression PreParser::ParseAssignmentExpression(bool accept_IN,
       expression.AsIdentifier().IsEvalOrArguments()) {
     Scanner::Location after = scanner()->location();
     ReportMessageAt(before.beg_pos, after.end_pos,
-                    "strict_lhs_assignment", NULL);
+                    "strict_eval_arguments", NULL);
     *ok = false;
     return Expression::Default();
   }
@@ -935,7 +926,7 @@ PreParser::Expression PreParser::ParseUnaryExpression(bool* ok) {
         expression.AsIdentifier().IsEvalOrArguments()) {
       Scanner::Location after = scanner()->location();
       ReportMessageAt(before.beg_pos, after.end_pos,
-                      "strict_lhs_prefix", NULL);
+                      "strict_eval_arguments", NULL);
       *ok = false;
     }
     return Expression::Default();
@@ -958,7 +949,7 @@ PreParser::Expression PreParser::ParsePostfixExpression(bool* ok) {
         expression.AsIdentifier().IsEvalOrArguments()) {
       Scanner::Location after = scanner()->location();
       ReportMessageAt(before.beg_pos, after.end_pos,
-                      "strict_lhs_postfix", NULL);
+                      "strict_eval_arguments", NULL);
       *ok = false;
       return Expression::Default();
     }
@@ -1059,12 +1050,15 @@ PreParser::Expression PreParser::ParseMemberWithNewPrefixesExpression(
     bool is_generator = allow_generators() && Check(Token::MUL);
     Identifier identifier = Identifier::Default();
     if (peek_any_identifier()) {
-      identifier = ParseIdentifier(CHECK_OK);
+      identifier = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
     }
     result = ParseFunctionLiteral(is_generator, CHECK_OK);
+    // If we're in strict mode, ParseIdentifier will catch using eval, arguments
+    // or a strict reserved word as function name. However, if only the function
+    // is strict, we need to do an extra check.
     if (result.IsStrictFunction() && !identifier.IsValidStrictVariable()) {
       StrictModeIdentifierViolation(scanner()->location(),
-                                    "strict_function_name",
+                                    "strict_eval_arguments",
                                     identifier,
                                     ok);
       return Expression::Default();
@@ -1137,7 +1131,8 @@ PreParser::Expression PreParser::ParsePrimaryExpression(bool* ok) {
     case Token::FUTURE_STRICT_RESERVED_WORD:
     case Token::YIELD:
     case Token::IDENTIFIER: {
-      Identifier id = ParseIdentifier(CHECK_OK);
+      // Using eval or arguments in this context is OK even in strict mode.
+      Identifier id = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
       result = Expression::FromIdentifier(id);
       break;
     }
@@ -1354,13 +1349,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(bool is_generator,
   bool done = (peek() == Token::RPAREN);
   DuplicateFinder duplicate_finder(scanner()->unicode_cache());
   while (!done) {
-    Identifier id = ParseIdentifier(CHECK_OK);
-    if (!id.IsValidStrictVariable()) {
-      StrictModeIdentifierViolation(scanner()->location(),
-                                    "strict_param_name",
-                                    id,
-                                    CHECK_OK);
-    }
+    ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
     int prev_value;
     if (scanner()->is_literal_ascii()) {
       prev_value =
@@ -1434,7 +1423,8 @@ PreParser::Expression PreParser::ParseV8Intrinsic(bool* ok) {
     *ok = false;
     return Expression::Default();
   }
-  ParseIdentifier(CHECK_OK);
+  // Allow "eval" or "arguments" for backward compatibility.
+  ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
   ParseArguments(ok);
 
   return Expression::Default();
@@ -1493,12 +1483,26 @@ PreParser::Identifier PreParser::GetIdentifierSymbol() {
 }
 
 
-PreParser::Identifier PreParser::ParseIdentifier(bool* ok) {
+// Parses an identifier that is valid for the current scope, in particular it
+// fails on strict mode future reserved keywords in a strict scope. If
+// allow_eval_or_arguments is kAllowEvalOrArguments, we allow "eval" or
+// "arguments" as identifier even in strict mode (this is needed in cases like
+// "var foo = eval;").
+PreParser::Identifier PreParser::ParseIdentifier(
+    AllowEvalOrArgumentsAsIdentifier allow_eval_or_arguments,
+    bool* ok) {
   Token::Value next = Next();
-  if (next == Token::IDENTIFIER ||
-      (is_classic_mode() &&
-       (next == Token::FUTURE_STRICT_RESERVED_WORD ||
-        (next == Token::YIELD && !scope_->is_generator())))) {
+  if (next == Token::IDENTIFIER) {
+    PreParser::Identifier name = GetIdentifierSymbol();
+    if (allow_eval_or_arguments == kDontAllowEvalOrArguments &&
+        !is_classic_mode() && name.IsEvalOrArguments()) {
+      StrictModeIdentifierViolation(
+          scanner()->location(), "strict_eval_arguments", name, ok);
+    }
+    return name;
+  } else if (is_classic_mode() &&
+             (next == Token::FUTURE_STRICT_RESERVED_WORD ||
+              (next == Token::YIELD && !scope_->is_generator()))) {
     return GetIdentifierSymbol();
   } else {
     ReportUnexpectedToken(next);
index e99b4b0..0db902f 100644 (file)
@@ -76,6 +76,11 @@ class ParserBase {
   }
 
  protected:
+  enum AllowEvalOrArgumentsAsIdentifier {
+    kAllowEvalOrArguments,
+    kDontAllowEvalOrArguments
+  };
+
   Scanner* scanner() const { return scanner_; }
   int position() { return scanner_->location().beg_pos; }
   int peek_position() { return scanner_->peek_location().beg_pos; }
@@ -640,7 +645,7 @@ class PreParser : public ParserBase {
   Expression ParseFunctionLiteral(bool is_generator, bool* ok);
   void ParseLazyFunctionLiteralBody(bool* ok);
 
-  Identifier ParseIdentifier(bool* ok);
+  Identifier ParseIdentifier(AllowEvalOrArgumentsAsIdentifier, bool* ok);
   Identifier ParseIdentifierName(bool* ok);
   Identifier ParseIdentifierNameOrGetOrSet(bool* is_get,
                                            bool* is_set,
index 029689a..07ecf99 100644 (file)
@@ -53,22 +53,22 @@ PASS testThis.call() is undefined
 PASS testThis.apply() is undefined
 PASS testThis.call(undefined) is undefined
 PASS testThis.apply(undefined) is undefined
-PASS (function eval(){'use strict';}) threw exception SyntaxError: Function name may not be eval or arguments in strict mode.
-PASS (function(){(function eval(){'use strict';})}) threw exception SyntaxError: Function name may not be eval or arguments in strict mode.
-PASS (function (eval){'use strict';}) threw exception SyntaxError: Parameter name eval or arguments is not allowed in strict mode.
-PASS (function(){(function (eval){'use strict';})}) threw exception SyntaxError: Parameter name eval or arguments is not allowed in strict mode.
-PASS (function arguments(){'use strict';}) threw exception SyntaxError: Function name may not be eval or arguments in strict mode.
-PASS (function(){(function arguments(){'use strict';})}) threw exception SyntaxError: Function name may not be eval or arguments in strict mode.
-PASS (function (arguments){'use strict';}) threw exception SyntaxError: Parameter name eval or arguments is not allowed in strict mode.
-PASS (function(){(function (arguments){'use strict';})}) threw exception SyntaxError: Parameter name eval or arguments is not allowed in strict mode.
-PASS (function (){'use strict'; var eval;}) threw exception SyntaxError: Variable name may not be eval or arguments in strict mode.
-PASS (function(){(function (){'use strict'; var eval;})}) threw exception SyntaxError: Variable name may not be eval or arguments in strict mode.
-PASS (function (){'use strict'; var arguments;}) threw exception SyntaxError: Variable name may not be eval or arguments in strict mode.
-PASS (function(){(function (){'use strict'; var arguments;})}) threw exception SyntaxError: Variable name may not be eval or arguments in strict mode.
-PASS (function (){'use strict'; try{}catch(eval){}}) threw exception SyntaxError: Catch variable may not be eval or arguments in strict mode.
-PASS (function(){(function (){'use strict'; try{}catch(eval){}})}) threw exception SyntaxError: Catch variable may not be eval or arguments in strict mode.
-PASS (function (){'use strict'; try{}catch(arguments){}}) threw exception SyntaxError: Catch variable may not be eval or arguments in strict mode.
-PASS (function(){(function (){'use strict'; try{}catch(arguments){}})}) threw exception SyntaxError: Catch variable may not be eval or arguments in strict mode.
+PASS (function eval(){'use strict';}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function(){(function eval(){'use strict';})}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function (eval){'use strict';}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function(){(function (eval){'use strict';})}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function arguments(){'use strict';}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function(){(function arguments(){'use strict';})}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function (arguments){'use strict';}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function(){(function (arguments){'use strict';})}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function (){'use strict'; var eval;}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function(){(function (){'use strict'; var eval;})}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function (){'use strict'; var arguments;}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function(){(function (){'use strict'; var arguments;})}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function (){'use strict'; try{}catch(eval){}}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function(){(function (){'use strict'; try{}catch(eval){}})}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function (){'use strict'; try{}catch(arguments){}}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function(){(function (){'use strict'; try{}catch(arguments){}})}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
 PASS (function (a, a){'use strict';}) threw exception SyntaxError: Strict mode function may not have duplicate parameter names.
 PASS (function(){(function (a, a){'use strict';})}) threw exception SyntaxError: Strict mode function may not have duplicate parameter names.
 PASS (function (a){'use strict'; delete a;})() threw exception SyntaxError: Delete of an unqualified identifier in strict mode..
@@ -134,23 +134,23 @@ PASS 'use strict'; eval('var introducedVariable = "FAIL: variable introduced int
 PASS 'use strict'; objectWithReadonlyProperty.prop = 'fail' threw exception TypeError: Cannot assign to read only property 'prop' of #<Object>.
 PASS 'use strict'; delete objectWithReadonlyProperty.prop threw exception TypeError: Cannot delete property 'prop' of #<Object>.
 PASS 'use strict'; delete objectWithReadonlyProperty[readonlyPropName] threw exception TypeError: Cannot delete property 'prop' of #<Object>.
-PASS 'use strict'; ++eval threw exception SyntaxError: Prefix increment/decrement may not have eval or arguments operand in strict mode.
-PASS (function(){'use strict'; ++eval}) threw exception SyntaxError: Prefix increment/decrement may not have eval or arguments operand in strict mode.
-PASS 'use strict'; eval++ threw exception SyntaxError: Postfix increment/decrement may not have eval or arguments operand in strict mode.
-PASS (function(){'use strict'; eval++}) threw exception SyntaxError: Postfix increment/decrement may not have eval or arguments operand in strict mode.
-PASS 'use strict'; --eval threw exception SyntaxError: Prefix increment/decrement may not have eval or arguments operand in strict mode.
-PASS (function(){'use strict'; --eval}) threw exception SyntaxError: Prefix increment/decrement may not have eval or arguments operand in strict mode.
-PASS 'use strict'; eval-- threw exception SyntaxError: Postfix increment/decrement may not have eval or arguments operand in strict mode.
-PASS (function(){'use strict'; eval--}) threw exception SyntaxError: Postfix increment/decrement may not have eval or arguments operand in strict mode.
-PASS 'use strict'; function f() { ++arguments } threw exception SyntaxError: Prefix increment/decrement may not have eval or arguments operand in strict mode.
-PASS (function(){'use strict'; function f() { ++arguments }}) threw exception SyntaxError: Prefix increment/decrement may not have eval or arguments operand in strict mode.
-PASS 'use strict'; function f() { arguments++ } threw exception SyntaxError: Postfix increment/decrement may not have eval or arguments operand in strict mode.
-PASS (function(){'use strict'; function f() { arguments++ }}) threw exception SyntaxError: Postfix increment/decrement may not have eval or arguments operand in strict mode.
-PASS 'use strict'; function f() { --arguments } threw exception SyntaxError: Prefix increment/decrement may not have eval or arguments operand in strict mode.
-PASS (function(){'use strict'; function f() { --arguments }}) threw exception SyntaxError: Prefix increment/decrement may not have eval or arguments operand in strict mode.
-PASS 'use strict'; function f() { arguments-- } threw exception SyntaxError: Postfix increment/decrement may not have eval or arguments operand in strict mode.
-PASS (function(){'use strict'; function f() { arguments-- }}) threw exception SyntaxError: Postfix increment/decrement may not have eval or arguments operand in strict mode.
-PASS global.eval('"use strict"; if (0) ++arguments; true;') threw exception SyntaxError: Prefix increment/decrement may not have eval or arguments operand in strict mode.
+PASS 'use strict'; ++eval threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function(){'use strict'; ++eval}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS 'use strict'; eval++ threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function(){'use strict'; eval++}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS 'use strict'; --eval threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function(){'use strict'; --eval}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS 'use strict'; eval-- threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function(){'use strict'; eval--}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS 'use strict'; function f() { ++arguments } threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function(){'use strict'; function f() { ++arguments }}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS 'use strict'; function f() { arguments++ } threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function(){'use strict'; function f() { arguments++ }}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS 'use strict'; function f() { --arguments } threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function(){'use strict'; function f() { --arguments }}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS 'use strict'; function f() { arguments-- } threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function(){'use strict'; function f() { arguments-- }}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS global.eval('"use strict"; if (0) ++arguments; true;') threw exception SyntaxError: Unexpected eval or arguments in strict mode.
 PASS 'use strict'; ++(1, eval) threw exception ReferenceError: Invalid left-hand side expression in prefix operation.
 FAIL (function(){'use strict'; ++(1, eval)}) should throw an exception. Was function (){'use strict'; ++(1, eval)}.
 PASS 'use strict'; (1, eval)++ threw exception ReferenceError: Invalid left-hand side expression in postfix operation.
@@ -212,16 +212,16 @@ PASS 'use strict';̻ threw exception SyntaxError: Unexpected token ILLEGAL.
 PASS (function(){'use strict';̻}) threw exception SyntaxError: Unexpected token ILLEGAL.
 PASS 'use strict';5.f threw exception SyntaxError: Unexpected token ILLEGAL.
 PASS (function(){'use strict';5.f}) threw exception SyntaxError: Unexpected token ILLEGAL.
-PASS 'use strict';1-(eval=1); threw exception SyntaxError: Assignment to eval or arguments is not allowed in strict mode.
-PASS (function(){'use strict';1-(eval=1);}) threw exception SyntaxError: Assignment to eval or arguments is not allowed in strict mode.
-PASS 'use strict';arguments=1; threw exception SyntaxError: Assignment to eval or arguments is not allowed in strict mode.
-PASS (function(){'use strict';arguments=1;}) threw exception SyntaxError: Assignment to eval or arguments is not allowed in strict mode.
-PASS 'use strict';1-(arguments=1); threw exception SyntaxError: Assignment to eval or arguments is not allowed in strict mode.
-PASS (function(){'use strict';1-(arguments=1);}) threw exception SyntaxError: Assignment to eval or arguments is not allowed in strict mode.
-PASS 'use strict';var a=(eval=1); threw exception SyntaxError: Assignment to eval or arguments is not allowed in strict mode.
-PASS (function(){'use strict';var a=(eval=1);}) threw exception SyntaxError: Assignment to eval or arguments is not allowed in strict mode.
-PASS 'use strict';var a=(arguments=1); threw exception SyntaxError: Assignment to eval or arguments is not allowed in strict mode.
-PASS (function(){'use strict';var a=(arguments=1);}) threw exception SyntaxError: Assignment to eval or arguments is not allowed in strict mode.
+PASS 'use strict';1-(eval=1); threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function(){'use strict';1-(eval=1);}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS 'use strict';arguments=1; threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function(){'use strict';arguments=1;}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS 'use strict';1-(arguments=1); threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function(){'use strict';1-(arguments=1);}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS 'use strict';var a=(eval=1); threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function(){'use strict';var a=(eval=1);}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS 'use strict';var a=(arguments=1); threw exception SyntaxError: Unexpected eval or arguments in strict mode.
+PASS (function(){'use strict';var a=(arguments=1);}) threw exception SyntaxError: Unexpected eval or arguments in strict mode.
 PASS 'use strict'; try { throw 1; } catch (e) { aGlobal = true; } is true
 PASS 'use strict'; (function () { try { throw 1; } catch (e) { aGlobal = true; }})(); aGlobal; is true
 PASS (function () {'use strict';  try { throw 1; } catch (e) { aGlobal = true; }})(); aGlobal; is true