Make invalid break/continue statements an early syntax error.

Previously we delayed the throwing of syntax errors until runtime, so
unreachable errors didn't get reported.
To match a change in JSC, we now stop parsing and report the error immediately.

BUG=69736
TEST=

Review URL: http://codereview.chromium.org/6355006

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6341 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
lrn@chromium.org 2011-01-17 09:36:10 +00:00
parent fae90d4f32
commit f09705ab9b
5 changed files with 59 additions and 27 deletions

View File

@ -778,7 +778,8 @@ void Parser::ReportMessageAt(Scanner::Location source_location,
const char* type,
Vector<const char*> args) {
MessageLocation location(script_,
source_location.beg_pos, source_location.end_pos);
source_location.beg_pos,
source_location.end_pos);
Handle<JSArray> array = Factory::NewJSArray(args.length());
for (int i = 0; i < args.length(); i++) {
SetElement(array, i, Factory::NewStringFromUtf8(CStrVector(args[i])));
@ -788,6 +789,21 @@ void Parser::ReportMessageAt(Scanner::Location source_location,
}
void Parser::ReportMessageAt(Scanner::Location source_location,
const char* type,
Vector<Handle<String> > args) {
MessageLocation location(script_,
source_location.beg_pos,
source_location.end_pos);
Handle<JSArray> array = Factory::NewJSArray(args.length());
for (int i = 0; i < args.length(); i++) {
SetElement(array, i, args[i]);
}
Handle<Object> result = Factory::NewSyntaxError(type, array);
Top::Throw(*result, &location);
}
// Base class containing common code for the different finder classes used by
// the parser.
class ParserFinder {
@ -1693,12 +1709,16 @@ Statement* Parser::ParseContinueStatement(bool* ok) {
IterationStatement* target = NULL;
target = LookupContinueTarget(label, CHECK_OK);
if (target == NULL) {
// Illegal continue statement. To be consistent with KJS we delay
// reporting of the syntax error until runtime.
Handle<String> error_type = Factory::illegal_continue_symbol();
if (!label.is_null()) error_type = Factory::unknown_label_symbol();
Expression* throw_error = NewThrowSyntaxError(error_type, label);
return new ExpressionStatement(throw_error);
// Illegal continue statement.
const char* message = "illegal_continue";
Vector<Handle<String> > args;
if (!label.is_null()) {
message = "unknown_label";
args = Vector<Handle<String> >(&label, 1);
}
ReportMessageAt(scanner().location(), message, args);
*ok = false;
return NULL;
}
ExpectSemicolon(CHECK_OK);
return new ContinueStatement(target);
@ -1724,12 +1744,16 @@ Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) {
BreakableStatement* target = NULL;
target = LookupBreakTarget(label, CHECK_OK);
if (target == NULL) {
// Illegal break statement. To be consistent with KJS we delay
// reporting of the syntax error until runtime.
Handle<String> error_type = Factory::illegal_break_symbol();
if (!label.is_null()) error_type = Factory::unknown_label_symbol();
Expression* throw_error = NewThrowSyntaxError(error_type, label);
return new ExpressionStatement(throw_error);
// Illegal break statement.
const char* message = "illegal_break";
Vector<Handle<String> > args;
if (!label.is_null()) {
message = "unknown_label";
args = Vector<Handle<String> >(&label, 1);
}
ReportMessageAt(scanner().location(), message, args);
*ok = false;
return NULL;
}
ExpectSemicolon(CHECK_OK);
return new BreakStatement(target);

View File

@ -430,6 +430,9 @@ class Parser {
void ReportMessageAt(Scanner::Location loc,
const char* message,
Vector<const char*> args);
void ReportMessageAt(Scanner::Location loc,
const char* message,
Vector<Handle<String> > args);
protected:
FunctionLiteral* ParseLazy(Handle<SharedFunctionInfo> info,

View File

@ -25,17 +25,18 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// To be compatible with KJS syntax errors for illegal return, break
// and continue should be delayed to runtime.
// To be compatible with JSC syntax errors for illegal returns should be delayed
// to runtime.
// Invalid continue and break statements are caught at compile time.
// Do not throw syntax errors for illegal return, break and continue
// at compile time.
// Do not throw syntax errors for illegal return at compile time.
assertDoesNotThrow("if (false) return;");
assertDoesNotThrow("if (false) break;");
assertDoesNotThrow("if (false) continue;");
// Throw syntax errors for illegal return, break and continue at
// compile time.
// Throw syntax errors for illegal break and continue at compile time.
assertThrows("if (false) break;");
assertThrows("if (false) continue;");
// Throw syntax errors for illegal return, break and continue at runtime.
assertThrows("return;");
assertThrows("break;");
assertThrows("continue;");

View File

@ -25,14 +25,14 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
xeval = function(s) { eval(s); }
xeval("$=function anonymous() { /*noex*/do {} while(({ get x(x) { break ; }, set x() { (undefined);} })); }");
assertThrows("$=function anonymous() { /*noex*/do {} while(({ get x(x) { break ; }, set x() { (undefined);} })); }");
foo = function() { eval("$=function anonymous() { /*noex*/do {} while(({ get x(x) { break ; }, set x() { (undefined);} })); }"); }
function foo() {
assertThrows("$=function anonymous() { /*noex*/do {} while(({ get x(x) { break ; }, set x() { (undefined);} })); }");
}
foo();
xeval = function(s) { eval(s); }
eval("$=function anonymous() { /*noex*/do {} while(({ get x(x) { break ; }, set x() { (undefined);} })); }");
assertThrows("$=function anonymous() { /*noex*/do {} while(({ get x(x) { break ; }, set x() { (undefined);} })); }");
xeval = function(s) { eval(s); }
xeval('$=function(){L: {break L;break L;}};');

View File

@ -25,11 +25,15 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// We throw syntax errors early for invalid break and continue statements.
// (Notice that the example isn't valid ECMAScript due to the
// function declaration that is not at top level.)
function f() {
// Force eager compilation of x through the use of eval. The break
// in function x should not try to break out of the enclosing while.
return eval("while(0) function x() { break; }; 42");
};
assertEquals(42, f());
assertThrows("f()");