Commit 64abe652 authored by arv's avatar arv Committed by Commit bot

Allow eval and arguments as property names

We incorrectly disallowed eval and arguments in accessor and method
names. This was because we checked the name inside the
ParseFunctionLiteral. We now flag accessors so that lazy parsing of
these functions are treated correctly.

BUG=v8:1984
R=adamk, dslomov@chromium.org
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#26497}
parent 70079dab
...@@ -3676,9 +3676,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral( ...@@ -3676,9 +3676,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
// We don't yet know if the function will be strict, so we cannot yet // We don't yet know if the function will be strict, so we cannot yet
// produce errors for parameter names or duplicates. However, we remember // produce errors for parameter names or duplicates. However, we remember
// the locations of these errors if they occur and produce the errors later. // the locations of these errors if they occur and produce the errors later.
Scanner::Location eval_args_error_log = Scanner::Location::invalid(); Scanner::Location eval_args_error_loc = Scanner::Location::invalid();
Scanner::Location dupe_error_loc = Scanner::Location::invalid(); Scanner::Location dupe_error_loc = Scanner::Location::invalid();
Scanner::Location reserved_loc = Scanner::Location::invalid(); Scanner::Location reserved_error_loc = Scanner::Location::invalid();
bool is_rest = false; bool is_rest = false;
bool done = arity_restriction == FunctionLiteral::GETTER_ARITY || bool done = arity_restriction == FunctionLiteral::GETTER_ARITY ||
...@@ -3695,11 +3695,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral( ...@@ -3695,11 +3695,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK); ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
// Store locations for possible future error reports. // Store locations for possible future error reports.
if (!eval_args_error_log.IsValid() && IsEvalOrArguments(param_name)) { if (!eval_args_error_loc.IsValid() && IsEvalOrArguments(param_name)) {
eval_args_error_log = scanner()->location(); eval_args_error_loc = scanner()->location();
} }
if (!reserved_loc.IsValid() && is_strict_reserved) { if (!reserved_error_loc.IsValid() && is_strict_reserved) {
reserved_loc = scanner()->location(); reserved_error_loc = scanner()->location();
} }
if (!dupe_error_loc.IsValid() && scope_->IsDeclared(param_name)) { if (!dupe_error_loc.IsValid() && scope_->IsDeclared(param_name)) {
duplicate_parameters = FunctionLiteral::kHasDuplicateParameters; duplicate_parameters = FunctionLiteral::kHasDuplicateParameters;
...@@ -3810,19 +3810,16 @@ FunctionLiteral* Parser::ParseFunctionLiteral( ...@@ -3810,19 +3810,16 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
handler_count = function_state.handler_count(); handler_count = function_state.handler_count();
} }
// Validate strict mode. // Validate name and parameter names. We can do this only after parsing the
// Concise methods use StrictFormalParameters. // function, since the function can declare itself strict.
// Functions for which IsSimpleParameterList() returns false use CheckFunctionName(language_mode(), kind, function_name,
// StrictFormalParameters. name_is_strict_reserved, function_name_location,
if (is_strict(language_mode()) || IsConciseMethod(kind) || is_rest) { CHECK_OK);
CheckStrictFunctionNameAndParameters(function_name, const bool use_strict_params = is_rest || IsConciseMethod(kind);
name_is_strict_reserved, CheckFunctionParameterNames(language_mode(), use_strict_params,
function_name_location, eval_args_error_loc, dupe_error_loc,
eval_args_error_log, reserved_error_loc, CHECK_OK);
dupe_error_loc,
reserved_loc,
CHECK_OK);
}
if (is_strict(language_mode())) { if (is_strict(language_mode())) {
CheckStrictOctalLiteral(scope->start_position(), scope->end_position(), CheckStrictOctalLiteral(scope->start_position(), scope->end_position(),
CHECK_OK); CHECK_OK);
......
...@@ -936,36 +936,16 @@ PreParser::Expression PreParser::ParseFunctionLiteral( ...@@ -936,36 +936,16 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
} }
Expect(Token::RBRACE, CHECK_OK); Expect(Token::RBRACE, CHECK_OK);
// Validate strict mode. We can do this only after parsing the function, // Validate name and parameter names. We can do this only after parsing the
// since the function can declare itself strict. // function, since the function can declare itself strict.
// Concise methods use StrictFormalParameters. CheckFunctionName(language_mode(), kind, function_name,
if (is_strict(language_mode()) || IsConciseMethod(kind) || is_rest) { name_is_strict_reserved, function_name_location, CHECK_OK);
if (function_name.IsEvalOrArguments()) { const bool use_strict_params = is_rest || IsConciseMethod(kind);
ReportMessageAt(function_name_location, "strict_eval_arguments"); CheckFunctionParameterNames(language_mode(), use_strict_params,
*ok = false; eval_args_error_loc, dupe_error_loc,
return Expression::Default(); reserved_error_loc, CHECK_OK);
}
if (name_is_strict_reserved) {
ReportMessageAt(function_name_location, "unexpected_strict_reserved");
*ok = false;
return Expression::Default();
}
if (eval_args_error_loc.IsValid()) {
ReportMessageAt(eval_args_error_loc, "strict_eval_arguments");
*ok = false;
return Expression::Default();
}
if (dupe_error_loc.IsValid()) {
ReportMessageAt(dupe_error_loc, "strict_param_dupe");
*ok = false;
return Expression::Default();
}
if (reserved_error_loc.IsValid()) {
ReportMessageAt(reserved_error_loc, "unexpected_strict_reserved");
*ok = false;
return Expression::Default();
}
if (is_strict(language_mode())) {
int end_position = scanner()->location().end_pos; int end_position = scanner()->location().end_pos;
CheckStrictOctalLiteral(start_position, end_position, CHECK_OK); CheckStrictOctalLiteral(start_position, end_position, CHECK_OK);
} }
......
...@@ -426,17 +426,18 @@ class ParserBase : public Traits { ...@@ -426,17 +426,18 @@ class ParserBase : public Traits {
CheckOctalLiteral(beg_pos, end_pos, "template_octal_literal", ok); CheckOctalLiteral(beg_pos, end_pos, "template_octal_literal", ok);
} }
// Validates strict mode for function parameter lists. This has to be // Checking the name of a function literal. This has to be done after parsing
// done after parsing the function, since the function can declare // the function, since the function can declare itself strict.
// itself strict. void CheckFunctionName(LanguageMode language_mode, FunctionKind kind,
void CheckStrictFunctionNameAndParameters( IdentifierT function_name,
IdentifierT function_name, bool function_name_is_strict_reserved,
bool function_name_is_strict_reserved, const Scanner::Location& function_name_loc,
const Scanner::Location& function_name_loc, bool* ok) {
const Scanner::Location& eval_args_error_loc, // Property names are never checked.
const Scanner::Location& dupe_error_loc, if (IsConciseMethod(kind) || IsAccessorFunction(kind)) return;
const Scanner::Location& reserved_loc, // The function name needs to be checked in strict mode.
bool* ok) { if (is_sloppy(language_mode)) return;
if (this->IsEvalOrArguments(function_name)) { if (this->IsEvalOrArguments(function_name)) {
Traits::ReportMessageAt(function_name_loc, "strict_eval_arguments"); Traits::ReportMessageAt(function_name_loc, "strict_eval_arguments");
*ok = false; *ok = false;
...@@ -447,11 +448,25 @@ class ParserBase : public Traits { ...@@ -447,11 +448,25 @@ class ParserBase : public Traits {
*ok = false; *ok = false;
return; return;
} }
}
// Checking the parameter names of a function literal. This has to be done
// after parsing the function, since the function can declare itself strict.
void CheckFunctionParameterNames(LanguageMode language_mode,
bool strict_params,
const Scanner::Location& eval_args_error_loc,
const Scanner::Location& dupe_error_loc,
const Scanner::Location& reserved_loc,
bool* ok) {
if (is_sloppy(language_mode) && !strict_params) return;
if (eval_args_error_loc.IsValid()) { if (eval_args_error_loc.IsValid()) {
Traits::ReportMessageAt(eval_args_error_loc, "strict_eval_arguments"); Traits::ReportMessageAt(eval_args_error_loc, "strict_eval_arguments");
*ok = false; *ok = false;
return; return;
} }
// TODO(arv): When we add support for destructuring in setters we also need
// to check for duplicate names.
if (dupe_error_loc.IsValid()) { if (dupe_error_loc.IsValid()) {
Traits::ReportMessageAt(dupe_error_loc, "strict_param_dupe"); Traits::ReportMessageAt(dupe_error_loc, "strict_param_dupe");
*ok = false; *ok = false;
...@@ -2838,6 +2853,7 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(int start_pos, ...@@ -2838,6 +2853,7 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(int start_pos,
Traits::Type::ptr_to_scope(scope), Traits::Type::ptr_to_scope(scope),
kArrowFunction, &function_factory); kArrowFunction, &function_factory);
Scanner::Location dupe_error_loc = Scanner::Location::invalid(); Scanner::Location dupe_error_loc = Scanner::Location::invalid();
// TODO(arv): Pass in eval_args_error_loc and reserved_loc here.
num_parameters = Traits::DeclareArrowParametersFromExpression( num_parameters = Traits::DeclareArrowParametersFromExpression(
params_ast, scope_, &dupe_error_loc, ok); params_ast, scope_, &dupe_error_loc, ok);
if (!*ok) { if (!*ok) {
...@@ -2891,14 +2907,13 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(int start_pos, ...@@ -2891,14 +2907,13 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(int start_pos,
scope->set_end_position(scanner()->location().end_pos); scope->set_end_position(scanner()->location().end_pos);
// Arrow function *parameter lists* are always checked as in strict mode. // Arrow function *parameter lists* are always checked as in strict mode.
bool function_name_is_strict_reserved = false; // TODO(arv): eval_args_error_loc and reserved_loc needs to be set by
Scanner::Location function_name_loc = Scanner::Location::invalid(); // DeclareArrowParametersFromExpression.
Scanner::Location eval_args_error_loc = Scanner::Location::invalid(); Scanner::Location eval_args_error_loc = Scanner::Location::invalid();
Scanner::Location reserved_loc = Scanner::Location::invalid(); Scanner::Location reserved_loc = Scanner::Location::invalid();
this->CheckStrictFunctionNameAndParameters( const bool use_strict_params = true;
this->EmptyIdentifier(), function_name_is_strict_reserved, this->CheckFunctionParameterNames(language_mode(), use_strict_params,
function_name_loc, eval_args_error_loc, dupe_error_loc, reserved_loc, eval_args_error_loc, dupe_error_loc, reserved_loc, CHECK_OK);
CHECK_OK);
// Validate strict mode. // Validate strict mode.
if (is_strict(language_mode())) { if (is_strict(language_mode())) {
......
...@@ -5104,3 +5104,48 @@ TEST(LanguageModeDirectives) { ...@@ -5104,3 +5104,48 @@ TEST(LanguageModeDirectives) {
TestLanguageMode("\"use some future directive\"; \"use strict\";", i::STRICT); TestLanguageMode("\"use some future directive\"; \"use strict\";", i::STRICT);
TestLanguageMode("\"use some future directive\"; \"use strong\";", i::STRONG); TestLanguageMode("\"use some future directive\"; \"use strong\";", i::STRONG);
} }
TEST(PropertyNameEvalArguments) {
const char* context_data[][2] = {{"'use strict';", ""},
{"'use strong';", ""},
{NULL, NULL}};
const char* statement_data[] = {
"({eval: 1})",
"({arguments: 1})",
"({eval() {}})",
"({arguments() {}})",
"({*eval() {}})",
"({*arguments() {}})",
"({get eval() {}})",
"({get arguments() {}})",
"({set eval(_) {}})",
"({set arguments(_) {}})",
"class C {eval() {}}",
"class C {arguments() {}}",
"class C {*eval() {}}",
"class C {*arguments() {}}",
"class C {get eval() {}}",
"class C {get arguments() {}}",
"class C {set eval(_) {}}",
"class C {set arguments(_) {}}",
"class C {static eval() {}}",
"class C {static arguments() {}}",
"class C {static *eval() {}}",
"class C {static *arguments() {}}",
"class C {static get eval() {}}",
"class C {static get arguments() {}}",
"class C {static set eval(_) {}}",
"class C {static set arguments(_) {}}",
NULL};
static const ParserFlag always_flags[] = {
kAllowHarmonyClasses, kAllowHarmonyObjectLiterals, kAllowHarmonyScoping,
kAllowStrongMode};
RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
always_flags, arraysize(always_flags));
}
// Copyright 2015 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: --harmony-classes --harmony-sloppy
(function Method() {
class C {
eval() {
return 1;
}
arguments() {
return 2;
}
static eval() {
return 3;
}
static arguments() {
return 4;
}
};
assertEquals(1, new C().eval());
assertEquals(2, new C().arguments());
assertEquals(3, C.eval());
assertEquals(4, C.arguments());
})();
(function Getters() {
class C {
get eval() {
return 1;
}
get arguments() {
return 2;
}
static get eval() {
return 3;
}
static get arguments() {
return 4;
}
};
assertEquals(1, new C().eval);
assertEquals(2, new C().arguments);
assertEquals(3, C.eval);
assertEquals(4, C.arguments);
})();
(function Setters() {
var x = 0;
class C {
set eval(v) {
x = v;
}
set arguments(v) {
x = v;
}
static set eval(v) {
x = v;
}
static set arguments(v) {
x = v;
}
};
new C().eval = 1;
assertEquals(1, x);
new C().arguments = 2;
assertEquals(2, x);
C.eval = 3;
assertEquals(3, x);
C.arguments = 4;
assertEquals(4, x);
})();
// Copyright 2015 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: --harmony-object-literals
(function TestSloppyMode() {
var o = {
eval() {
return 1;
},
arguments() {
return 2;
},
};
assertEquals(1, o.eval());
assertEquals(2, o.arguments());
})();
(function TestStrictMode() {
'use strict';
var o = {
eval() {
return 1;
},
arguments() {
return 2;
},
};
assertEquals(1, o.eval());
assertEquals(2, o.arguments());
})();
// Copyright 2015 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.
(function TestSloppyMode() {
var e = 1, a = 2;
var o = {
get eval() {
return e;
},
set eval(v) {
e = v;
},
get arguments() {
return a;
},
set arguments(v) {
a = v;
},
};
assertEquals(1, o.eval);
o.eval = 3;
assertEquals(3, e);
assertEquals(2, o.arguments);
o.arguments = 4;
assertEquals(4, a);
})();
(function TestStrictMode() {
'use strict';
var e = 1, a = 2;
var o = {
get eval() {
return e;
},
set eval(v) {
e = v;
},
get arguments() {
return a;
},
set arguments(v) {
a = v;
},
};
assertEquals(1, o.eval);
o.eval = 3;
assertEquals(3, e);
assertEquals(2, o.arguments);
o.arguments = 4;
assertEquals(4, a);
})();
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