# HG changeset patch # User David Anderson # Date 1356234523 28800 # Node ID 2b8512340180409535b6e7b2c745bd6693bafc2d # Parent 6030e0b46fe29235ac10d927d626c29133ef1f0d Re-introduce definite return analysis. diff -r 6030e0b46fe2 -r 2b8512340180 include/keima.h --- a/include/keima.h Sat Dec 22 18:25:31 2012 -0800 +++ b/include/keima.h Sat Dec 22 19:48:43 2012 -0800 @@ -467,7 +467,7 @@ /* * Compiles a file and returns a Module. */ -extern Local Compile(const char *path); +extern bool Compile(const char *path); class Internals { diff -r 6030e0b46fe2 -r 2b8512340180 src/API.cpp --- a/src/API.cpp Sat Dec 22 18:25:31 2012 -0800 +++ b/src/API.cpp Sat Dec 22 19:48:43 2012 -0800 @@ -91,7 +91,7 @@ return Ke::Local(reinterpret_cast(Ke::HandleScope::CreateHandle(from))); } -ke::Module * +bool InternalCompile(const char *path) { PoolScope poolScope(ZONE()->pool()); @@ -102,36 +102,20 @@ unit->path_ = path; if (!cc.addTranslationUnit(unit)) - return NULL; + return false; if (!cc.compile()) - return NULL; - - return NULL; + return false; -#if 0 - ke::Local module(ZONE(), CompileFromSource(cc, path, bytes, length)); - delete [] bytes; - if (!module) - return NULL; - - ke::Local pathstr(ZONE(), ke::String::New(ZONE(), path, Heap::Tenure_Old)); - if (!pathstr) - return NULL; - - module->setPath(pathstr); - return module; -#endif - return NULL; + return true; } // This is split out from InternalCompile so the RootScope doesn't conflict // with making a return handle. -Ke::Local +bool Ke::Compile(const char *path) { - ke::Local module(ZONE(), InternalCompile(path)); - return ToLocal(module); + return InternalCompile(path); } void diff -r 6030e0b46fe2 -r 2b8512340180 src/Messages.tbl --- a/src/Messages.tbl Sat Dec 22 18:25:31 2012 -0800 +++ b/src/Messages.tbl Sat Dec 22 19:48:43 2012 -0800 @@ -53,9 +53,9 @@ MSG(NativeNotBound, TypeError, "attempted to call unbound native \"%s\"") MSG(AllocationOverflow, SystemError, "allocation request overflowed") MSG(TooMuchRecursion, SystemError, "stack overflow: too much recursion") -MSG(MissingReturnValue, SyntaxError, "tagged function must return a value") +MSG(MissingReturnValue, SyntaxError, "function must return a value") MSG(NotAllPathsReturnValue, SyntaxError, "not all paths through function return a value") -MSG(UsedVoidReturn, SyntaxError, "return value expected, but function does not return a value") +MSG(UsedVoidReturn, SyntaxError, "value returned, but function is void") MSG(FunctionDoesNotReturnValue, SyntaxError, "cannot use the result of a function with no return value") MSG(IdentifierNotFound, SyntaxError, "identifier '%s' could not be found") MSG(TypeMismatchDuringInvoke, TypeError, "incoming type '%s' does not match signature type '%s'") diff -r 6030e0b46fe2 -r 2b8512340180 src/Stack.cpp --- a/src/Stack.cpp Sat Dec 22 18:25:31 2012 -0800 +++ b/src/Stack.cpp Sat Dec 22 19:48:43 2012 -0800 @@ -201,15 +201,15 @@ top_.fp = top_.fp->prev(); } -void -Frame::enterLoop(Zone *zone) -{ - assert(loopDepth_ < code_->maxLoopDepth()); - loopStack()[loopDepth_] = zone->heap().lifoPosition(); - loopDepth_++; -} - -void +void +Frame::enterLoop(Zone *zone) +{ + assert(loopDepth_ < code_->maxLoopDepth()); + loopStack()[loopDepth_] = zone->heap().lifoPosition(); + loopDepth_++; +} + +void Frame::leaveLoop(Zone *zone) { assert(loopDepth_ > 0); diff -r 6030e0b46fe2 -r 2b8512340180 src/compiler/CompileContext.cpp --- a/src/compiler/CompileContext.cpp Sat Dec 22 18:25:31 2012 -0800 +++ b/src/compiler/CompileContext.cpp Sat Dec 22 19:48:43 2012 -0800 @@ -239,6 +239,9 @@ if (!zone_->stack().pushModuleFrame(unit->module_, args)) assert(false); + if (failures_) + return false; + ke::LocalSlot slot; if (!Interpret(zone_, NULL, &slot)) assert(false); diff -r 6030e0b46fe2 -r 2b8512340180 src/compiler/SemanticAnalysis.cpp --- a/src/compiler/SemanticAnalysis.cpp Sat Dec 22 18:25:31 2012 -0800 +++ b/src/compiler/SemanticAnalysis.cpp Sat Dec 22 19:48:43 2012 -0800 @@ -79,7 +79,8 @@ emitter_(pool_), module_(parent->module_), fun_(fun), - loop_(NULL) + loop_(NULL), + control_(NULL) { } @@ -167,8 +168,21 @@ } AutoEnterScope varScope(&scope_, stmt->varScope()); + ControlStatus status = visitForControl(stmt->body()); - stmt->body()->accept(this); + if (!fun_->returnType()->isVoid()) { + // If the function is not void, report if not all paths return a value. + // All other incorrect return cases have been caught already. + if (status.returns() == Returns_Sometimes) { + cc_.reportError(stmt->pos(), Message_NotAllPathsReturnValue); + return NULL; + } + + if (status.returns() == Returns_Never) { + cc_.reportError(stmt->pos(), Message_MissingReturnValue); + return NULL; + } + } Local code(zone_, __ finish()); if (!code) @@ -217,28 +231,60 @@ } void +SemanticAnalysis::ControlScope::merge(const ControlStatus &left, const ControlStatus &right) +{ + // If both sides terminate in a return, we consider this a return as well. + if (left.returns() == Returns_Always && right.returns() == Returns_Always) { + terminate(Returns_Always); + return; + } + + ReturnStatus status = (left.returns() == Returns_Never && right.returns() == Returns_Never) + ? Returns_Never + : Returns_Sometimes; + + if (left.terminates() && right.terminates()) + terminate(status); + else + returns(status); +} + +SemanticAnalysis::ControlStatus +SemanticAnalysis::visitForControl(Statement *statement) +{ + ControlScope scope(&control_); + statement->accept(this); + return scope.status(); +} + +void SemanticAnalysis::visitIfStatement(IfStatement *node) { Label join; + ControlStatus trueBranch; + ControlStatus falseBranch(false, Returns_Never); + if (!node->ifFalse()) { Label success; visitForTest(node->condition(), &success, &join, &success); __ bind(&success); - node->ifTrue()->accept(this); + trueBranch = visitForControl(node->ifTrue()); } else { Label success, next; visitForTest(node->condition(), &success, &next, &success); __ bind(&success); - node->ifTrue()->accept(this); + trueBranch = visitForControl(node->ifTrue()); __ jump(&join); __ bind(&next); - node->ifFalse()->accept(this); + falseBranch = visitForControl(node->ifFalse()); } __ bind(&join); + + control_->merge(trueBranch, falseBranch); } void @@ -250,7 +296,7 @@ loop_->setUsesLifoStack(); } -void +SemanticAnalysis::ControlStatus SemanticAnalysis::visitLoopBody(Statement *stmt) { // We always mark off a loop body, so on each edge, we can balance the @@ -264,11 +310,13 @@ // possibility that a long-running loop will overflow the LIFO region // and therefore start requiring nursery allocations. int pos = __ enterloop(); - stmt->accept(this); + ControlStatus status = visitForControl(stmt); __ leaveloop(); if (loop_->usesLifoStack()) __ setLoopUsesLifoStack(pos); + + return status; } void @@ -289,7 +337,7 @@ __ jump(&test); __ bind(&header); - visitLoopBody(node->body()); + ControlStatus status = visitLoopBody(node->body()); __ bind(&update); if (node->update()) @@ -303,6 +351,14 @@ } __ bind(&join); + + // If there was a condition, we treat this like a while loop. Otherwise, + // the join point is only reachable if the loop contains a break. The + // termination status doesn't tell us anything yet. + if (node->condition() || loop.breaks()) + control_->merge(status, ControlStatus(false, Returns_Never)); + else + control_->terminate(status.returns()); assert(__ stackDepth() == 0); } @@ -317,19 +373,34 @@ __ bind(&header); + ControlStatus status; + LoopScope loop(scope_, &join, &header, &loop_); if (node->token() == TOK_WHILE) { Label body; visitForTest(node->condition(), &body, &join, &body); - visitLoopBody(node->body()); + status = visitLoopBody(node->body()); __ jump(&header); } else { - visitLoopBody(node->body()); + status = visitLoopBody(node->body()); visitForTest(node->condition(), &header, &join, &join); } __ bind(&join); + // Detect loops that will always have a fork in the contro-flow graph. + // This will be a |while| loop, or a |do-while| loop whose body does + // not terminate. For now, we treat these as an |if| regardless of the + // direction the branch can take. That means the control-flow is always + // conditional. + if (node->token() == TOK_WHILE || status.terminates() || loop.breaks()) { + control_->merge(status, ControlStatus(false, Returns_Never)); + } else { + // At this point, we've got a do-while loop with a |return| or + // |continue|, meaning that the rest of the block is unreachable. + control_->terminate(status.returns()); + } + assert(__ stackDepth() == 0); } @@ -398,9 +469,11 @@ void SemanticAnalysis::visitReturnStatement(ReturnStatement *node) { + control_->returns(Returns_Always); + if (!node->expression()) { if (!fun_->returnType()->isVoid()) { - cc_.reportError(node->pos(), Message_UsedVoidReturn); + cc_.reportError(node->pos(), Message_MissingReturnValue); return; } @@ -408,6 +481,11 @@ return; } + if (fun_->returnType()->isVoid()) { + cc_.reportError(node->pos(), Message_UsedVoidReturn); + return; + } + PoolScope poolScope(zone_->pool()); RootScope rootScope(zone_); @@ -420,7 +498,11 @@ return; discharge(hir); - __ return_(); + + if (hir->type()->isVoid()) + __ returnvoid(); + else + __ return_(); } void @@ -601,6 +683,7 @@ return; } + loop_->setBreaks(); __ j(OP_BREAK, loop_->break_()); } diff -r 6030e0b46fe2 -r 2b8512340180 src/compiler/SemanticAnalysis.h --- a/src/compiler/SemanticAnalysis.h Sat Dec 22 18:25:31 2012 -0800 +++ b/src/compiler/SemanticAnalysis.h Sat Dec 22 19:48:43 2012 -0800 @@ -88,8 +88,85 @@ Coerce_Assign }; + // For a given control flow path, whether it returns. + enum ReturnStatus + { + Returns_Never, + Returns_Sometimes, + Returns_Always + }; + + // For a given control flow path, whether it terminates, + // and if it terminates, whether it returns. + class ControlStatus + { + bool terminates_; + ReturnStatus returns_; + + public: + ControlStatus() + { + } + ControlStatus(bool terminates, ReturnStatus returns) + : terminates_(terminates), + returns_(returns) + { + } + + bool terminates() const { + return terminates_; + } + ReturnStatus returns() const { + return returns_; + } + }; + + class ControlScope + { + ReturnStatus returns_; + ControlScope **prevp_; + ControlScope *prev_; + bool terminates_; + + public: + ControlScope(ControlScope **prevp) + : returns_(Returns_Never), + prevp_(prevp), + prev_(*prevp), + terminates_(false) + { + *prevp_ = this; + } + ~ControlScope() { + *prevp_ = prev_; + } + ControlStatus status() { + return ControlStatus(terminates_, returns_); + } + + void returns(ReturnStatus status) { + // We allow multiple terminates, but only the first one takes + // effect. For example, |break; continue;| is legal, but the + // continue is unreachable. + if (terminates_) + return; + if (status > returns_) + returns_ = status; + } + void terminate(ReturnStatus status) { + if (terminates_) + return; + terminates_ = true; + returns_ = status; + } + void merge(const ControlStatus &left, const ControlStatus &right); + void inherit(const ControlStatus &other); + }; + + void requireLifoStack(); - void visitLoopBody(Statement *stmt); + ControlStatus visitForControl(Statement *statement); + ControlStatus visitLoopBody(Statement *stmt); void visitForTest(Expression *expr, BytecodeEmitter::Label *trueBranch, BytecodeEmitter::Label *falseBranch, @@ -117,6 +194,7 @@ LoopScope **prevp_; LoopScope *prev_; bool usesLifoStack_; + bool breaks_; public: LoopScope(Scope *scope, BytecodeEmitter::Label *bk, BytecodeEmitter::Label *ct, @@ -126,7 +204,8 @@ ct_(ct), prevp_(prevp), prev_(*prevp), - usesLifoStack_(false) + usesLifoStack_(false), + breaks_(false) { *prevp_ = this; } @@ -151,6 +230,12 @@ bool usesLifoStack() const { return usesLifoStack_; } + void setBreaks() { + breaks_ = true; + } + bool breaks() const { + return breaks_; + } }; private: @@ -164,6 +249,7 @@ ScopedRoot module_; ScopedRoot fun_; LoopScope *loop_; + ControlScope *control_; }; } // namespace ke diff -r 6030e0b46fe2 -r 2b8512340180 src/main.cpp --- a/src/main.cpp Sat Dec 22 18:25:31 2012 -0800 +++ b/src/main.cpp Sat Dec 22 19:48:43 2012 -0800 @@ -45,7 +45,7 @@ } } virtual void beginCompilationErrors(const char *file) { - fprintf(stderr, "\nDisplaying compilation errors for \"%s\"\n", file); + fprintf(stderr, "Displaying compilation errors for \"%s\"\n", file); } virtual void reportCompilationError(const char *message, unsigned line, unsigned col) { fprintf(stderr, " line %d, col %d: %s\n", line, col, message); @@ -110,12 +110,15 @@ int rval = 0; Keima::InstallMessageReporter(&s_Reporter); - { + do { MainCollector entry; Keima::SetPublicFunctionListener(&entry); HandleScope scope; - Compile(argv[1]); + if (!Compile(argv[1])) { + rval = 1; + break; + } Keima::CollectGarbage(); @@ -131,7 +134,7 @@ if (!Keima::Invoke(fun, NULL, 0, true, &rval)) rval = 1; } - } + } while (0); Keima::Shutdown(); diff -r 6030e0b46fe2 -r 2b8512340180 tests/basic/precall-void-used.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/precall-void-used.out Sat Dec 22 19:48:43 2012 -0800 @@ -0,0 +1,1 @@ +0 diff -r 6030e0b46fe2 -r 2b8512340180 tests/basic/precall-void-used.sp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/precall-void-used.sp Sat Dec 22 19:48:43 2012 -0800 @@ -0,0 +1,17 @@ +native PrintNum(num); + +g() +{ + PrintNum(f()); +} + +f() +{ + return 0; +} + +public main() +{ + g(); +} + diff -r 6030e0b46fe2 -r 2b8512340180 tests/basic/return-analyze-for-1.out diff -r 6030e0b46fe2 -r 2b8512340180 tests/basic/return-analyze-for-1.sp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/return-analyze-for-1.sp Sat Dec 22 19:48:43 2012 -0800 @@ -0,0 +1,12 @@ +public f() +{ + for (;;) { + } +} + +public main() +{ +} + + + diff -r 6030e0b46fe2 -r 2b8512340180 tests/basic/return-analyze-for-2.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/return-analyze-for-2.out Sat Dec 22 19:48:43 2012 -0800 @@ -0,0 +1,1 @@ +5 diff -r 6030e0b46fe2 -r 2b8512340180 tests/basic/return-analyze-for-2.sp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/return-analyze-for-2.sp Sat Dec 22 19:48:43 2012 -0800 @@ -0,0 +1,16 @@ +native PrintNum(num); + +f() +{ + for (;;) { + return 5; + } +} + +public main() +{ + PrintNum(f()); +} + + + diff -r 6030e0b46fe2 -r 2b8512340180 tests/basic/return-analyze-for-3.err --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/return-analyze-for-3.err Sat Dec 22 19:48:43 2012 -0800 @@ -0,0 +1,1 @@ + line 1, col 2: not all paths through function return a value diff -r 6030e0b46fe2 -r 2b8512340180 tests/basic/return-analyze-for-3.sp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/return-analyze-for-3.sp Sat Dec 22 19:48:43 2012 -0800 @@ -0,0 +1,13 @@ +f(x) +{ + for (;;) { + if (x) + return 5; + } +} + +public main() +{ + f(5); +} + diff -r 6030e0b46fe2 -r 2b8512340180 tests/basic/return-analyze-for-4.err --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/return-analyze-for-4.err Sat Dec 22 19:48:43 2012 -0800 @@ -0,0 +1,1 @@ + line 1, col 8: not all paths through function return a value diff -r 6030e0b46fe2 -r 2b8512340180 tests/basic/return-analyze-for-4.sp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/return-analyze-for-4.sp Sat Dec 22 19:48:43 2012 -0800 @@ -0,0 +1,13 @@ +public f(x) +{ + for (; x;) { + return 5; + } +} + +public main() +{ + return f(5); +} + + diff -r 6030e0b46fe2 -r 2b8512340180 tests/basic/return-analyze-for-5.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/return-analyze-for-5.out Sat Dec 22 19:48:43 2012 -0800 @@ -0,0 +1,1 @@ +54 diff -r 6030e0b46fe2 -r 2b8512340180 tests/basic/return-analyze-for-5.sp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/return-analyze-for-5.sp Sat Dec 22 19:48:43 2012 -0800 @@ -0,0 +1,17 @@ +native PrintNum(num); + +f(x) +{ + for (; x;) { + return 5; + } + return 4; +} + +public main() +{ + PrintNum(f(5)); + PrintNum(f(0)); +} + + diff -r 6030e0b46fe2 -r 2b8512340180 tests/basic/return-analyze-if-1.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/return-analyze-if-1.out Sat Dec 22 19:48:43 2012 -0800 @@ -0,0 +1,1 @@ +25 diff -r 6030e0b46fe2 -r 2b8512340180 tests/basic/return-analyze-if-1.sp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/return-analyze-if-1.sp Sat Dec 22 19:48:43 2012 -0800 @@ -0,0 +1,16 @@ +native PrintNum(num); + +f(x) +{ + if (x) + return 5; + return 2; +} + +public main() +{ + PrintNum(f(0)); + PrintNum(f(1)); +} + + diff -r 6030e0b46fe2 -r 2b8512340180 tests/basic/return-analyze-if-2.err --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/return-analyze-if-2.err Sat Dec 22 19:48:43 2012 -0800 @@ -0,0 +1,1 @@ + line 3, col 3: not all paths through function return a value diff -r 6030e0b46fe2 -r 2b8512340180 tests/basic/return-analyze-if-2.sp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/return-analyze-if-2.sp Sat Dec 22 19:48:43 2012 -0800 @@ -0,0 +1,14 @@ +native PrintNum(num); + +f(x) +{ + if (x) + return 5; +} + +public main() +{ + PrintNum(f(4)); +} + + diff -r 6030e0b46fe2 -r 2b8512340180 tests/basic/return-analyze-if-3.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/return-analyze-if-3.out Sat Dec 22 19:48:43 2012 -0800 @@ -0,0 +1,1 @@ +65 diff -r 6030e0b46fe2 -r 2b8512340180 tests/basic/return-analyze-if-3.sp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/return-analyze-if-3.sp Sat Dec 22 19:48:43 2012 -0800 @@ -0,0 +1,17 @@ +native PrintNum(num); + +f(x) +{ + if (x) + return 5; + else + return 6; +} + +public main() +{ + PrintNum(f(0)); + PrintNum(f(1)); +} + + diff -r 6030e0b46fe2 -r 2b8512340180 tests/basic/return-analyze-if-4.err --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/return-analyze-if-4.err Sat Dec 22 19:48:43 2012 -0800 @@ -0,0 +1,1 @@ + line 3, col 3: not all paths through function return a value diff -r 6030e0b46fe2 -r 2b8512340180 tests/basic/return-analyze-if-4.sp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/return-analyze-if-4.sp Sat Dec 22 19:48:43 2012 -0800 @@ -0,0 +1,17 @@ +native PrintNum(num); + +f(x) +{ + if (x) + return 5; + else if (x) + return 6; +} + +public main() +{ + PrintNum(f(0)); + PrintNum(f(1)); +} + + diff -r 6030e0b46fe2 -r 2b8512340180 tests/basic/return-analyze-if-5.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/return-analyze-if-5.out Sat Dec 22 19:48:43 2012 -0800 @@ -0,0 +1,1 @@ +596 diff -r 6030e0b46fe2 -r 2b8512340180 tests/basic/return-analyze-if-5.sp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/return-analyze-if-5.sp Sat Dec 22 19:48:43 2012 -0800 @@ -0,0 +1,20 @@ +native PrintNum(num); + +f(x) +{ + if (x == 5) + return 5; + else if (x == 7) + return 9; + else + return 6; +} + +public main() +{ + PrintNum(f(5)); + PrintNum(f(7)); + PrintNum(f(2)); +} + + diff -r 6030e0b46fe2 -r 2b8512340180 tests/prototype/precall-void-used.sp --- a/tests/prototype/precall-void-used.sp Sat Dec 22 18:25:31 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -native PrintToServer(const String:str[], ...); - -f() -{ - return main(); -} - -main() -{ -} - diff -r 6030e0b46fe2 -r 2b8512340180 tests/prototype/return-analyze-for-1.sp --- a/tests/prototype/return-analyze-for-1.sp Sat Dec 22 18:25:31 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -native PrintToServer(const String:str[], ...); - -main(x) -{ - for (;;) { - } -} - -public f() -{ - return main(5); -} - - diff -r 6030e0b46fe2 -r 2b8512340180 tests/prototype/return-analyze-for-2.sp --- a/tests/prototype/return-analyze-for-2.sp Sat Dec 22 18:25:31 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -native PrintToServer(const String:str[], ...); - -main(x) -{ - for (;;) { - return 5; - } -} - -public f() -{ - return main(5); -} - - diff -r 6030e0b46fe2 -r 2b8512340180 tests/prototype/return-analyze-for-3.sp --- a/tests/prototype/return-analyze-for-3.sp Sat Dec 22 18:25:31 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -native PrintToServer(const String:str[], ...); - -main(x) -{ - for (;;) { - if (x) - return 5; - } -} - -public f() -{ - return main(5); -} - - diff -r 6030e0b46fe2 -r 2b8512340180 tests/prototype/return-analyze-for-4.sp --- a/tests/prototype/return-analyze-for-4.sp Sat Dec 22 18:25:31 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -native PrintToServer(const String:str[], ...); - -main(x) -{ - for (; x;) { - return 5; - } -} - -public f() -{ - return main(5); -} - - diff -r 6030e0b46fe2 -r 2b8512340180 tests/prototype/return-analyze-for-5.sp --- a/tests/prototype/return-analyze-for-5.sp Sat Dec 22 18:25:31 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -native PrintToServer(const String:str[], ...); - -main(x) -{ - for (; x;) { - return 5; - } - return 4; -} - -public f() -{ - return main(5); -} - - diff -r 6030e0b46fe2 -r 2b8512340180 tests/prototype/return-analyze-if-1.sp --- a/tests/prototype/return-analyze-if-1.sp Sat Dec 22 18:25:31 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -native PrintToServer(const String:str[], ...); - -main(x) -{ - if (x) - return 5; - return 2; -} - -f() -{ - return main(5); -} - - diff -r 6030e0b46fe2 -r 2b8512340180 tests/prototype/return-analyze-if-2.sp --- a/tests/prototype/return-analyze-if-2.sp Sat Dec 22 18:25:31 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -native PrintToServer(const String:str[], ...); - -main(x) -{ - if (x) - return 5; -} - -f() -{ - return main(5); -} - - diff -r 6030e0b46fe2 -r 2b8512340180 tests/prototype/return-analyze-if-3.sp --- a/tests/prototype/return-analyze-if-3.sp Sat Dec 22 18:25:31 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -native PrintToServer(const String:str[], ...); - -main(x) -{ - if (x) - return 5; - else - return 6; -} - -public f() -{ - return main(5); -} - - diff -r 6030e0b46fe2 -r 2b8512340180 tests/prototype/return-analyze-if-4.sp --- a/tests/prototype/return-analyze-if-4.sp Sat Dec 22 18:25:31 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -native PrintToServer(const String:str[], ...); - -main(x) -{ - if (x) - return 5; - else if (x) - return 6; -} - -public f() -{ - return main(5); -} - - diff -r 6030e0b46fe2 -r 2b8512340180 tests/prototype/return-analyze-if-5.sp --- a/tests/prototype/return-analyze-if-5.sp Sat Dec 22 18:25:31 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -native PrintToServer(const String:str[], ...); - -main(x) -{ - if (x) - return 5; - else if (x) - return 6; - else - return 6; -} - -public f() -{ - return main(5); -} - - diff -r 6030e0b46fe2 -r 2b8512340180 tests/test.py --- a/tests/test.py Sat Dec 22 18:25:31 2012 -0800 +++ b/tests/test.py Sat Dec 22 19:48:43 2012 -0800 @@ -29,6 +29,9 @@ i = 0 for line in f: line = line.rstrip('\r\n') + if "Displaying compilation errors for" in lines[i]: + i += 1 + continue if line != lines[i]: message = 'Got "' + lines[i] + '", expected "' + line + '"' ok = False