Commit 74cf8e01 authored by rossberg's avatar rossberg Committed by Commit bot

[strong] Check constructor returns

R=dslomov@chromium.org
BUG=v8:3956
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#27320}
parent cd339784
...@@ -175,6 +175,8 @@ var kMessages = { ...@@ -175,6 +175,8 @@ var kMessages = {
strong_super_call_missing: ["Please always invoke the super constructor in subclasses in strong mode"], strong_super_call_missing: ["Please always invoke the super constructor in subclasses in strong mode"],
strong_super_call_duplicate: ["Please don't invoke the super constructor multiple times in strong mode"], strong_super_call_duplicate: ["Please don't invoke the super constructor multiple times in strong mode"],
strong_super_call_nested: ["Please don't invoke the super constructor nested inside another statement or expression in strong mode"], strong_super_call_nested: ["Please don't invoke the super constructor nested inside another statement or expression in strong mode"],
strong_constructor_return_value: ["Please do not return a value from a constructor in strong mode"],
strong_constructor_return_misplaced: ["Please do not return from a constructor before its super constructor invocation in strong mode"],
sloppy_lexical: ["Block-scoped declarations (let, const, function, class) not yet supported outside strict mode"], sloppy_lexical: ["Block-scoped declarations (let, const, function, class) not yet supported outside strict mode"],
malformed_arrow_function_parameter_list: ["Malformed arrow function parameter list"], malformed_arrow_function_parameter_list: ["Malformed arrow function parameter list"],
generator_poison_pill: ["'caller' and 'arguments' properties may not be accessed on generator functions."], generator_poison_pill: ["'caller' and 'arguments' properties may not be accessed on generator functions."],
......
...@@ -2707,6 +2707,7 @@ Statement* Parser::ParseReturnStatement(bool* ok) { ...@@ -2707,6 +2707,7 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
// reported (underlining). // reported (underlining).
Expect(Token::RETURN, CHECK_OK); Expect(Token::RETURN, CHECK_OK);
Scanner::Location loc = scanner()->location(); Scanner::Location loc = scanner()->location();
function_state_->set_return_location(loc);
Token::Value tok = peek(); Token::Value tok = peek();
Statement* result; Statement* result;
...@@ -2721,6 +2722,14 @@ Statement* Parser::ParseReturnStatement(bool* ok) { ...@@ -2721,6 +2722,14 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
return_value = GetLiteralUndefined(position()); return_value = GetLiteralUndefined(position());
} }
} else { } else {
if (is_strong(language_mode()) &&
i::IsConstructor(function_state_->kind())) {
int pos = peek_position();
ReportMessageAt(Scanner::Location(pos, pos + 1),
"strong_constructor_return_value");
*ok = false;
return NULL;
}
return_value = ParseExpression(true, CHECK_OK); return_value = ParseExpression(true, CHECK_OK);
} }
ExpectSemicolon(CHECK_OK); ExpectSemicolon(CHECK_OK);
......
...@@ -613,6 +613,7 @@ PreParser::Statement PreParser::ParseReturnStatement(bool* ok) { ...@@ -613,6 +613,7 @@ PreParser::Statement PreParser::ParseReturnStatement(bool* ok) {
// reporting any errors on it, because of the way errors are // reporting any errors on it, because of the way errors are
// reported (underlining). // reported (underlining).
Expect(Token::RETURN, CHECK_OK); Expect(Token::RETURN, CHECK_OK);
function_state_->set_return_location(scanner()->location());
// An ECMAScript program is considered syntactically incorrect if it // An ECMAScript program is considered syntactically incorrect if it
// contains a return statement that is not within the body of a // contains a return statement that is not within the body of a
...@@ -624,6 +625,14 @@ PreParser::Statement PreParser::ParseReturnStatement(bool* ok) { ...@@ -624,6 +625,14 @@ PreParser::Statement PreParser::ParseReturnStatement(bool* ok) {
tok != Token::SEMICOLON && tok != Token::SEMICOLON &&
tok != Token::RBRACE && tok != Token::RBRACE &&
tok != Token::EOS) { tok != Token::EOS) {
if (is_strong(language_mode()) &&
i::IsConstructor(function_state_->kind())) {
int pos = peek_position();
ReportMessageAt(Scanner::Location(pos, pos + 1),
"strong_constructor_return_value");
*ok = false;
return Statement::Default();
}
ParseExpression(true, CHECK_OK); ParseExpression(true, CHECK_OK);
} }
ExpectSemicolon(CHECK_OK); ExpectSemicolon(CHECK_OK);
......
...@@ -217,9 +217,13 @@ class ParserBase : public Traits { ...@@ -217,9 +217,13 @@ class ParserBase : public Traits {
void AddProperty() { expected_property_count_++; } void AddProperty() { expected_property_count_++; }
int expected_property_count() { return expected_property_count_; } int expected_property_count() { return expected_property_count_; }
Scanner::Location return_location() const { return return_location_; }
Scanner::Location super_call_location() const { Scanner::Location super_call_location() const {
return super_call_location_; return super_call_location_;
} }
void set_return_location(Scanner::Location location) {
return_location_ = location;
}
void set_super_call_location(Scanner::Location location) { void set_super_call_location(Scanner::Location location) {
super_call_location_ = location; super_call_location_ = location;
} }
...@@ -254,6 +258,9 @@ class ParserBase : public Traits { ...@@ -254,6 +258,9 @@ class ParserBase : public Traits {
// Properties count estimation. // Properties count estimation.
int expected_property_count_; int expected_property_count_;
// Location of most recent 'return' statement (invalid if none).
Scanner::Location return_location_;
// Location of call to the "super" constructor (invalid if none). // Location of call to the "super" constructor (invalid if none).
Scanner::Location super_call_location_; Scanner::Location super_call_location_;
...@@ -1667,6 +1674,7 @@ ParserBase<Traits>::FunctionState::FunctionState( ...@@ -1667,6 +1674,7 @@ ParserBase<Traits>::FunctionState::FunctionState(
: next_materialized_literal_index_(0), : next_materialized_literal_index_(0),
next_handler_index_(0), next_handler_index_(0),
expected_property_count_(0), expected_property_count_(0),
return_location_(Scanner::Location::invalid()),
super_call_location_(Scanner::Location::invalid()), super_call_location_(Scanner::Location::invalid()),
kind_(kind), kind_(kind),
generator_object_variable_(NULL), generator_object_variable_(NULL),
...@@ -2796,11 +2804,17 @@ ParserBase<Traits>::ParseSuperExpression(bool is_new, bool* ok) { ...@@ -2796,11 +2804,17 @@ ParserBase<Traits>::ParseSuperExpression(bool is_new, bool* ok) {
// new super() is never allowed. // new super() is never allowed.
// super() is only allowed in derived constructor // super() is only allowed in derived constructor
if (!is_new && peek() == Token::LPAREN && IsSubclassConstructor(kind)) { if (!is_new && peek() == Token::LPAREN && IsSubclassConstructor(kind)) {
if (is_strong(language_mode()) && if (is_strong(language_mode())) {
function_state->super_call_location().IsValid()) { if (function_state->super_call_location().IsValid()) {
ReportMessageAt(scanner()->location(), "strong_super_call_duplicate"); ReportMessageAt(scanner()->location(), "strong_super_call_duplicate");
*ok = false; *ok = false;
return this->EmptyExpression(); return this->EmptyExpression();
} else if (function_state->return_location().IsValid()) {
ReportMessageAt(function_state->return_location(),
"strong_constructor_return_misplaced");
*ok = false;
return this->EmptyExpression();
}
} }
function_state->set_super_call_location(scanner()->location()); function_state->set_super_call_location(scanner()->location());
return this->SuperReference(scope_, factory()); return this->SuperReference(scope_, factory());
......
...@@ -5608,6 +5608,32 @@ TEST(StrongSuperCalls) { ...@@ -5608,6 +5608,32 @@ TEST(StrongSuperCalls) {
} }
TEST(StrongConstructorReturns) {
const char* sloppy_context_data[][2] = {{"", ""}, {NULL}};
const char* strict_context_data[][2] = {{"'use strict';", ""}, {NULL}};
const char* strong_context_data[][2] = {{"'use strong';", ""}, {NULL}};
const char* data[] = {
"class C extends Object { constructor() { super(); return {}; } }",
"class C extends Object { constructor() { super(); { return {}; } } }",
"class C extends Object { constructor() { super(); if (1) return {}; } }",
"class C extends Object { constructor() { return; super(); } }",
"class C extends Object { constructor() { { return; } super(); } }",
"class C extends Object { constructor() { if (0) return; super(); } }",
NULL};
static const ParserFlag always_flags[] = {
kAllowStrongMode, kAllowHarmonyClasses, kAllowHarmonyObjectLiterals
};
RunParserSyncTest(sloppy_context_data, data, kError, NULL, 0, always_flags,
arraysize(always_flags));
RunParserSyncTest(strict_context_data, data, kSuccess, NULL, 0, always_flags,
arraysize(always_flags));
RunParserSyncTest(strong_context_data, data, kError, NULL, 0, always_flags,
arraysize(always_flags));
}
TEST(ArrowFunctionASIErrors) { TEST(ArrowFunctionASIErrors) {
const char* context_data[][2] = {{"'use strict';", ""}, {"", ""}, const char* context_data[][2] = {{"'use strict';", ""}, {"", ""},
{NULL, NULL}}; {NULL, NULL}};
......
...@@ -32,9 +32,9 @@ function constructor(body) { ...@@ -32,9 +32,9 @@ function constructor(body) {
})(); })();
(function NoNestedSuper() { (function NoNestedSuper() {
assertSyntaxError(constructor("(super())")); assertSyntaxError(constructor("(super());"));
assertSyntaxError(constructor("(() => super())(); } })")); assertSyntaxError(constructor("(() => super())();"));
assertSyntaxError(constructor("{ super();")); assertSyntaxError(constructor("{ super(); }"));
assertSyntaxError(constructor("if (1) super();")); assertSyntaxError(constructor("if (1) super();"));
})(); })();
...@@ -43,4 +43,18 @@ function constructor(body) { ...@@ -43,4 +43,18 @@ function constructor(body) {
assertSyntaxError(constructor("super(); super();")); assertSyntaxError(constructor("super(); super();"));
assertSyntaxError(constructor("super(); (super());")); assertSyntaxError(constructor("super(); (super());"));
assertSyntaxError(constructor("super(); { super() }")); assertSyntaxError(constructor("super(); { super() }"));
assertSyntaxError(constructor("super(); (() => super())();"));
})();
(function NoReturnValue() {
assertSyntaxError(constructor("return {};"));
assertSyntaxError(constructor("return undefined;"));
assertSyntaxError(constructor("{ return {}; }"));
assertSyntaxError(constructor("if (1) return {};"));
})();
(function NoReturnBeforeSuper() {
assertSyntaxError(constructor("return; super();"));
assertSyntaxError(constructor("if (0) return; super();"));
assertSyntaxError(constructor("{ return; } super();"));
})(); })();
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