F(this, "this") \
F(throw_iterator_result_not_an_object, "ThrowIteratorResultNotAnObject") \
F(to_string, "ToString") \
+ F(undefined, "undefined") \
F(use_asm, "use asm") \
F(use_strong, "use strong") \
F(use_strict, "use strict") \
strict_caller: ["Illegal access to a strict mode caller function."],
strong_ellision: ["In strong mode, arrays with holes are deprecated, use maps instead"],
strong_arguments: ["In strong mode, 'arguments' is deprecated, use '...args' instead"],
+ strong_undefined: ["In strong mode, binding or assigning to 'undefined' is deprecated"],
strong_equal: ["In strong mode, '==' and '!=' are deprecated, use '===' and '!==' instead"],
strong_delete: ["In strong mode, 'delete' is deprecated, use maps or sets instead"],
strong_var: ["In strong mode, 'var' is deprecated, use 'let' or 'const' instead"],
return IsEval(identifier) || IsArguments(identifier);
}
+bool ParserTraits::IsUndefined(const AstRawString* identifier) const {
+ return identifier == parser_->ast_value_factory()->undefined_string();
+}
bool ParserTraits::IsPrototype(const AstRawString* identifier) const {
return identifier == parser_->ast_value_factory()->prototype_string();
*ok = false;
ReportMessage("strict_eval_arguments");
return NULL;
+ } else if (is_strong(language_mode()) && IsUndefined(local_name)) {
+ *ok = false;
+ ReportMessage("strong_undefined");
+ return NULL;
}
VariableProxy* proxy = NewUnresolved(local_name, IMPORT);
ImportDeclaration* declaration =
ImportDeclaration* import_default_declaration = NULL;
if (tok != Token::MUL && tok != Token::LBRACE) {
const AstRawString* local_name =
- ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
+ ParseIdentifier(kDontAllowRestrictedIdentifiers, CHECK_OK);
VariableProxy* proxy = NewUnresolved(local_name, IMPORT);
import_default_declaration = factory()->NewImportDeclaration(
proxy, ast_value_factory()->default_string(), NULL, scope_, pos);
Consume(Token::MUL);
ExpectContextualKeyword(CStrVector("as"), CHECK_OK);
module_instance_binding =
- ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
+ ParseIdentifier(kDontAllowRestrictedIdentifiers, CHECK_OK);
// TODO(ES6): Add an appropriate declaration.
break;
}
int pos = peek_position();
Expect(Token::FUNCTION, CHECK_OK);
// Allow "eval" or "arguments" for backward compatibility.
- const AstRawString* name = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
+ const AstRawString* name =
+ ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
bool done = (peek() == Token::RPAREN);
while (!done) {
- ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
+ ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
done = (peek() == Token::RPAREN);
if (!done) {
Expect(Token::COMMA, CHECK_OK);
// Parse variable name.
if (nvars > 0) Consume(Token::COMMA);
- name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
+ name = ParseIdentifier(kDontAllowRestrictedIdentifiers, CHECK_OK);
if (!first_name) first_name = name;
Scanner::Location variable_loc = scanner()->location();
if (fni_ != NULL) fni_->PushVariableName(name);
if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
// ECMA allows "eval" or "arguments" as labels even in strict mode.
- label = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
+ label = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
}
IterationStatement* target = LookupContinueTarget(label, CHECK_OK);
if (target == NULL) {
if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
// ECMA allows "eval" or "arguments" as labels even in strict mode.
- label = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
+ label = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
}
// Parse labeled break statements that target themselves into
// empty statements, e.g. 'l1: l2: l3: break l2;'
Expect(Token::LPAREN, CHECK_OK);
catch_scope = NewScope(scope_, CATCH_SCOPE);
catch_scope->set_start_position(scanner()->location().beg_pos);
- name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
+ name = ParseIdentifier(kDontAllowRestrictedIdentifiers, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
Scanner::Location dupe_error_loc = Scanner::Location::invalid();
Scanner::Location reserved_error_loc = Scanner::Location::invalid();
+ // Similarly for strong mode.
+ Scanner::Location undefined_error_loc = Scanner::Location::invalid();
+
bool is_rest = false;
bool done = arity_restriction == FunctionLiteral::GETTER_ARITY ||
(peek() == Token::RPAREN &&
if (!eval_args_error_loc.IsValid() && IsEvalOrArguments(param_name)) {
eval_args_error_loc = scanner()->location();
}
+ if (!undefined_error_loc.IsValid() && IsUndefined(param_name)) {
+ undefined_error_loc = scanner()->location();
+ }
if (!reserved_error_loc.IsValid() && is_strict_reserved) {
reserved_error_loc = scanner()->location();
}
CHECK_OK);
const bool use_strict_params = is_rest || IsConciseMethod(kind);
CheckFunctionParameterNames(language_mode(), use_strict_params,
- eval_args_error_loc, dupe_error_loc,
- reserved_error_loc, CHECK_OK);
+ eval_args_error_loc, undefined_error_loc,
+ dupe_error_loc, reserved_error_loc, CHECK_OK);
if (is_strict(language_mode())) {
CheckStrictOctalLiteral(scope->start_position(), scope->end_position(),
*ok = false;
return NULL;
}
+ if (is_strong(language_mode()) && IsUndefined(name)) {
+ ReportMessageAt(class_name_location, "strong_undefined");
+ *ok = false;
+ return NULL;
+ }
// Create a block scope which is additionally tagged as class scope; this is
// important for resolving variable references to the class name in the strong
int pos = peek_position();
Expect(Token::MOD, CHECK_OK);
// Allow "eval" or "arguments" for backward compatibility.
- const AstRawString* name = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
+ const AstRawString* name = ParseIdentifier(kAllowRestrictedIdentifiers,
+ CHECK_OK);
Scanner::Location spread_pos;
ZoneList<Expression*>* args = ParseArguments(&spread_pos, CHECK_OK);
bool IsEval(const AstRawString* identifier) const;
bool IsArguments(const AstRawString* identifier) const;
bool IsEvalOrArguments(const AstRawString* identifier) const;
+ bool IsUndefined(const AstRawString* identifier) const;
V8_INLINE bool IsFutureStrictReserved(const AstRawString* identifier) const;
// Returns true if the expression is of type "this.foo".
if (scanner->UnescapedLiteralMatches("arguments", 9)) {
return PreParserIdentifier::Arguments();
}
+ if (scanner->UnescapedLiteralMatches("undefined", 9)) {
+ return PreParserIdentifier::Undefined();
+ }
if (scanner->LiteralMatches("prototype", 9)) {
return PreParserIdentifier::Prototype();
}
do {
// Parse variable name.
if (nvars > 0) Consume(Token::COMMA);
- ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
+ ParseIdentifier(kDontAllowRestrictedIdentifiers, CHECK_OK);
Scanner::Location variable_loc = scanner()->location();
nvars++;
if (peek() == Token::ASSIGN || require_initializer ||
tok != Token::RBRACE &&
tok != Token::EOS) {
// ECMA allows "eval" or "arguments" as labels even in strict mode.
- ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
+ ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
}
ExpectSemicolon(CHECK_OK);
return Statement::Default();
tok != Token::RBRACE &&
tok != Token::EOS) {
// ECMA allows "eval" or "arguments" as labels even in strict mode.
- ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
+ ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
}
ExpectSemicolon(CHECK_OK);
return Statement::Default();
if (tok == Token::CATCH) {
Consume(Token::CATCH);
Expect(Token::LPAREN, CHECK_OK);
- ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
+ ParseIdentifier(kDontAllowRestrictedIdentifiers, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
{
Scope* with_scope = NewScope(scope_, WITH_SCOPE);
Scanner::Location dupe_error_loc = Scanner::Location::invalid();
Scanner::Location reserved_error_loc = Scanner::Location::invalid();
+ // Similarly for strong mode.
+ Scanner::Location undefined_error_loc = Scanner::Location::invalid();
+
bool is_rest = false;
bool done = arity_restriction == FunctionLiteral::GETTER_ARITY ||
(peek() == Token::RPAREN &&
if (!eval_args_error_loc.IsValid() && param_name.IsEvalOrArguments()) {
eval_args_error_loc = scanner()->location();
}
+ if (!undefined_error_loc.IsValid() && param_name.IsUndefined()) {
+ undefined_error_loc = scanner()->location();
+ }
if (!reserved_error_loc.IsValid() && is_strict_reserved) {
reserved_error_loc = scanner()->location();
}
name_is_strict_reserved, function_name_location, CHECK_OK);
const bool use_strict_params = is_rest || IsConciseMethod(kind);
CheckFunctionParameterNames(language_mode(), use_strict_params,
- eval_args_error_loc, dupe_error_loc,
- reserved_error_loc, CHECK_OK);
+ eval_args_error_loc, undefined_error_loc,
+ dupe_error_loc, reserved_error_loc, CHECK_OK);
if (is_strict(language_mode())) {
int end_position = scanner()->location().end_pos;
*ok = false;
return EmptyExpression();
}
+ LanguageMode class_language_mode = language_mode();
+ if (is_strong(class_language_mode) && IsUndefined(name)) {
+ ReportMessageAt(class_name_location, "strong_undefined");
+ *ok = false;
+ return EmptyExpression();
+ }
Scope* scope = NewScope(scope_, BLOCK_SCOPE);
BlockState block_state(&scope_, scope);
scope_->SetLanguageMode(
- static_cast<LanguageMode>(scope_->language_mode() | STRICT_BIT));
+ static_cast<LanguageMode>(class_language_mode | STRICT_BIT));
// TODO(marja): Make PreParser use scope names too.
// scope_->SetScopeName(name);
return Expression::Default();
}
// Allow "eval" or "arguments" for backward compatibility.
- ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
+ ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
Scanner::Location spread_pos;
ParseArguments(&spread_pos, ok);
void set_allow_strong_mode(bool allow) { allow_strong_mode_ = allow; }
protected:
- enum AllowEvalOrArgumentsAsIdentifier {
- kAllowEvalOrArguments,
- kDontAllowEvalOrArguments
+ enum AllowRestrictedIdentifiers {
+ kAllowRestrictedIdentifiers,
+ kDontAllowRestrictedIdentifiers
};
enum Mode {
*ok = false;
return;
}
+ if (is_strong(language_mode) && this->IsUndefined(function_name)) {
+ Traits::ReportMessageAt(function_name_loc, "strong_undefined");
+ *ok = false;
+ return;
+ }
}
// Checking the parameter names of a function literal. This has to be done
void CheckFunctionParameterNames(LanguageMode language_mode,
bool strict_params,
const Scanner::Location& eval_args_error_loc,
+ const Scanner::Location& undefined_error_loc,
const Scanner::Location& dupe_error_loc,
const Scanner::Location& reserved_loc,
bool* ok) {
*ok = false;
return;
}
+ if (is_strong(language_mode) && undefined_error_loc.IsValid()) {
+ Traits::ReportMessageAt(eval_args_error_loc, "strong_undefined");
+ *ok = false;
+ return;
+ }
// TODO(arv): When we add support for destructuring in setters we also need
// to check for duplicate names.
if (dupe_error_loc.IsValid()) {
// 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;").
- IdentifierT ParseIdentifier(
- AllowEvalOrArgumentsAsIdentifier,
- bool* ok);
+ IdentifierT ParseIdentifier(AllowRestrictedIdentifiers, bool* ok);
// Parses an identifier or a strict mode future reserved word, and indicate
// whether it is strict mode future reserved.
IdentifierT ParseIdentifierOrStrictReservedWord(
static PreParserIdentifier Arguments() {
return PreParserIdentifier(kArgumentsIdentifier);
}
+ static PreParserIdentifier Undefined() {
+ return PreParserIdentifier(kUndefinedIdentifier);
+ }
static PreParserIdentifier FutureReserved() {
return PreParserIdentifier(kFutureReservedIdentifier);
}
bool IsEval() const { return type_ == kEvalIdentifier; }
bool IsArguments() const { return type_ == kArgumentsIdentifier; }
bool IsEvalOrArguments() const { return IsEval() || IsArguments(); }
+ bool IsUndefined() const { return type_ == kUndefinedIdentifier; }
bool IsLet() const { return type_ == kLetIdentifier; }
bool IsStatic() const { return type_ == kStaticIdentifier; }
bool IsYield() const { return type_ == kYieldIdentifier; }
type_ == kLetIdentifier || type_ == kStaticIdentifier ||
type_ == kYieldIdentifier;
}
- bool IsValidStrictVariable() const { return type_ == kUnknownIdentifier; }
V8_INLINE bool IsValidArrowParam() const {
// A valid identifier can be an arrow function parameter
// except for eval, arguments, yield, and reserved keywords.
kYieldIdentifier,
kEvalIdentifier,
kArgumentsIdentifier,
+ kUndefinedIdentifier,
kPrototypeIdentifier,
kConstructorIdentifier
};
return identifier.IsEvalOrArguments();
}
+ static bool IsUndefined(PreParserIdentifier identifier) {
+ return identifier.IsUndefined();
+ }
+
static bool IsPrototype(PreParserIdentifier identifier) {
return identifier.IsPrototype();
}
}
-template<class Traits>
+template <class Traits>
typename ParserBase<Traits>::IdentifierT ParserBase<Traits>::ParseIdentifier(
- AllowEvalOrArgumentsAsIdentifier allow_eval_or_arguments,
- bool* ok) {
+ AllowRestrictedIdentifiers allow_restricted_identifiers, bool* ok) {
Token::Value next = Next();
if (next == Token::IDENTIFIER) {
IdentifierT name = this->GetSymbol(scanner());
- if (allow_eval_or_arguments == kDontAllowEvalOrArguments) {
+ if (allow_restricted_identifiers == kDontAllowRestrictedIdentifiers) {
if (is_strict(language_mode()) && this->IsEvalOrArguments(name)) {
ReportMessage("strict_eval_arguments");
*ok = false;
}
+ if (is_strong(language_mode()) && this->IsUndefined(name)) {
+ ReportMessage("strong_undefined");
+ *ok = false;
+ }
} else {
if (is_strong(language_mode()) && this->IsArguments(name)) {
ReportMessage("strong_arguments");
}
}
-
template <class Traits>
typename ParserBase<Traits>::IdentifierT ParserBase<
Traits>::ParseIdentifierOrStrictReservedWord(bool* is_strict_reserved,
case Token::YIELD:
case Token::FUTURE_STRICT_RESERVED_WORD: {
// Using eval or arguments in this context is OK even in strict mode.
- IdentifierT name = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
+ IdentifierT name = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
result = this->ExpressionFromIdentifier(name, beg_pos, end_pos, scope_,
factory());
break;
scope->set_end_position(scanner()->location().end_pos);
// Arrow function *parameter lists* are always checked as in strict mode.
- // TODO(arv): eval_args_error_loc and reserved_loc needs to be set by
- // DeclareArrowParametersFromExpression.
+ // TODO(arv): eval_args_error_loc, undefined_error_loc, and reserved_loc
+ // needs to be set by DeclareArrowParametersFromExpression.
Scanner::Location eval_args_error_loc = Scanner::Location::invalid();
+ Scanner::Location undefined_error_loc = Scanner::Location::invalid();
Scanner::Location reserved_loc = Scanner::Location::invalid();
const bool use_strict_params = true;
this->CheckFunctionParameterNames(language_mode(), use_strict_params,
- eval_args_error_loc, dupe_error_loc, reserved_loc, CHECK_OK);
+ eval_args_error_loc, undefined_error_loc,
+ dupe_error_loc, reserved_loc, CHECK_OK);
// Validate strict mode.
if (is_strict(language_mode())) {
Traits>::CheckAndRewriteReferenceExpression(ExpressionT expression,
Scanner::Location location,
const char* message, bool* ok) {
- if (is_strict(language_mode()) && this->IsIdentifier(expression) &&
- this->IsEvalOrArguments(this->AsIdentifier(expression))) {
- this->ReportMessageAt(location, "strict_eval_arguments", kSyntaxError);
- *ok = false;
- return this->EmptyExpression();
- } else if (expression->IsValidReferenceExpression()) {
+ if (this->IsIdentifier(expression)) {
+ if (is_strict(language_mode()) &&
+ this->IsEvalOrArguments(this->AsIdentifier(expression))) {
+ this->ReportMessageAt(location, "strict_eval_arguments", kSyntaxError);
+ *ok = false;
+ return this->EmptyExpression();
+ }
+ if (is_strong(language_mode()) &&
+ this->IsUndefined(this->AsIdentifier(expression))) {
+ this->ReportMessageAt(location, "strong_undefined", kSyntaxError);
+ *ok = false;
+ return this->EmptyExpression();
+ }
+ }
+ if (expression->IsValidReferenceExpression()) {
return expression;
} else if (expression->IsCall()) {
// If it is a call, make it a runtime error for legacy web compatibility.
}
+TEST(StrongUndefinedLocal) {
+ const char* context_data[][2] = {{"", ""}, {NULL}};
+
+ const char* data[] = {
+ "function undefined() {'use strong';}",
+ "function* undefined() {'use strong';}",
+ "(function undefined() {'use strong';});",
+ "{foo: (function undefined(){'use strong';})};",
+ "(function* undefined() {'use strong';})",
+ "{foo: (function* undefined(){'use strong';})};",
+ "function foo(a, b, undefined, c, d) {'use strong';}",
+ "function* foo(a, b, undefined, c, d) {'use strong';}",
+ "(function foo(a, b, undefined, c, d) {'use strong';})",
+ "{foo: (function foo(a, b, undefined, c, d) {'use strong';})};",
+ "(function* foo(a, b, undefined, c, d) {'use strong';})",
+ "{foo: (function* foo(a, b, undefined, c, d) {'use strong';})};",
+ "class C { foo(a, b, undefined, c, d) {'use strong';} }",
+ "class C { *foo(a, b, undefined, c, d) {'use strong';} }",
+ "({ foo(a, b, undefined, c, d) {'use strong';} });",
+ "{ *foo(a, b, undefined, c, d) {'use strong';} });",
+ "class undefined {'use strong'}",
+ "(class undefined {'use strong'});",
+ NULL};
+
+ static const ParserFlag always_flags[] = {kAllowStrongMode};
+
+ RunParserSyncTest(context_data, data, kError, NULL, 0,
+ always_flags, arraysize(always_flags));
+}
+
+
TEST(ArrowFunctionASIErrors) {
const char* context_data[][2] = {{"'use strict';", ""}, {"", ""},
{NULL, NULL}};
--- /dev/null
+// Copyright 2014 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.
+
+// Flags: --strong-mode --harmony-sloppy --harmony-arrow-functions
+
+// Repurposing the strict mode 'eval' and 'arguments' tests to test for correct
+// behaviour of 'undefined' as an identifier in strong mode.
+"use strict";
+
+function CheckStrongMode(code) {
+ let strictContexts = [
+ ["'use strict';", ""],
+ ["function outer() { 'use strict';", "}"],
+ ["function outer() { 'use strict'; function inner() {", "}}"],
+ ["class C { m() {", "} }"]
+ ]
+ let strongContexts = [
+ ["'use strong';", ""],
+ ["function outer() { 'use strong';", "}"],
+ ["function outer() { 'use strong'; function inner() {", "}}"],
+ ["class C { m() { 'use strong';", "} }"]
+ ]
+
+ for (let context of strictContexts) {
+ assertThrows(context[0] + code + context[1] + "; throw new TypeError();",
+ TypeError);
+ }
+ for (let context of strongContexts) {
+ assertThrows(context[0] + code + context[1], SyntaxError);
+ }
+}
+
+// Binding 'undefined'
+CheckStrongMode("var undefined;");
+CheckStrongMode("let undefined;");
+CheckStrongMode("var undefined = 0;");
+CheckStrongMode("let undefined = 0;");
+CheckStrongMode("const undefined = 0;");
+CheckStrongMode("var x, y = 0, undefined;");
+CheckStrongMode("let x, y = 0, undefined;");
+
+// Function identifier is 'undefined'
+// Function declaration
+CheckStrongMode("function undefined() {}");
+assertThrows("function undefined() {'use strong';}", SyntaxError);
+
+// Generator function
+CheckStrongMode("function* undefined() {}");
+assertThrows("function* undefined() {'use strong';}", SyntaxError);
+
+// Function expression
+CheckStrongMode("(function undefined() {});");
+assertThrows("(function undefined() {'use strong';});", SyntaxError);
+CheckStrongMode("{foo: (function undefined(){})};");
+assertThrows("{foo: (function undefined(){'use strong';})};", SyntaxError);
+
+//Generator function expression
+CheckStrongMode("(function* undefined() {})");
+assertThrows("(function* undefined() {'use strong';})", SyntaxError);
+CheckStrongMode("{foo: (function* undefined(){})};");
+assertThrows("{foo: (function* undefined(){'use strong';})};", SyntaxError);
+
+// Function parameter named 'undefined'
+// Function declaration
+CheckStrongMode("function foo(a, b, undefined, c, d) {}");
+assertThrows("function foo(a, b, undefined, c, d) {'use strong';}",
+ SyntaxError);
+
+// Generator function declaration
+CheckStrongMode("function* foo(a, b, undefined, c, d) {}");
+assertThrows("function* foo(a, b, undefined, c, d) {'use strong';}",
+ SyntaxError);
+
+// Function expression
+CheckStrongMode("(function foo(a, b, undefined, c, d) {});");
+assertThrows("(function foo(a, b, undefined, c, d) {'use strong';})",
+ SyntaxError);
+CheckStrongMode("{foo: (function foo(a, b, undefined, c, d) {})};");
+assertThrows("{foo: (function foo(a, b, undefined, c, d) {'use strong';})};",
+ SyntaxError);
+
+// Generator function expression
+CheckStrongMode("(function* foo(a, b, undefined, c, d) {});");
+assertThrows("(function* foo(a, b, undefined, c, d) {'use strong';})",
+ SyntaxError);
+CheckStrongMode("{foo: (function* foo(a, b, undefined, c, d) {})};");
+assertThrows("{foo: (function* foo(a, b, undefined, c, d) {'use strong';})};",
+ SyntaxError);
+
+// Method parameter named 'undefined'
+// Class method
+CheckStrongMode("class C { foo(a, b, undefined, c, d) {} }");
+assertThrows("class C { foo(a, b, undefined, c, d) {'use strong';} }",
+ SyntaxError);
+
+//Class generator method
+CheckStrongMode("class C { *foo(a, b, undefined, c, d) {} }");
+assertThrows("class C { *foo(a, b, undefined, c, d) {'use strong';} }",
+ SyntaxError);
+
+//Object literal method
+CheckStrongMode("({ foo(a, b, undefined, c, d) {} });");
+assertThrows("({ foo(a, b, undefined, c, d) {'use strong';} });", SyntaxError);
+
+//Object literal generator method
+CheckStrongMode("({ *foo(a, b, undefined, c, d) {} });");
+assertThrows("({ *foo(a, b, undefined, c, d) {'use strong';} });", SyntaxError);
+
+// Arrow function expression with 'undefined' param
+// TODO(conradw): Checking arrow function heads is hard to modify just now
+// CheckStrongMode("(undefined => {})");
+// assertThrows("(undefined => {'use strong';})");
+
+// Class declaration named 'undefined'
+CheckStrongMode("class undefined {}");
+assertThrows("class undefined {'use strong'}", SyntaxError);
+
+// Class expression named 'undefined'
+CheckStrongMode("(class undefined {});");
+assertThrows("(class undefined {'use strong'});", SyntaxError);
+
+// Binding/assigning to 'undefined' in for
+CheckStrongMode("for(undefined = 0;false;);");
+CheckStrongMode("for(var undefined = 0;false;);");
+CheckStrongMode("for(let undefined = 0;false;);");
+CheckStrongMode("for(const undefined = 0;false;);");
+
+// Binding/assigning to 'undefined' in for-in
+CheckStrongMode("for(undefined in {});");
+CheckStrongMode("for(var undefined in {});");
+CheckStrongMode("for(let undefined in {});");
+CheckStrongMode("for(const undefined in {});");
+
+// Binding/assigning to 'undefined' in for-of
+CheckStrongMode("for(undefined of []);");
+CheckStrongMode("for(var undefined of []);");
+CheckStrongMode("for(let undefined of []);");
+CheckStrongMode("for(const undefined of []);");
+
+// Property accessor parameter named 'undefined'.
+CheckStrongMode("let o = { set foo(undefined) {} }");
+assertThrows("let o = { set foo(undefined) {'use strong';} }", SyntaxError);
+
+// catch(undefined)
+CheckStrongMode("try {} catch(undefined) {};");
+
+// Assignment to undefined
+CheckStrongMode("undefined = 0;");
+CheckStrongMode("print(undefined = 0);");
+CheckStrongMode("let x = undefined = 0;");
+
+// Compound assignment to undefined
+CheckStrongMode("undefined *= 0;");
+CheckStrongMode("undefined /= 0;");
+CheckStrongMode("print(undefined %= 0);");
+CheckStrongMode("let x = undefined += 0;");
+CheckStrongMode("let x = undefined -= 0;");
+CheckStrongMode("undefined <<= 0;");
+CheckStrongMode("undefined >>= 0;");
+CheckStrongMode("print(undefined >>>= 0);");
+CheckStrongMode("print(undefined &= 0);");
+CheckStrongMode("let x = undefined ^= 0;");
+CheckStrongMode("let x = undefined |= 0;");
+
+// Postfix increment with undefined
+CheckStrongMode("undefined++;");
+CheckStrongMode("print(undefined++);");
+CheckStrongMode("let x = undefined++;");
+
+// Postfix decrement with undefined
+CheckStrongMode("undefined--;");
+CheckStrongMode("print(undefined--);");
+CheckStrongMode("let x = undefined--;");
+
+// Prefix increment with undefined
+CheckStrongMode("++undefined;");
+CheckStrongMode("print(++undefined);");
+CheckStrongMode("let x = ++undefined;");
+
+// Prefix decrement with undefined
+CheckStrongMode("--undefined;");
+CheckStrongMode("print(--undefined);");
+CheckStrongMode("let x = --undefined;");
+
+// Function constructor: 'undefined' parameter name
+assertDoesNotThrow(function() {
+ Function("undefined", "");
+});
+assertThrows(function() {
+ Function("undefined", "'use strong';");
+}, SyntaxError);