1.1 --- a/src/compiler/SemanticAnalysis.cpp Sat Dec 22 18:25:31 2012 -0800
1.2 +++ b/src/compiler/SemanticAnalysis.cpp Sat Dec 22 19:48:43 2012 -0800
1.3 @@ -79,7 +79,8 @@
1.4 emitter_(pool_),
1.5 module_(parent->module_),
1.6 fun_(fun),
1.7 - loop_(NULL)
1.8 + loop_(NULL),
1.9 + control_(NULL)
1.10 {
1.11
1.12 }
1.13 @@ -167,8 +168,21 @@
1.14 }
1.15
1.16 AutoEnterScope varScope(&scope_, stmt->varScope());
1.17 + ControlStatus status = visitForControl(stmt->body());
1.18
1.19 - stmt->body()->accept(this);
1.20 + if (!fun_->returnType()->isVoid()) {
1.21 + // If the function is not void, report if not all paths return a value.
1.22 + // All other incorrect return cases have been caught already.
1.23 + if (status.returns() == Returns_Sometimes) {
1.24 + cc_.reportError(stmt->pos(), Message_NotAllPathsReturnValue);
1.25 + return NULL;
1.26 + }
1.27 +
1.28 + if (status.returns() == Returns_Never) {
1.29 + cc_.reportError(stmt->pos(), Message_MissingReturnValue);
1.30 + return NULL;
1.31 + }
1.32 + }
1.33
1.34 Local<Code> code(zone_, __ finish());
1.35 if (!code)
1.36 @@ -217,28 +231,60 @@
1.37 }
1.38
1.39 void
1.40 +SemanticAnalysis::ControlScope::merge(const ControlStatus &left, const ControlStatus &right)
1.41 +{
1.42 + // If both sides terminate in a return, we consider this a return as well.
1.43 + if (left.returns() == Returns_Always && right.returns() == Returns_Always) {
1.44 + terminate(Returns_Always);
1.45 + return;
1.46 + }
1.47 +
1.48 + ReturnStatus status = (left.returns() == Returns_Never && right.returns() == Returns_Never)
1.49 + ? Returns_Never
1.50 + : Returns_Sometimes;
1.51 +
1.52 + if (left.terminates() && right.terminates())
1.53 + terminate(status);
1.54 + else
1.55 + returns(status);
1.56 +}
1.57 +
1.58 +SemanticAnalysis::ControlStatus
1.59 +SemanticAnalysis::visitForControl(Statement *statement)
1.60 +{
1.61 + ControlScope scope(&control_);
1.62 + statement->accept(this);
1.63 + return scope.status();
1.64 +}
1.65 +
1.66 +void
1.67 SemanticAnalysis::visitIfStatement(IfStatement *node)
1.68 {
1.69 Label join;
1.70
1.71 + ControlStatus trueBranch;
1.72 + ControlStatus falseBranch(false, Returns_Never);
1.73 +
1.74 if (!node->ifFalse()) {
1.75 Label success;
1.76
1.77 visitForTest(node->condition(), &success, &join, &success);
1.78 __ bind(&success);
1.79 - node->ifTrue()->accept(this);
1.80 + trueBranch = visitForControl(node->ifTrue());
1.81 } else {
1.82 Label success, next;
1.83
1.84 visitForTest(node->condition(), &success, &next, &success);
1.85 __ bind(&success);
1.86 - node->ifTrue()->accept(this);
1.87 + trueBranch = visitForControl(node->ifTrue());
1.88 __ jump(&join);
1.89 __ bind(&next);
1.90 - node->ifFalse()->accept(this);
1.91 + falseBranch = visitForControl(node->ifFalse());
1.92 }
1.93
1.94 __ bind(&join);
1.95 +
1.96 + control_->merge(trueBranch, falseBranch);
1.97 }
1.98
1.99 void
1.100 @@ -250,7 +296,7 @@
1.101 loop_->setUsesLifoStack();
1.102 }
1.103
1.104 -void
1.105 +SemanticAnalysis::ControlStatus
1.106 SemanticAnalysis::visitLoopBody(Statement *stmt)
1.107 {
1.108 // We always mark off a loop body, so on each edge, we can balance the
1.109 @@ -264,11 +310,13 @@
1.110 // possibility that a long-running loop will overflow the LIFO region
1.111 // and therefore start requiring nursery allocations.
1.112 int pos = __ enterloop();
1.113 - stmt->accept(this);
1.114 + ControlStatus status = visitForControl(stmt);
1.115 __ leaveloop();
1.116
1.117 if (loop_->usesLifoStack())
1.118 __ setLoopUsesLifoStack(pos);
1.119 +
1.120 + return status;
1.121 }
1.122
1.123 void
1.124 @@ -289,7 +337,7 @@
1.125 __ jump(&test);
1.126
1.127 __ bind(&header);
1.128 - visitLoopBody(node->body());
1.129 + ControlStatus status = visitLoopBody(node->body());
1.130
1.131 __ bind(&update);
1.132 if (node->update())
1.133 @@ -303,6 +351,14 @@
1.134 }
1.135
1.136 __ bind(&join);
1.137 +
1.138 + // If there was a condition, we treat this like a while loop. Otherwise,
1.139 + // the join point is only reachable if the loop contains a break. The
1.140 + // termination status doesn't tell us anything yet.
1.141 + if (node->condition() || loop.breaks())
1.142 + control_->merge(status, ControlStatus(false, Returns_Never));
1.143 + else
1.144 + control_->terminate(status.returns());
1.145
1.146 assert(__ stackDepth() == 0);
1.147 }
1.148 @@ -317,19 +373,34 @@
1.149
1.150 __ bind(&header);
1.151
1.152 + ControlStatus status;
1.153 +
1.154 LoopScope loop(scope_, &join, &header, &loop_);
1.155 if (node->token() == TOK_WHILE) {
1.156 Label body;
1.157 visitForTest(node->condition(), &body, &join, &body);
1.158 - visitLoopBody(node->body());
1.159 + status = visitLoopBody(node->body());
1.160 __ jump(&header);
1.161 } else {
1.162 - visitLoopBody(node->body());
1.163 + status = visitLoopBody(node->body());
1.164 visitForTest(node->condition(), &header, &join, &join);
1.165 }
1.166
1.167 __ bind(&join);
1.168
1.169 + // Detect loops that will always have a fork in the contro-flow graph.
1.170 + // This will be a |while| loop, or a |do-while| loop whose body does
1.171 + // not terminate. For now, we treat these as an |if| regardless of the
1.172 + // direction the branch can take. That means the control-flow is always
1.173 + // conditional.
1.174 + if (node->token() == TOK_WHILE || status.terminates() || loop.breaks()) {
1.175 + control_->merge(status, ControlStatus(false, Returns_Never));
1.176 + } else {
1.177 + // At this point, we've got a do-while loop with a |return| or
1.178 + // |continue|, meaning that the rest of the block is unreachable.
1.179 + control_->terminate(status.returns());
1.180 + }
1.181 +
1.182 assert(__ stackDepth() == 0);
1.183 }
1.184
1.185 @@ -398,9 +469,11 @@
1.186 void
1.187 SemanticAnalysis::visitReturnStatement(ReturnStatement *node)
1.188 {
1.189 + control_->returns(Returns_Always);
1.190 +
1.191 if (!node->expression()) {
1.192 if (!fun_->returnType()->isVoid()) {
1.193 - cc_.reportError(node->pos(), Message_UsedVoidReturn);
1.194 + cc_.reportError(node->pos(), Message_MissingReturnValue);
1.195 return;
1.196 }
1.197
1.198 @@ -408,6 +481,11 @@
1.199 return;
1.200 }
1.201
1.202 + if (fun_->returnType()->isVoid()) {
1.203 + cc_.reportError(node->pos(), Message_UsedVoidReturn);
1.204 + return;
1.205 + }
1.206 +
1.207 PoolScope poolScope(zone_->pool());
1.208 RootScope rootScope(zone_);
1.209
1.210 @@ -420,7 +498,11 @@
1.211 return;
1.212
1.213 discharge(hir);
1.214 - __ return_();
1.215 +
1.216 + if (hir->type()->isVoid())
1.217 + __ returnvoid();
1.218 + else
1.219 + __ return_();
1.220 }
1.221
1.222 void
1.223 @@ -601,6 +683,7 @@
1.224 return;
1.225 }
1.226
1.227 + loop_->setBreaks();
1.228 __ j(OP_BREAK, loop_->break_());
1.229 }
1.230