Re-introduce definite return analysis.
Re-introduce definite return analysis.
1.1 --- a/include/keima.h Sat Dec 22 18:25:31 2012 -0800
1.2 +++ b/include/keima.h Sat Dec 22 19:48:43 2012 -0800
1.3 @@ -467,7 +467,7 @@
1.4 /*
1.5 * Compiles a file and returns a Module.
1.6 */
1.7 -extern Local<Module> Compile(const char *path);
1.8 +extern bool Compile(const char *path);
1.9
1.10 class Internals
1.11 {
2.1 --- a/src/API.cpp Sat Dec 22 18:25:31 2012 -0800
2.2 +++ b/src/API.cpp Sat Dec 22 19:48:43 2012 -0800
2.3 @@ -91,7 +91,7 @@
2.4 return Ke::Local<To>(reinterpret_cast<To *>(Ke::HandleScope::CreateHandle(from)));
2.5 }
2.6
2.7 -ke::Module *
2.8 +bool
2.9 InternalCompile(const char *path)
2.10 {
2.11 PoolScope poolScope(ZONE()->pool());
2.12 @@ -102,36 +102,20 @@
2.13 unit->path_ = path;
2.14
2.15 if (!cc.addTranslationUnit(unit))
2.16 - return NULL;
2.17 + return false;
2.18
2.19 if (!cc.compile())
2.20 - return NULL;
2.21 -
2.22 - return NULL;
2.23 + return false;
2.24
2.25 -#if 0
2.26 - ke::Local<ke::Module> module(ZONE(), CompileFromSource(cc, path, bytes, length));
2.27 - delete [] bytes;
2.28 - if (!module)
2.29 - return NULL;
2.30 -
2.31 - ke::Local<ke::String> pathstr(ZONE(), ke::String::New(ZONE(), path, Heap::Tenure_Old));
2.32 - if (!pathstr)
2.33 - return NULL;
2.34 -
2.35 - module->setPath(pathstr);
2.36 - return module;
2.37 -#endif
2.38 - return NULL;
2.39 + return true;
2.40 }
2.41
2.42 // This is split out from InternalCompile so the RootScope doesn't conflict
2.43 // with making a return handle.
2.44 -Ke::Local<Ke::Module>
2.45 +bool
2.46 Ke::Compile(const char *path)
2.47 {
2.48 - ke::Local<ke::Module> module(ZONE(), InternalCompile(path));
2.49 - return ToLocal<ke::Module, Ke::Module>(module);
2.50 + return InternalCompile(path);
2.51 }
2.52
2.53 void
3.1 --- a/src/Messages.tbl Sat Dec 22 18:25:31 2012 -0800
3.2 +++ b/src/Messages.tbl Sat Dec 22 19:48:43 2012 -0800
3.3 @@ -53,9 +53,9 @@
3.4 MSG(NativeNotBound, TypeError, "attempted to call unbound native \"%s\"")
3.5 MSG(AllocationOverflow, SystemError, "allocation request overflowed")
3.6 MSG(TooMuchRecursion, SystemError, "stack overflow: too much recursion")
3.7 -MSG(MissingReturnValue, SyntaxError, "tagged function must return a value")
3.8 +MSG(MissingReturnValue, SyntaxError, "function must return a value")
3.9 MSG(NotAllPathsReturnValue, SyntaxError, "not all paths through function return a value")
3.10 -MSG(UsedVoidReturn, SyntaxError, "return value expected, but function does not return a value")
3.11 +MSG(UsedVoidReturn, SyntaxError, "value returned, but function is void")
3.12 MSG(FunctionDoesNotReturnValue, SyntaxError, "cannot use the result of a function with no return value")
3.13 MSG(IdentifierNotFound, SyntaxError, "identifier '%s' could not be found")
3.14 MSG(TypeMismatchDuringInvoke, TypeError, "incoming type '%s' does not match signature type '%s'")
4.1 --- a/src/Stack.cpp Sat Dec 22 18:25:31 2012 -0800
4.2 +++ b/src/Stack.cpp Sat Dec 22 19:48:43 2012 -0800
4.3 @@ -201,15 +201,15 @@
4.4 top_.fp = top_.fp->prev();
4.5 }
4.6
4.7 -void
4.8 -Frame::enterLoop(Zone *zone)
4.9 -{
4.10 - assert(loopDepth_ < code_->maxLoopDepth());
4.11 - loopStack()[loopDepth_] = zone->heap().lifoPosition();
4.12 - loopDepth_++;
4.13 -}
4.14 -
4.15 -void
4.16 +void
4.17 +Frame::enterLoop(Zone *zone)
4.18 +{
4.19 + assert(loopDepth_ < code_->maxLoopDepth());
4.20 + loopStack()[loopDepth_] = zone->heap().lifoPosition();
4.21 + loopDepth_++;
4.22 +}
4.23 +
4.24 +void
4.25 Frame::leaveLoop(Zone *zone)
4.26 {
4.27 assert(loopDepth_ > 0);
5.1 --- a/src/compiler/CompileContext.cpp Sat Dec 22 18:25:31 2012 -0800
5.2 +++ b/src/compiler/CompileContext.cpp Sat Dec 22 19:48:43 2012 -0800
5.3 @@ -239,6 +239,9 @@
5.4 if (!zone_->stack().pushModuleFrame(unit->module_, args))
5.5 assert(false);
5.6
5.7 + if (failures_)
5.8 + return false;
5.9 +
5.10 ke::LocalSlot slot;
5.11 if (!Interpret(zone_, NULL, &slot))
5.12 assert(false);
6.1 --- a/src/compiler/SemanticAnalysis.cpp Sat Dec 22 18:25:31 2012 -0800
6.2 +++ b/src/compiler/SemanticAnalysis.cpp Sat Dec 22 19:48:43 2012 -0800
6.3 @@ -79,7 +79,8 @@
6.4 emitter_(pool_),
6.5 module_(parent->module_),
6.6 fun_(fun),
6.7 - loop_(NULL)
6.8 + loop_(NULL),
6.9 + control_(NULL)
6.10 {
6.11
6.12 }
6.13 @@ -167,8 +168,21 @@
6.14 }
6.15
6.16 AutoEnterScope varScope(&scope_, stmt->varScope());
6.17 + ControlStatus status = visitForControl(stmt->body());
6.18
6.19 - stmt->body()->accept(this);
6.20 + if (!fun_->returnType()->isVoid()) {
6.21 + // If the function is not void, report if not all paths return a value.
6.22 + // All other incorrect return cases have been caught already.
6.23 + if (status.returns() == Returns_Sometimes) {
6.24 + cc_.reportError(stmt->pos(), Message_NotAllPathsReturnValue);
6.25 + return NULL;
6.26 + }
6.27 +
6.28 + if (status.returns() == Returns_Never) {
6.29 + cc_.reportError(stmt->pos(), Message_MissingReturnValue);
6.30 + return NULL;
6.31 + }
6.32 + }
6.33
6.34 Local<Code> code(zone_, __ finish());
6.35 if (!code)
6.36 @@ -217,28 +231,60 @@
6.37 }
6.38
6.39 void
6.40 +SemanticAnalysis::ControlScope::merge(const ControlStatus &left, const ControlStatus &right)
6.41 +{
6.42 + // If both sides terminate in a return, we consider this a return as well.
6.43 + if (left.returns() == Returns_Always && right.returns() == Returns_Always) {
6.44 + terminate(Returns_Always);
6.45 + return;
6.46 + }
6.47 +
6.48 + ReturnStatus status = (left.returns() == Returns_Never && right.returns() == Returns_Never)
6.49 + ? Returns_Never
6.50 + : Returns_Sometimes;
6.51 +
6.52 + if (left.terminates() && right.terminates())
6.53 + terminate(status);
6.54 + else
6.55 + returns(status);
6.56 +}
6.57 +
6.58 +SemanticAnalysis::ControlStatus
6.59 +SemanticAnalysis::visitForControl(Statement *statement)
6.60 +{
6.61 + ControlScope scope(&control_);
6.62 + statement->accept(this);
6.63 + return scope.status();
6.64 +}
6.65 +
6.66 +void
6.67 SemanticAnalysis::visitIfStatement(IfStatement *node)
6.68 {
6.69 Label join;
6.70
6.71 + ControlStatus trueBranch;
6.72 + ControlStatus falseBranch(false, Returns_Never);
6.73 +
6.74 if (!node->ifFalse()) {
6.75 Label success;
6.76
6.77 visitForTest(node->condition(), &success, &join, &success);
6.78 __ bind(&success);
6.79 - node->ifTrue()->accept(this);
6.80 + trueBranch = visitForControl(node->ifTrue());
6.81 } else {
6.82 Label success, next;
6.83
6.84 visitForTest(node->condition(), &success, &next, &success);
6.85 __ bind(&success);
6.86 - node->ifTrue()->accept(this);
6.87 + trueBranch = visitForControl(node->ifTrue());
6.88 __ jump(&join);
6.89 __ bind(&next);
6.90 - node->ifFalse()->accept(this);
6.91 + falseBranch = visitForControl(node->ifFalse());
6.92 }
6.93
6.94 __ bind(&join);
6.95 +
6.96 + control_->merge(trueBranch, falseBranch);
6.97 }
6.98
6.99 void
6.100 @@ -250,7 +296,7 @@
6.101 loop_->setUsesLifoStack();
6.102 }
6.103
6.104 -void
6.105 +SemanticAnalysis::ControlStatus
6.106 SemanticAnalysis::visitLoopBody(Statement *stmt)
6.107 {
6.108 // We always mark off a loop body, so on each edge, we can balance the
6.109 @@ -264,11 +310,13 @@
6.110 // possibility that a long-running loop will overflow the LIFO region
6.111 // and therefore start requiring nursery allocations.
6.112 int pos = __ enterloop();
6.113 - stmt->accept(this);
6.114 + ControlStatus status = visitForControl(stmt);
6.115 __ leaveloop();
6.116
6.117 if (loop_->usesLifoStack())
6.118 __ setLoopUsesLifoStack(pos);
6.119 +
6.120 + return status;
6.121 }
6.122
6.123 void
6.124 @@ -289,7 +337,7 @@
6.125 __ jump(&test);
6.126
6.127 __ bind(&header);
6.128 - visitLoopBody(node->body());
6.129 + ControlStatus status = visitLoopBody(node->body());
6.130
6.131 __ bind(&update);
6.132 if (node->update())
6.133 @@ -303,6 +351,14 @@
6.134 }
6.135
6.136 __ bind(&join);
6.137 +
6.138 + // If there was a condition, we treat this like a while loop. Otherwise,
6.139 + // the join point is only reachable if the loop contains a break. The
6.140 + // termination status doesn't tell us anything yet.
6.141 + if (node->condition() || loop.breaks())
6.142 + control_->merge(status, ControlStatus(false, Returns_Never));
6.143 + else
6.144 + control_->terminate(status.returns());
6.145
6.146 assert(__ stackDepth() == 0);
6.147 }
6.148 @@ -317,19 +373,34 @@
6.149
6.150 __ bind(&header);
6.151
6.152 + ControlStatus status;
6.153 +
6.154 LoopScope loop(scope_, &join, &header, &loop_);
6.155 if (node->token() == TOK_WHILE) {
6.156 Label body;
6.157 visitForTest(node->condition(), &body, &join, &body);
6.158 - visitLoopBody(node->body());
6.159 + status = visitLoopBody(node->body());
6.160 __ jump(&header);
6.161 } else {
6.162 - visitLoopBody(node->body());
6.163 + status = visitLoopBody(node->body());
6.164 visitForTest(node->condition(), &header, &join, &join);
6.165 }
6.166
6.167 __ bind(&join);
6.168
6.169 + // Detect loops that will always have a fork in the contro-flow graph.
6.170 + // This will be a |while| loop, or a |do-while| loop whose body does
6.171 + // not terminate. For now, we treat these as an |if| regardless of the
6.172 + // direction the branch can take. That means the control-flow is always
6.173 + // conditional.
6.174 + if (node->token() == TOK_WHILE || status.terminates() || loop.breaks()) {
6.175 + control_->merge(status, ControlStatus(false, Returns_Never));
6.176 + } else {
6.177 + // At this point, we've got a do-while loop with a |return| or
6.178 + // |continue|, meaning that the rest of the block is unreachable.
6.179 + control_->terminate(status.returns());
6.180 + }
6.181 +
6.182 assert(__ stackDepth() == 0);
6.183 }
6.184
6.185 @@ -398,9 +469,11 @@
6.186 void
6.187 SemanticAnalysis::visitReturnStatement(ReturnStatement *node)
6.188 {
6.189 + control_->returns(Returns_Always);
6.190 +
6.191 if (!node->expression()) {
6.192 if (!fun_->returnType()->isVoid()) {
6.193 - cc_.reportError(node->pos(), Message_UsedVoidReturn);
6.194 + cc_.reportError(node->pos(), Message_MissingReturnValue);
6.195 return;
6.196 }
6.197
6.198 @@ -408,6 +481,11 @@
6.199 return;
6.200 }
6.201
6.202 + if (fun_->returnType()->isVoid()) {
6.203 + cc_.reportError(node->pos(), Message_UsedVoidReturn);
6.204 + return;
6.205 + }
6.206 +
6.207 PoolScope poolScope(zone_->pool());
6.208 RootScope rootScope(zone_);
6.209
6.210 @@ -420,7 +498,11 @@
6.211 return;
6.212
6.213 discharge(hir);
6.214 - __ return_();
6.215 +
6.216 + if (hir->type()->isVoid())
6.217 + __ returnvoid();
6.218 + else
6.219 + __ return_();
6.220 }
6.221
6.222 void
6.223 @@ -601,6 +683,7 @@
6.224 return;
6.225 }
6.226
6.227 + loop_->setBreaks();
6.228 __ j(OP_BREAK, loop_->break_());
6.229 }
6.230
7.1 --- a/src/compiler/SemanticAnalysis.h Sat Dec 22 18:25:31 2012 -0800
7.2 +++ b/src/compiler/SemanticAnalysis.h Sat Dec 22 19:48:43 2012 -0800
7.3 @@ -88,8 +88,85 @@
7.4 Coerce_Assign
7.5 };
7.6
7.7 + // For a given control flow path, whether it returns.
7.8 + enum ReturnStatus
7.9 + {
7.10 + Returns_Never,
7.11 + Returns_Sometimes,
7.12 + Returns_Always
7.13 + };
7.14 +
7.15 + // For a given control flow path, whether it terminates,
7.16 + // and if it terminates, whether it returns.
7.17 + class ControlStatus
7.18 + {
7.19 + bool terminates_;
7.20 + ReturnStatus returns_;
7.21 +
7.22 + public:
7.23 + ControlStatus()
7.24 + {
7.25 + }
7.26 + ControlStatus(bool terminates, ReturnStatus returns)
7.27 + : terminates_(terminates),
7.28 + returns_(returns)
7.29 + {
7.30 + }
7.31 +
7.32 + bool terminates() const {
7.33 + return terminates_;
7.34 + }
7.35 + ReturnStatus returns() const {
7.36 + return returns_;
7.37 + }
7.38 + };
7.39 +
7.40 + class ControlScope
7.41 + {
7.42 + ReturnStatus returns_;
7.43 + ControlScope **prevp_;
7.44 + ControlScope *prev_;
7.45 + bool terminates_;
7.46 +
7.47 + public:
7.48 + ControlScope(ControlScope **prevp)
7.49 + : returns_(Returns_Never),
7.50 + prevp_(prevp),
7.51 + prev_(*prevp),
7.52 + terminates_(false)
7.53 + {
7.54 + *prevp_ = this;
7.55 + }
7.56 + ~ControlScope() {
7.57 + *prevp_ = prev_;
7.58 + }
7.59 + ControlStatus status() {
7.60 + return ControlStatus(terminates_, returns_);
7.61 + }
7.62 +
7.63 + void returns(ReturnStatus status) {
7.64 + // We allow multiple terminates, but only the first one takes
7.65 + // effect. For example, |break; continue;| is legal, but the
7.66 + // continue is unreachable.
7.67 + if (terminates_)
7.68 + return;
7.69 + if (status > returns_)
7.70 + returns_ = status;
7.71 + }
7.72 + void terminate(ReturnStatus status) {
7.73 + if (terminates_)
7.74 + return;
7.75 + terminates_ = true;
7.76 + returns_ = status;
7.77 + }
7.78 + void merge(const ControlStatus &left, const ControlStatus &right);
7.79 + void inherit(const ControlStatus &other);
7.80 + };
7.81 +
7.82 +
7.83 void requireLifoStack();
7.84 - void visitLoopBody(Statement *stmt);
7.85 + ControlStatus visitForControl(Statement *statement);
7.86 + ControlStatus visitLoopBody(Statement *stmt);
7.87 void visitForTest(Expression *expr,
7.88 BytecodeEmitter::Label *trueBranch,
7.89 BytecodeEmitter::Label *falseBranch,
7.90 @@ -117,6 +194,7 @@
7.91 LoopScope **prevp_;
7.92 LoopScope *prev_;
7.93 bool usesLifoStack_;
7.94 + bool breaks_;
7.95
7.96 public:
7.97 LoopScope(Scope *scope, BytecodeEmitter::Label *bk, BytecodeEmitter::Label *ct,
7.98 @@ -126,7 +204,8 @@
7.99 ct_(ct),
7.100 prevp_(prevp),
7.101 prev_(*prevp),
7.102 - usesLifoStack_(false)
7.103 + usesLifoStack_(false),
7.104 + breaks_(false)
7.105 {
7.106 *prevp_ = this;
7.107 }
7.108 @@ -151,6 +230,12 @@
7.109 bool usesLifoStack() const {
7.110 return usesLifoStack_;
7.111 }
7.112 + void setBreaks() {
7.113 + breaks_ = true;
7.114 + }
7.115 + bool breaks() const {
7.116 + return breaks_;
7.117 + }
7.118 };
7.119
7.120 private:
7.121 @@ -164,6 +249,7 @@
7.122 ScopedRoot<Module> module_;
7.123 ScopedRoot<FunctionType> fun_;
7.124 LoopScope *loop_;
7.125 + ControlScope *control_;
7.126 };
7.127
7.128 } // namespace ke
8.1 --- a/src/main.cpp Sat Dec 22 18:25:31 2012 -0800
8.2 +++ b/src/main.cpp Sat Dec 22 19:48:43 2012 -0800
8.3 @@ -45,7 +45,7 @@
8.4 }
8.5 }
8.6 virtual void beginCompilationErrors(const char *file) {
8.7 - fprintf(stderr, "\nDisplaying compilation errors for \"%s\"\n", file);
8.8 + fprintf(stderr, "Displaying compilation errors for \"%s\"\n", file);
8.9 }
8.10 virtual void reportCompilationError(const char *message, unsigned line, unsigned col) {
8.11 fprintf(stderr, " line %d, col %d: %s\n", line, col, message);
8.12 @@ -110,12 +110,15 @@
8.13 int rval = 0;
8.14
8.15 Keima::InstallMessageReporter(&s_Reporter);
8.16 - {
8.17 + do {
8.18 MainCollector entry;
8.19 Keima::SetPublicFunctionListener(&entry);
8.20
8.21 HandleScope scope;
8.22 - Compile(argv[1]);
8.23 + if (!Compile(argv[1])) {
8.24 + rval = 1;
8.25 + break;
8.26 + }
8.27
8.28 Keima::CollectGarbage();
8.29
8.30 @@ -131,7 +134,7 @@
8.31 if (!Keima::Invoke(fun, NULL, 0, true, &rval))
8.32 rval = 1;
8.33 }
8.34 - }
8.35 + } while (0);
8.36
8.37 Keima::Shutdown();
8.38
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/tests/basic/precall-void-used.out Sat Dec 22 19:48:43 2012 -0800
9.3 @@ -0,0 +1,1 @@
9.4 +0
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/tests/basic/precall-void-used.sp Sat Dec 22 19:48:43 2012 -0800
10.3 @@ -0,0 +1,17 @@
10.4 +native PrintNum(num);
10.5 +
10.6 +g()
10.7 +{
10.8 + PrintNum(f());
10.9 +}
10.10 +
10.11 +f()
10.12 +{
10.13 + return 0;
10.14 +}
10.15 +
10.16 +public main()
10.17 +{
10.18 + g();
10.19 +}
10.20 +
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
12.2 +++ b/tests/basic/return-analyze-for-1.sp Sat Dec 22 19:48:43 2012 -0800
12.3 @@ -0,0 +1,12 @@
12.4 +public f()
12.5 +{
12.6 + for (;;) {
12.7 + }
12.8 +}
12.9 +
12.10 +public main()
12.11 +{
12.12 +}
12.13 +
12.14 +
12.15 +
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
13.2 +++ b/tests/basic/return-analyze-for-2.out Sat Dec 22 19:48:43 2012 -0800
13.3 @@ -0,0 +1,1 @@
13.4 +5
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
14.2 +++ b/tests/basic/return-analyze-for-2.sp Sat Dec 22 19:48:43 2012 -0800
14.3 @@ -0,0 +1,16 @@
14.4 +native PrintNum(num);
14.5 +
14.6 +f()
14.7 +{
14.8 + for (;;) {
14.9 + return 5;
14.10 + }
14.11 +}
14.12 +
14.13 +public main()
14.14 +{
14.15 + PrintNum(f());
14.16 +}
14.17 +
14.18 +
14.19 +
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
15.2 +++ b/tests/basic/return-analyze-for-3.err Sat Dec 22 19:48:43 2012 -0800
15.3 @@ -0,0 +1,1 @@
15.4 + line 1, col 2: not all paths through function return a value
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
16.2 +++ b/tests/basic/return-analyze-for-3.sp Sat Dec 22 19:48:43 2012 -0800
16.3 @@ -0,0 +1,13 @@
16.4 +f(x)
16.5 +{
16.6 + for (;;) {
16.7 + if (x)
16.8 + return 5;
16.9 + }
16.10 +}
16.11 +
16.12 +public main()
16.13 +{
16.14 + f(5);
16.15 +}
16.16 +
17.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
17.2 +++ b/tests/basic/return-analyze-for-4.err Sat Dec 22 19:48:43 2012 -0800
17.3 @@ -0,0 +1,1 @@
17.4 + line 1, col 8: not all paths through function return a value
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
18.2 +++ b/tests/basic/return-analyze-for-4.sp Sat Dec 22 19:48:43 2012 -0800
18.3 @@ -0,0 +1,13 @@
18.4 +public f(x)
18.5 +{
18.6 + for (; x;) {
18.7 + return 5;
18.8 + }
18.9 +}
18.10 +
18.11 +public main()
18.12 +{
18.13 + return f(5);
18.14 +}
18.15 +
18.16 +
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
19.2 +++ b/tests/basic/return-analyze-for-5.out Sat Dec 22 19:48:43 2012 -0800
19.3 @@ -0,0 +1,1 @@
19.4 +54
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
20.2 +++ b/tests/basic/return-analyze-for-5.sp Sat Dec 22 19:48:43 2012 -0800
20.3 @@ -0,0 +1,17 @@
20.4 +native PrintNum(num);
20.5 +
20.6 +f(x)
20.7 +{
20.8 + for (; x;) {
20.9 + return 5;
20.10 + }
20.11 + return 4;
20.12 +}
20.13 +
20.14 +public main()
20.15 +{
20.16 + PrintNum(f(5));
20.17 + PrintNum(f(0));
20.18 +}
20.19 +
20.20 +
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
21.2 +++ b/tests/basic/return-analyze-if-1.out Sat Dec 22 19:48:43 2012 -0800
21.3 @@ -0,0 +1,1 @@
21.4 +25
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
22.2 +++ b/tests/basic/return-analyze-if-1.sp Sat Dec 22 19:48:43 2012 -0800
22.3 @@ -0,0 +1,16 @@
22.4 +native PrintNum(num);
22.5 +
22.6 +f(x)
22.7 +{
22.8 + if (x)
22.9 + return 5;
22.10 + return 2;
22.11 +}
22.12 +
22.13 +public main()
22.14 +{
22.15 + PrintNum(f(0));
22.16 + PrintNum(f(1));
22.17 +}
22.18 +
22.19 +
23.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
23.2 +++ b/tests/basic/return-analyze-if-2.err Sat Dec 22 19:48:43 2012 -0800
23.3 @@ -0,0 +1,1 @@
23.4 + line 3, col 3: not all paths through function return a value
24.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
24.2 +++ b/tests/basic/return-analyze-if-2.sp Sat Dec 22 19:48:43 2012 -0800
24.3 @@ -0,0 +1,14 @@
24.4 +native PrintNum(num);
24.5 +
24.6 +f(x)
24.7 +{
24.8 + if (x)
24.9 + return 5;
24.10 +}
24.11 +
24.12 +public main()
24.13 +{
24.14 + PrintNum(f(4));
24.15 +}
24.16 +
24.17 +
25.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
25.2 +++ b/tests/basic/return-analyze-if-3.out Sat Dec 22 19:48:43 2012 -0800
25.3 @@ -0,0 +1,1 @@
25.4 +65
26.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
26.2 +++ b/tests/basic/return-analyze-if-3.sp Sat Dec 22 19:48:43 2012 -0800
26.3 @@ -0,0 +1,17 @@
26.4 +native PrintNum(num);
26.5 +
26.6 +f(x)
26.7 +{
26.8 + if (x)
26.9 + return 5;
26.10 + else
26.11 + return 6;
26.12 +}
26.13 +
26.14 +public main()
26.15 +{
26.16 + PrintNum(f(0));
26.17 + PrintNum(f(1));
26.18 +}
26.19 +
26.20 +
27.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
27.2 +++ b/tests/basic/return-analyze-if-4.err Sat Dec 22 19:48:43 2012 -0800
27.3 @@ -0,0 +1,1 @@
27.4 + line 3, col 3: not all paths through function return a value
28.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
28.2 +++ b/tests/basic/return-analyze-if-4.sp Sat Dec 22 19:48:43 2012 -0800
28.3 @@ -0,0 +1,17 @@
28.4 +native PrintNum(num);
28.5 +
28.6 +f(x)
28.7 +{
28.8 + if (x)
28.9 + return 5;
28.10 + else if (x)
28.11 + return 6;
28.12 +}
28.13 +
28.14 +public main()
28.15 +{
28.16 + PrintNum(f(0));
28.17 + PrintNum(f(1));
28.18 +}
28.19 +
28.20 +
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
29.2 +++ b/tests/basic/return-analyze-if-5.out Sat Dec 22 19:48:43 2012 -0800
29.3 @@ -0,0 +1,1 @@
29.4 +596
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
30.2 +++ b/tests/basic/return-analyze-if-5.sp Sat Dec 22 19:48:43 2012 -0800
30.3 @@ -0,0 +1,20 @@
30.4 +native PrintNum(num);
30.5 +
30.6 +f(x)
30.7 +{
30.8 + if (x == 5)
30.9 + return 5;
30.10 + else if (x == 7)
30.11 + return 9;
30.12 + else
30.13 + return 6;
30.14 +}
30.15 +
30.16 +public main()
30.17 +{
30.18 + PrintNum(f(5));
30.19 + PrintNum(f(7));
30.20 + PrintNum(f(2));
30.21 +}
30.22 +
30.23 +
31.1 --- a/tests/prototype/precall-void-used.sp Sat Dec 22 18:25:31 2012 -0800
31.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
31.3 @@ -1,11 +0,0 @@
31.4 -native PrintToServer(const String:str[], ...);
31.5 -
31.6 -f()
31.7 -{
31.8 - return main();
31.9 -}
31.10 -
31.11 -main()
31.12 -{
31.13 -}
31.14 -
32.1 --- a/tests/prototype/return-analyze-for-1.sp Sat Dec 22 18:25:31 2012 -0800
32.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
32.3 @@ -1,14 +0,0 @@
32.4 -native PrintToServer(const String:str[], ...);
32.5 -
32.6 -main(x)
32.7 -{
32.8 - for (;;) {
32.9 - }
32.10 -}
32.11 -
32.12 -public f()
32.13 -{
32.14 - return main(5);
32.15 -}
32.16 -
32.17 -
33.1 --- a/tests/prototype/return-analyze-for-2.sp Sat Dec 22 18:25:31 2012 -0800
33.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
33.3 @@ -1,15 +0,0 @@
33.4 -native PrintToServer(const String:str[], ...);
33.5 -
33.6 -main(x)
33.7 -{
33.8 - for (;;) {
33.9 - return 5;
33.10 - }
33.11 -}
33.12 -
33.13 -public f()
33.14 -{
33.15 - return main(5);
33.16 -}
33.17 -
33.18 -
34.1 --- a/tests/prototype/return-analyze-for-3.sp Sat Dec 22 18:25:31 2012 -0800
34.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
34.3 @@ -1,16 +0,0 @@
34.4 -native PrintToServer(const String:str[], ...);
34.5 -
34.6 -main(x)
34.7 -{
34.8 - for (;;) {
34.9 - if (x)
34.10 - return 5;
34.11 - }
34.12 -}
34.13 -
34.14 -public f()
34.15 -{
34.16 - return main(5);
34.17 -}
34.18 -
34.19 -
35.1 --- a/tests/prototype/return-analyze-for-4.sp Sat Dec 22 18:25:31 2012 -0800
35.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
35.3 @@ -1,15 +0,0 @@
35.4 -native PrintToServer(const String:str[], ...);
35.5 -
35.6 -main(x)
35.7 -{
35.8 - for (; x;) {
35.9 - return 5;
35.10 - }
35.11 -}
35.12 -
35.13 -public f()
35.14 -{
35.15 - return main(5);
35.16 -}
35.17 -
35.18 -
36.1 --- a/tests/prototype/return-analyze-for-5.sp Sat Dec 22 18:25:31 2012 -0800
36.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
36.3 @@ -1,16 +0,0 @@
36.4 -native PrintToServer(const String:str[], ...);
36.5 -
36.6 -main(x)
36.7 -{
36.8 - for (; x;) {
36.9 - return 5;
36.10 - }
36.11 - return 4;
36.12 -}
36.13 -
36.14 -public f()
36.15 -{
36.16 - return main(5);
36.17 -}
36.18 -
36.19 -
37.1 --- a/tests/prototype/return-analyze-if-1.sp Sat Dec 22 18:25:31 2012 -0800
37.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
37.3 @@ -1,15 +0,0 @@
37.4 -native PrintToServer(const String:str[], ...);
37.5 -
37.6 -main(x)
37.7 -{
37.8 - if (x)
37.9 - return 5;
37.10 - return 2;
37.11 -}
37.12 -
37.13 -f()
37.14 -{
37.15 - return main(5);
37.16 -}
37.17 -
37.18 -
38.1 --- a/tests/prototype/return-analyze-if-2.sp Sat Dec 22 18:25:31 2012 -0800
38.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
38.3 @@ -1,14 +0,0 @@
38.4 -native PrintToServer(const String:str[], ...);
38.5 -
38.6 -main(x)
38.7 -{
38.8 - if (x)
38.9 - return 5;
38.10 -}
38.11 -
38.12 -f()
38.13 -{
38.14 - return main(5);
38.15 -}
38.16 -
38.17 -
39.1 --- a/tests/prototype/return-analyze-if-3.sp Sat Dec 22 18:25:31 2012 -0800
39.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
39.3 @@ -1,16 +0,0 @@
39.4 -native PrintToServer(const String:str[], ...);
39.5 -
39.6 -main(x)
39.7 -{
39.8 - if (x)
39.9 - return 5;
39.10 - else
39.11 - return 6;
39.12 -}
39.13 -
39.14 -public f()
39.15 -{
39.16 - return main(5);
39.17 -}
39.18 -
39.19 -
40.1 --- a/tests/prototype/return-analyze-if-4.sp Sat Dec 22 18:25:31 2012 -0800
40.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
40.3 @@ -1,16 +0,0 @@
40.4 -native PrintToServer(const String:str[], ...);
40.5 -
40.6 -main(x)
40.7 -{
40.8 - if (x)
40.9 - return 5;
40.10 - else if (x)
40.11 - return 6;
40.12 -}
40.13 -
40.14 -public f()
40.15 -{
40.16 - return main(5);
40.17 -}
40.18 -
40.19 -
41.1 --- a/tests/prototype/return-analyze-if-5.sp Sat Dec 22 18:25:31 2012 -0800
41.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
41.3 @@ -1,18 +0,0 @@
41.4 -native PrintToServer(const String:str[], ...);
41.5 -
41.6 -main(x)
41.7 -{
41.8 - if (x)
41.9 - return 5;
41.10 - else if (x)
41.11 - return 6;
41.12 - else
41.13 - return 6;
41.14 -}
41.15 -
41.16 -public f()
41.17 -{
41.18 - return main(5);
41.19 -}
41.20 -
41.21 -
42.1 --- a/tests/test.py Sat Dec 22 18:25:31 2012 -0800
42.2 +++ b/tests/test.py Sat Dec 22 19:48:43 2012 -0800
42.3 @@ -29,6 +29,9 @@
42.4 i = 0
42.5 for line in f:
42.6 line = line.rstrip('\r\n')
42.7 + if "Displaying compilation errors for" in lines[i]:
42.8 + i += 1
42.9 + continue
42.10 if line != lines[i]:
42.11 message = 'Got "' + lines[i] + '", expected "' + line + '"'
42.12 ok = False