Commit c3c185c1 authored by rossberg@chromium.org's avatar rossberg@chromium.org

Make invalid LHSs a parse-time (reference) error

This is required by the spec. It also prevents crashes resulting from the attempt to read type feedback for the RHS of an invalid assignment which full codegen never actually allocated info for.

To do: check properly in preparser already.

R=marja@chromium.org, mstarzinger@chromium.org
BUG=351658
LOG=Y

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19976 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent dbb7f982
...@@ -1854,13 +1854,9 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { ...@@ -1854,13 +1854,9 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
void FullCodeGenerator::VisitAssignment(Assignment* expr) { void FullCodeGenerator::VisitAssignment(Assignment* expr) {
ASSERT(expr->target()->IsValidLeftHandSide());
Comment cmnt(masm_, "[ Assignment"); Comment cmnt(masm_, "[ Assignment");
// Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
// on the left-hand side.
if (!expr->target()->IsValidLeftHandSide()) {
VisitForEffect(expr->target());
return;
}
// Left-hand side can only be a property, a global or a (parameter or local) // Left-hand side can only be a property, a global or a (parameter or local)
// slot. // slot.
...@@ -2099,12 +2095,7 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, ...@@ -2099,12 +2095,7 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
void FullCodeGenerator::EmitAssignment(Expression* expr) { void FullCodeGenerator::EmitAssignment(Expression* expr) {
// Invalid left-hand sides are rewritten to have a 'throw ASSERT(expr->IsValidLeftHandSide());
// ReferenceError' on the left-hand side.
if (!expr->IsValidLeftHandSide()) {
VisitForEffect(expr);
return;
}
// Left-hand side can only be a property, a global or a (parameter or local) // Left-hand side can only be a property, a global or a (parameter or local)
// slot. // slot.
...@@ -3990,16 +3981,11 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { ...@@ -3990,16 +3981,11 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
ASSERT(expr->expression()->IsValidLeftHandSide());
Comment cmnt(masm_, "[ CountOperation"); Comment cmnt(masm_, "[ CountOperation");
SetSourcePosition(expr->position()); SetSourcePosition(expr->position());
// Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
// as the left-hand side.
if (!expr->expression()->IsValidLeftHandSide()) {
VisitForEffect(expr->expression());
return;
}
// Expression can only be a property, a global or a (parameter or local) // Expression can only be a property, a global or a (parameter or local)
// slot. // slot.
enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
......
...@@ -1865,13 +1865,9 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { ...@@ -1865,13 +1865,9 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
void FullCodeGenerator::VisitAssignment(Assignment* expr) { void FullCodeGenerator::VisitAssignment(Assignment* expr) {
ASSERT(expr->target()->IsValidLeftHandSide());
Comment cmnt(masm_, "[ Assignment"); Comment cmnt(masm_, "[ Assignment");
// Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
// on the left-hand side.
if (!expr->target()->IsValidLeftHandSide()) {
VisitForEffect(expr->target());
return;
}
// Left-hand side can only be a property, a global or a (parameter or local) // Left-hand side can only be a property, a global or a (parameter or local)
// slot. // slot.
...@@ -2402,12 +2398,7 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, ...@@ -2402,12 +2398,7 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
void FullCodeGenerator::EmitAssignment(Expression* expr) { void FullCodeGenerator::EmitAssignment(Expression* expr) {
// Invalid left-hand sides are rewritten by the parser to have a 'throw ASSERT(expr->IsValidLeftHandSide());
// ReferenceError' on the left-hand side.
if (!expr->IsValidLeftHandSide()) {
VisitForEffect(expr);
return;
}
// Left-hand side can only be a property, a global or a (parameter or local) // Left-hand side can only be a property, a global or a (parameter or local)
// slot. // slot.
...@@ -4282,16 +4273,11 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { ...@@ -4282,16 +4273,11 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
ASSERT(expr->expression()->IsValidLeftHandSide());
Comment cmnt(masm_, "[ CountOperation"); Comment cmnt(masm_, "[ CountOperation");
SetSourcePosition(expr->position()); SetSourcePosition(expr->position());
// Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
// as the left-hand side.
if (!expr->expression()->IsValidLeftHandSide()) {
VisitForEffect(expr->expression());
return;
}
// Expression can only be a property, a global or a (parameter or local) // Expression can only be a property, a global or a (parameter or local)
// slot. // slot.
enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
......
...@@ -1067,6 +1067,12 @@ Handle<Object> Factory::NewReferenceError(const char* message, ...@@ -1067,6 +1067,12 @@ Handle<Object> Factory::NewReferenceError(const char* message,
} }
Handle<Object> Factory::NewReferenceError(const char* message,
Handle<JSArray> args) {
return NewError("MakeReferenceError", message, args);
}
Handle<Object> Factory::NewReferenceError(Handle<String> message) { Handle<Object> Factory::NewReferenceError(Handle<String> message) {
return NewError("$ReferenceError", message); return NewError("$ReferenceError", message);
} }
......
...@@ -436,6 +436,7 @@ class Factory { ...@@ -436,6 +436,7 @@ class Factory {
Handle<Object> NewReferenceError(const char* message, Handle<Object> NewReferenceError(const char* message,
Vector< Handle<Object> > args); Vector< Handle<Object> > args);
Handle<Object> NewReferenceError(const char* message, Handle<JSArray> args);
Handle<Object> NewReferenceError(Handle<String> message); Handle<Object> NewReferenceError(Handle<String> message);
Handle<Object> NewEvalError(const char* message, Handle<Object> NewEvalError(const char* message,
......
...@@ -333,10 +333,6 @@ namespace internal { ...@@ -333,10 +333,6 @@ namespace internal {
V(MakeReferenceError_string, "MakeReferenceError") \ V(MakeReferenceError_string, "MakeReferenceError") \
V(MakeSyntaxError_string, "MakeSyntaxError") \ V(MakeSyntaxError_string, "MakeSyntaxError") \
V(MakeTypeError_string, "MakeTypeError") \ V(MakeTypeError_string, "MakeTypeError") \
V(invalid_lhs_in_assignment_string, "invalid_lhs_in_assignment") \
V(invalid_lhs_in_for_in_string, "invalid_lhs_in_for_in") \
V(invalid_lhs_in_postfix_op_string, "invalid_lhs_in_postfix_op") \
V(invalid_lhs_in_prefix_op_string, "invalid_lhs_in_prefix_op") \
V(illegal_return_string, "illegal_return") \ V(illegal_return_string, "illegal_return") \
V(illegal_break_string, "illegal_break") \ V(illegal_break_string, "illegal_break") \
V(illegal_continue_string, "illegal_continue") \ V(illegal_continue_string, "illegal_continue") \
......
...@@ -1818,13 +1818,9 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { ...@@ -1818,13 +1818,9 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
void FullCodeGenerator::VisitAssignment(Assignment* expr) { void FullCodeGenerator::VisitAssignment(Assignment* expr) {
ASSERT(expr->target()->IsValidLeftHandSide());
Comment cmnt(masm_, "[ Assignment"); Comment cmnt(masm_, "[ Assignment");
// Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
// on the left-hand side.
if (!expr->target()->IsValidLeftHandSide()) {
VisitForEffect(expr->target());
return;
}
// Left-hand side can only be a property, a global or a (parameter or local) // Left-hand side can only be a property, a global or a (parameter or local)
// slot. // slot.
...@@ -2353,12 +2349,7 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, ...@@ -2353,12 +2349,7 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
void FullCodeGenerator::EmitAssignment(Expression* expr) { void FullCodeGenerator::EmitAssignment(Expression* expr) {
// Invalid left-hand sides are rewritten by the parser to have a 'throw ASSERT(expr->IsValidLeftHandSide());
// ReferenceError' on the left-hand side.
if (!expr->IsValidLeftHandSide()) {
VisitForEffect(expr);
return;
}
// Left-hand side can only be a property, a global or a (parameter or local) // Left-hand side can only be a property, a global or a (parameter or local)
// slot. // slot.
...@@ -4284,16 +4275,11 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { ...@@ -4284,16 +4275,11 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
ASSERT(expr->expression()->IsValidLeftHandSide());
Comment cmnt(masm_, "[ CountOperation"); Comment cmnt(masm_, "[ CountOperation");
SetSourcePosition(expr->position()); SetSourcePosition(expr->position());
// Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
// as the left-hand side.
if (!expr->expression()->IsValidLeftHandSide()) {
VisitForEffect(expr->expression());
return;
}
// Expression can only be a property, a global or a (parameter or local) // Expression can only be a property, a global or a (parameter or local)
// slot. // slot.
enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
......
...@@ -45,10 +45,6 @@ var kMessages = { ...@@ -45,10 +45,6 @@ var kMessages = {
unterminated_regexp: ["Invalid regular expression: missing /"], unterminated_regexp: ["Invalid regular expression: missing /"],
regexp_flags: ["Cannot supply flags when constructing one RegExp from another"], regexp_flags: ["Cannot supply flags when constructing one RegExp from another"],
incompatible_method_receiver: ["Method ", "%0", " called on incompatible receiver ", "%1"], incompatible_method_receiver: ["Method ", "%0", " called on incompatible receiver ", "%1"],
invalid_lhs_in_assignment: ["Invalid left-hand side in assignment"],
invalid_lhs_in_for_in: ["Invalid left-hand side in for-in"],
invalid_lhs_in_postfix_op: ["Invalid left-hand side expression in postfix operation"],
invalid_lhs_in_prefix_op: ["Invalid left-hand side expression in prefix operation"],
multiple_defaults_in_switch: ["More than one default clause in switch statement"], multiple_defaults_in_switch: ["More than one default clause in switch statement"],
newline_after_throw: ["Illegal newline after throw"], newline_after_throw: ["Illegal newline after throw"],
redeclaration: ["%0", " '", "%1", "' has already been declared"], redeclaration: ["%0", " '", "%1", "' has already been declared"],
...@@ -132,6 +128,11 @@ var kMessages = { ...@@ -132,6 +128,11 @@ var kMessages = {
stack_overflow: ["Maximum call stack size exceeded"], stack_overflow: ["Maximum call stack size exceeded"],
invalid_time_value: ["Invalid time value"], invalid_time_value: ["Invalid time value"],
invalid_count_value: ["Invalid count value"], invalid_count_value: ["Invalid count value"],
// ReferenceError
invalid_lhs_in_assignment: ["Invalid left-hand side in assignment"],
invalid_lhs_in_for: ["Invalid left-hand side in for-loop"],
invalid_lhs_in_postfix_op: ["Invalid left-hand side expression in postfix operation"],
invalid_lhs_in_prefix_op: ["Invalid left-hand side expression in prefix operation"],
// SyntaxError // SyntaxError
paren_in_arg_string: ["Function arg string contains parenthesis"], paren_in_arg_string: ["Function arg string contains parenthesis"],
not_isvar: ["builtin %IS_VAR: not a variable"], not_isvar: ["builtin %IS_VAR: not a variable"],
......
...@@ -456,18 +456,6 @@ void ParserTraits::CheckAssigningFunctionLiteralToProperty(Expression* left, ...@@ -456,18 +456,6 @@ void ParserTraits::CheckAssigningFunctionLiteralToProperty(Expression* left,
} }
Expression* ParserTraits::ValidateAssignmentLeftHandSide(
Expression* expression) const {
ASSERT(expression != NULL);
if (!expression->IsValidLeftHandSide()) {
Handle<String> message =
parser_->isolate()->factory()->invalid_lhs_in_assignment_string();
expression = parser_->NewThrowReferenceError(message);
}
return expression;
}
Expression* ParserTraits::MarkExpressionAsLValue(Expression* expression) { Expression* ParserTraits::MarkExpressionAsLValue(Expression* expression) {
VariableProxy* proxy = expression != NULL VariableProxy* proxy = expression != NULL
? expression->AsVariableProxy() ? expression->AsVariableProxy()
...@@ -492,7 +480,8 @@ void ParserTraits::CheckStrictModeLValue(Expression* expression, ...@@ -492,7 +480,8 @@ void ParserTraits::CheckStrictModeLValue(Expression* expression,
void ParserTraits::ReportMessageAt(Scanner::Location source_location, void ParserTraits::ReportMessageAt(Scanner::Location source_location,
const char* message, const char* message,
Vector<const char*> args) { Vector<const char*> args,
bool is_reference_error) {
if (parser_->stack_overflow()) { if (parser_->stack_overflow()) {
// Suppress the error message (syntax error or such) in the presence of a // Suppress the error message (syntax error or such) in the presence of a
// stack overflow. The isolate allows only one pending exception at at time // stack overflow. The isolate allows only one pending exception at at time
...@@ -509,21 +498,25 @@ void ParserTraits::ReportMessageAt(Scanner::Location source_location, ...@@ -509,21 +498,25 @@ void ParserTraits::ReportMessageAt(Scanner::Location source_location,
elements->set(i, *arg_string); elements->set(i, *arg_string);
} }
Handle<JSArray> array = factory->NewJSArrayWithElements(elements); Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
Handle<Object> result = factory->NewSyntaxError(message, array); Handle<Object> result = is_reference_error
? factory->NewReferenceError(message, array)
: factory->NewSyntaxError(message, array);
parser_->isolate()->Throw(*result, &location); parser_->isolate()->Throw(*result, &location);
} }
void ParserTraits::ReportMessage(const char* message, void ParserTraits::ReportMessage(const char* message,
Vector<Handle<String> > args) { Vector<Handle<String> > args,
bool is_reference_error) {
Scanner::Location source_location = parser_->scanner()->location(); Scanner::Location source_location = parser_->scanner()->location();
ReportMessageAt(source_location, message, args); ReportMessageAt(source_location, message, args, is_reference_error);
} }
void ParserTraits::ReportMessageAt(Scanner::Location source_location, void ParserTraits::ReportMessageAt(Scanner::Location source_location,
const char* message, const char* message,
Vector<Handle<String> > args) { Vector<Handle<String> > args,
bool is_reference_error) {
if (parser_->stack_overflow()) { if (parser_->stack_overflow()) {
// Suppress the error message (syntax error or such) in the presence of a // Suppress the error message (syntax error or such) in the presence of a
// stack overflow. The isolate allows only one pending exception at at time // stack overflow. The isolate allows only one pending exception at at time
...@@ -539,7 +532,9 @@ void ParserTraits::ReportMessageAt(Scanner::Location source_location, ...@@ -539,7 +532,9 @@ void ParserTraits::ReportMessageAt(Scanner::Location source_location,
elements->set(i, *args[i]); elements->set(i, *args[i]);
} }
Handle<JSArray> array = factory->NewJSArrayWithElements(elements); Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
Handle<Object> result = factory->NewSyntaxError(message, array); Handle<Object> result = is_reference_error
? factory->NewReferenceError(message, array)
: factory->NewSyntaxError(message, array);
parser_->isolate()->Throw(*result, &location); parser_->isolate()->Throw(*result, &location);
} }
...@@ -2844,19 +2839,16 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { ...@@ -2844,19 +2839,16 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
init = variable_statement; init = variable_statement;
} }
} else { } else {
Scanner::Location lhs_location = scanner()->peek_location();
Expression* expression = ParseExpression(false, CHECK_OK); Expression* expression = ParseExpression(false, CHECK_OK);
ForEachStatement::VisitMode mode; ForEachStatement::VisitMode mode;
bool accept_OF = expression->AsVariableProxy(); bool accept_OF = expression->AsVariableProxy();
if (CheckInOrOf(accept_OF, &mode)) { if (CheckInOrOf(accept_OF, &mode)) {
// Signal a reference error if the expression is an invalid
// left-hand side expression. We could report this as a syntax
// error here but for compatibility with JSC we choose to report
// the error at runtime.
if (expression == NULL || !expression->IsValidLeftHandSide()) { if (expression == NULL || !expression->IsValidLeftHandSide()) {
Handle<String> message = ReportMessageAt(lhs_location, "invalid_lhs_in_for", true);
isolate()->factory()->invalid_lhs_in_for_in_string(); *ok = false;
expression = NewThrowReferenceError(message); return NULL;
} }
ForEachStatement* loop = ForEachStatement* loop =
factory()->NewForEachStatement(mode, labels, pos); factory()->NewForEachStatement(mode, labels, pos);
...@@ -3125,15 +3117,12 @@ Expression* Parser::ParseUnaryExpression(bool* ok) { ...@@ -3125,15 +3117,12 @@ Expression* Parser::ParseUnaryExpression(bool* ok) {
} else if (Token::IsCountOp(op)) { } else if (Token::IsCountOp(op)) {
op = Next(); op = Next();
Scanner::Location lhs_location = scanner()->peek_location();
Expression* expression = ParseUnaryExpression(CHECK_OK); Expression* expression = ParseUnaryExpression(CHECK_OK);
// Signal a reference error if the expression is an invalid
// left-hand side expression. We could report this as a syntax
// error here but for compatibility with JSC we choose to report the
// error at runtime.
if (expression == NULL || !expression->IsValidLeftHandSide()) { if (expression == NULL || !expression->IsValidLeftHandSide()) {
Handle<String> message = ReportMessageAt(lhs_location, "invalid_lhs_in_prefix_op", true);
isolate()->factory()->invalid_lhs_in_prefix_op_string(); *ok = false;
expression = NewThrowReferenceError(message); return NULL;
} }
if (strict_mode() == STRICT) { if (strict_mode() == STRICT) {
...@@ -3157,17 +3146,14 @@ Expression* Parser::ParsePostfixExpression(bool* ok) { ...@@ -3157,17 +3146,14 @@ Expression* Parser::ParsePostfixExpression(bool* ok) {
// PostfixExpression :: // PostfixExpression ::
// LeftHandSideExpression ('++' | '--')? // LeftHandSideExpression ('++' | '--')?
Scanner::Location lhs_location = scanner()->peek_location();
Expression* expression = ParseLeftHandSideExpression(CHECK_OK); Expression* expression = ParseLeftHandSideExpression(CHECK_OK);
if (!scanner()->HasAnyLineTerminatorBeforeNext() && if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
Token::IsCountOp(peek())) { Token::IsCountOp(peek())) {
// Signal a reference error if the expression is an invalid
// left-hand side expression. We could report this as a syntax
// error here but for compatibility with JSC we choose to report the
// error at runtime.
if (expression == NULL || !expression->IsValidLeftHandSide()) { if (expression == NULL || !expression->IsValidLeftHandSide()) {
Handle<String> message = ReportMessageAt(lhs_location, "invalid_lhs_in_postfix_op", true);
isolate()->factory()->invalid_lhs_in_postfix_op_string(); *ok = false;
expression = NewThrowReferenceError(message); return NULL;
} }
if (strict_mode() == STRICT) { if (strict_mode() == STRICT) {
......
...@@ -484,10 +484,10 @@ class ParserTraits { ...@@ -484,10 +484,10 @@ class ParserTraits {
static void CheckAssigningFunctionLiteralToProperty(Expression* left, static void CheckAssigningFunctionLiteralToProperty(Expression* left,
Expression* right); Expression* right);
// Signal a reference error if the expression is an invalid left-hand side // Determine whether the expression is a valid assignment left-hand side.
// expression. We could report this as a syntax error but for compatibility static bool IsValidLeftHandSide(Expression* expression) {
// with JSC we choose to report the error at runtime. return expression->IsValidLeftHandSide();
Expression* ValidateAssignmentLeftHandSide(Expression* expression) const; }
// Determine if the expression is a variable proxy and mark it as being used // Determine if the expression is a variable proxy and mark it as being used
// in an assignment or with a increment/decrement operator. This is currently // in an assignment or with a increment/decrement operator. This is currently
...@@ -501,11 +501,15 @@ class ParserTraits { ...@@ -501,11 +501,15 @@ class ParserTraits {
// Reporting errors. // Reporting errors.
void ReportMessageAt(Scanner::Location source_location, void ReportMessageAt(Scanner::Location source_location,
const char* message, const char* message,
Vector<const char*> args); Vector<const char*> args,
void ReportMessage(const char* message, Vector<Handle<String> > args); bool is_reference_error = false);
void ReportMessage(const char* message,
Vector<Handle<String> > args,
bool is_reference_error = false);
void ReportMessageAt(Scanner::Location source_location, void ReportMessageAt(Scanner::Location source_location,
const char* message, const char* message,
Vector<Handle<String> > args); Vector<Handle<String> > args,
bool is_reference_error = false);
// "null" return type creators. // "null" return type creators.
static Handle<String> EmptyIdentifier() { static Handle<String> EmptyIdentifier() {
......
...@@ -69,17 +69,20 @@ void PreParserTraits::CheckStrictModeLValue(PreParserExpression expression, ...@@ -69,17 +69,20 @@ void PreParserTraits::CheckStrictModeLValue(PreParserExpression expression,
void PreParserTraits::ReportMessageAt(Scanner::Location location, void PreParserTraits::ReportMessageAt(Scanner::Location location,
const char* message, const char* message,
Vector<const char*> args) { Vector<const char*> args,
bool is_reference_error) {
ReportMessageAt(location.beg_pos, ReportMessageAt(location.beg_pos,
location.end_pos, location.end_pos,
message, message,
args.length() > 0 ? args[0] : NULL); args.length() > 0 ? args[0] : NULL,
is_reference_error);
} }
void PreParserTraits::ReportMessageAt(Scanner::Location location, void PreParserTraits::ReportMessageAt(Scanner::Location location,
const char* type, const char* type,
const char* name_opt) { const char* name_opt,
bool is_reference_error) {
pre_parser_->log_ pre_parser_->log_
->LogMessage(location.beg_pos, location.end_pos, type, name_opt); ->LogMessage(location.beg_pos, location.end_pos, type, name_opt);
} }
...@@ -88,7 +91,8 @@ void PreParserTraits::ReportMessageAt(Scanner::Location location, ...@@ -88,7 +91,8 @@ void PreParserTraits::ReportMessageAt(Scanner::Location location,
void PreParserTraits::ReportMessageAt(int start_pos, void PreParserTraits::ReportMessageAt(int start_pos,
int end_pos, int end_pos,
const char* type, const char* type,
const char* name_opt) { const char* name_opt,
bool is_reference_error) {
pre_parser_->log_->LogMessage(start_pos, end_pos, type, name_opt); pre_parser_->log_->LogMessage(start_pos, end_pos, type, name_opt);
} }
......
...@@ -342,13 +342,16 @@ class ParserBase : public Traits { ...@@ -342,13 +342,16 @@ class ParserBase : public Traits {
bool is_generator() const { return function_state_->is_generator(); } bool is_generator() const { return function_state_->is_generator(); }
// Report syntax errors. // Report syntax errors.
void ReportMessage(const char* message, Vector<const char*> args) { void ReportMessage(const char* message, Vector<const char*> args,
bool is_reference_error = false) {
Scanner::Location source_location = scanner()->location(); Scanner::Location source_location = scanner()->location();
Traits::ReportMessageAt(source_location, message, args); Traits::ReportMessageAt(source_location, message, args, is_reference_error);
} }
void ReportMessageAt(Scanner::Location location, const char* message) { void ReportMessageAt(Scanner::Location location, const char* message,
Traits::ReportMessageAt(location, message, Vector<const char*>::empty()); bool is_reference_error = false) {
Traits::ReportMessageAt(location, message, Vector<const char*>::empty(),
is_reference_error);
} }
void ReportUnexpectedToken(Token::Value token); void ReportUnexpectedToken(Token::Value token);
...@@ -789,12 +792,10 @@ class PreParserTraits { ...@@ -789,12 +792,10 @@ class PreParserTraits {
static void CheckAssigningFunctionLiteralToProperty( static void CheckAssigningFunctionLiteralToProperty(
PreParserExpression left, PreParserExpression right) {} PreParserExpression left, PreParserExpression right) {}
// Determine whether the expression is a valid assignment left-hand side.
static PreParserExpression ValidateAssignmentLeftHandSide( static bool IsValidLeftHandSide(PreParserExpression expression) {
PreParserExpression expression) { // TODO(marja): check properly; for now, leave it to parser.
// Parser generates a runtime error here if the left hand side is not valid. return true;
// PreParser doesn't have to.
return expression;
} }
static PreParserExpression MarkExpressionAsLValue( static PreParserExpression MarkExpressionAsLValue(
...@@ -812,14 +813,17 @@ class PreParserTraits { ...@@ -812,14 +813,17 @@ class PreParserTraits {
// Reporting errors. // Reporting errors.
void ReportMessageAt(Scanner::Location location, void ReportMessageAt(Scanner::Location location,
const char* message, const char* message,
Vector<const char*> args); Vector<const char*> args,
bool is_reference_error = false);
void ReportMessageAt(Scanner::Location location, void ReportMessageAt(Scanner::Location location,
const char* type, const char* type,
const char* name_opt); const char* name_opt,
bool is_reference_error = false);
void ReportMessageAt(int start_pos, void ReportMessageAt(int start_pos,
int end_pos, int end_pos,
const char* type, const char* type,
const char* name_opt); const char* name_opt,
bool is_reference_error = false);
// "null" return type creators. // "null" return type creators.
static PreParserIdentifier EmptyIdentifier() { static PreParserIdentifier EmptyIdentifier() {
...@@ -1606,6 +1610,8 @@ typename Traits::Type::Expression ParserBase<Traits>::ParseAssignmentExpression( ...@@ -1606,6 +1610,8 @@ typename Traits::Type::Expression ParserBase<Traits>::ParseAssignmentExpression(
// YieldExpression // YieldExpression
// LeftHandSideExpression AssignmentOperator AssignmentExpression // LeftHandSideExpression AssignmentOperator AssignmentExpression
Scanner::Location lhs_location = scanner()->peek_location();
if (peek() == Token::YIELD && is_generator()) { if (peek() == Token::YIELD && is_generator()) {
return this->ParseYieldExpression(ok); return this->ParseYieldExpression(ok);
} }
...@@ -1620,12 +1626,11 @@ typename Traits::Type::Expression ParserBase<Traits>::ParseAssignmentExpression( ...@@ -1620,12 +1626,11 @@ typename Traits::Type::Expression ParserBase<Traits>::ParseAssignmentExpression(
return expression; return expression;
} }
// Signal a reference error if the expression is an invalid left-hand if (!IsValidLeftHandSide(expression)) {
// side expression. We could report this as a syntax error here but this->ReportMessageAt(lhs_location, "invalid_lhs_in_assignment", true);
// for compatibility with JSC we choose to report the error at *ok = false;
// runtime. return this->EmptyExpression();
// TODO(ES5): Should change parsing for spec conformance. }
expression = this->ValidateAssignmentLeftHandSide(expression);
if (strict_mode() == STRICT) { if (strict_mode() == STRICT) {
// Assignment to eval or arguments is disallowed in strict mode. // Assignment to eval or arguments is disallowed in strict mode.
......
...@@ -1843,13 +1843,9 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { ...@@ -1843,13 +1843,9 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
void FullCodeGenerator::VisitAssignment(Assignment* expr) { void FullCodeGenerator::VisitAssignment(Assignment* expr) {
ASSERT(expr->target()->IsValidLeftHandSide());
Comment cmnt(masm_, "[ Assignment"); Comment cmnt(masm_, "[ Assignment");
// Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
// on the left-hand side.
if (!expr->target()->IsValidLeftHandSide()) {
VisitForEffect(expr->target());
return;
}
// Left-hand side can only be a property, a global or a (parameter or local) // Left-hand side can only be a property, a global or a (parameter or local)
// slot. // slot.
...@@ -2346,12 +2342,7 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, ...@@ -2346,12 +2342,7 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
void FullCodeGenerator::EmitAssignment(Expression* expr) { void FullCodeGenerator::EmitAssignment(Expression* expr) {
// Invalid left-hand sides are rewritten by the parser to have a 'throw ASSERT(expr->IsValidLeftHandSide());
// ReferenceError' on the left-hand side.
if (!expr->IsValidLeftHandSide()) {
VisitForEffect(expr);
return;
}
// Left-hand side can only be a property, a global or a (parameter or local) // Left-hand side can only be a property, a global or a (parameter or local)
// slot. // slot.
...@@ -4283,16 +4274,11 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { ...@@ -4283,16 +4274,11 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
ASSERT(expr->expression()->IsValidLeftHandSide());
Comment cmnt(masm_, "[ CountOperation"); Comment cmnt(masm_, "[ CountOperation");
SetSourcePosition(expr->position()); SetSourcePosition(expr->position());
// Invalid left-hand-sides are rewritten to have a 'throw
// ReferenceError' as the left-hand side.
if (!expr->expression()->IsValidLeftHandSide()) {
VisitForEffect(expr->expression());
return;
}
// Expression can only be a property, a global or a (parameter or local) // Expression can only be a property, a global or a (parameter or local)
// slot. // slot.
enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
......
...@@ -2218,7 +2218,6 @@ TEST(NoErrorsNewExpression) { ...@@ -2218,7 +2218,6 @@ TEST(NoErrorsNewExpression) {
"new foo[bar].baz(baz)()[bar].baz;", "new foo[bar].baz(baz)()[bar].baz;",
"new \"foo\"", // Runtime error "new \"foo\"", // Runtime error
"new 1", // Runtime error "new 1", // Runtime error
"new foo++",
// This even runs: // This even runs:
"(new new Function(\"this.x = 1\")).x;", "(new new Function(\"this.x = 1\")).x;",
"new new Test_Two(String, 2).v(0123).length;", "new new Test_Two(String, 2).v(0123).length;",
...@@ -2240,6 +2239,8 @@ TEST(ErrorsNewExpression) { ...@@ -2240,6 +2239,8 @@ TEST(ErrorsNewExpression) {
"new foo bar", "new foo bar",
"new ) foo", "new ) foo",
"new ++foo", "new ++foo",
// TODO(marja): Activate this test once the preparser checks correctly.
// "new foo ++",
NULL NULL
}; };
......
...@@ -29,37 +29,37 @@ ...@@ -29,37 +29,37 @@
// exceptions are delayed until runtime. // exceptions are delayed until runtime.
// Normal assignments: // Normal assignments:
assertThrows("12 = 12"); assertThrows("12 = 12", ReferenceError);
assertThrows("x++ = 12"); assertThrows("x++ = 12", ReferenceError);
assertThrows("eval('var x') = 12"); assertThrows("eval('var x') = 12", ReferenceError);
assertDoesNotThrow("if (false) eval('var x') = 12"); assertThrows("if (false) eval('var x') = 12", ReferenceError);
// Pre- and post-fix operations: // Pre- and post-fix operations:
assertThrows("12++"); assertThrows("12++", ReferenceError);
assertThrows("12--"); assertThrows("12--", ReferenceError);
assertThrows("--12"); assertThrows("--12", ReferenceError);
assertThrows("++12"); assertThrows("++12", ReferenceError);
assertThrows("++(eval('12'))"); assertThrows("++(eval('12'))", ReferenceError);
assertThrows("(eval('12'))++"); assertThrows("(eval('12'))++", ReferenceError);
assertDoesNotThrow("if (false) ++(eval('12'))"); assertThrows("if (false) ++(eval('12'))", ReferenceError);
assertDoesNotThrow("if (false) (eval('12'))++"); assertThrows("if (false) (eval('12'))++", ReferenceError);
// For in: // For in:
assertThrows("for (12 in [1]) print(12);"); assertThrows("for (12 in [1]) print(12);", ReferenceError);
assertThrows("for (eval('var x') in [1]) print(12);"); assertThrows("for (eval('var x') in [1]) print(12);", ReferenceError);
assertDoesNotThrow("if (false) for (eval('var x') in [1]) print(12);"); assertThrows("if (false) for (eval('0') in [1]) print(12);", ReferenceError);
// For: // For:
assertThrows("for (12 = 1;;) print(12);"); assertThrows("for (12 = 1;;) print(12);", ReferenceError);
assertThrows("for (eval('var x') = 1;;) print(12);"); assertThrows("for (eval('var x') = 1;;) print(12);", ReferenceError);
assertDoesNotThrow("if (false) for (eval('var x') = 1;;) print(12);"); assertThrows("if (false) for (eval('var x') = 1;;) print(12);", ReferenceError);
// Assignments to 'this'. // Assignments to 'this'.
assertThrows("this = 42"); assertThrows("this = 42", ReferenceError);
assertDoesNotThrow("function f() { this = 12; }"); assertThrows("function f() { this = 12; }", ReferenceError);
assertThrows("for (this in {x:3, y:4, z:5}) ;"); assertThrows("for (this in {x:3, y:4, z:5}) ;", ReferenceError);
assertThrows("for (this = 0;;) ;"); assertThrows("for (this = 0;;) ;", ReferenceError);
assertThrows("this++"); assertThrows("this++", ReferenceError);
assertThrows("++this"); assertThrows("++this", ReferenceError);
assertThrows("this--"); assertThrows("this--", ReferenceError);
assertThrows("--this"); assertThrows("--this", ReferenceError);
// 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: --allow-natives-syntax
try {
var f = eval("(function(){0 = y + y})");
%OptimizeFunctionOnNextCall(f);
f();
assertUnreachable();
} catch(e) {
assertTrue(e instanceof ReferenceError);
}
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