diff -r 1aec996cde2d -r f7e573226c2b jitcraft/SemanticAnalysis.cpp --- a/jitcraft/SemanticAnalysis.cpp Thu Jul 12 00:38:00 2012 -0700 +++ b/jitcraft/SemanticAnalysis.cpp Sat Jul 14 18:43:34 2012 -0700 @@ -100,8 +100,8 @@ : zone_(zone), cc_(cc), tree_(tree), - loopDepth_(0), - scope_(NULL) + scope_(NULL), + loop_(NULL) { } @@ -147,18 +147,17 @@ } else if (expression->isIndexExpression()) { if (type->isArray()) expression->setType(type->contained()); + } else if (expression->isCallExpression()) { + if (type->isVoid()) { + CallExpression *call = expression->toCallExpression(); + cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue); + return NULL; + } } return expression->type(); } -Type * -SemanticAnalysis::visitForRef(Expression *expression) -{ - expression->accept(this); - return expression->type(); -} - // :TODO: this leaks an interior pointer. static inline const char * GetTypeName(Type *type) @@ -269,6 +268,14 @@ return var->type(); } +SemanticAnalysis::ControlStatus +SemanticAnalysis::visitForControl(Statement *statement) +{ + ControlScope scope(&control_); + statement->accept(this); + return scope.status(); +} + void SemanticAnalysis::visit(NameProxy *name) { @@ -332,6 +339,9 @@ void SemanticAnalysis::visit(ReturnStatement *node) { + // Set this early, so if we error we don't get more errors. + control_->returns(Returns_Always); + Local type(zone_, visitForLoad(node->expression())); if (!type) return; @@ -344,7 +354,8 @@ void SemanticAnalysis::visit(ForStatement *node) { - loopDepth_++; + LoopScope loop(&loop_); + if (node->scope()) scope_ = node->scope(); @@ -354,7 +365,6 @@ if (node->condition()) { Local type(zone_, visitForLoad(node->condition())); if (!type || !canTest(node->condition(), type)) { - loopDepth_--; return; } } @@ -362,26 +372,48 @@ if (node->update()) node->update()->accept(this); - node->body()->accept(this); + ControlStatus status = visitForControl(node->body()); + + // If there is a condition, we treat this like a while loop. Otherwise, + // 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()); if (node->scope()) scope_ = scope_->enclosing(); - loopDepth_--; } void SemanticAnalysis::visit(WhileStatement *node) { - loopDepth_++; + LoopScope loop(&loop_); Local type(zone_, visitForLoad(node->condition())); if (!type || !canTest(node->condition(), type)) { - loopDepth_--; return; } - node->body()->accept(this); - loopDepth_--; + ControlStatus status = visitForControl(node->body()); + + // Detect loops that will always have a fork in the control-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()); + } } void @@ -408,7 +440,7 @@ if (node->postDimensions()) { Local init(zone_); if (node->initialization()) { - if ((init = visitAndApplyType(node->initialization())) == NULL) + if ((init = visitForLoad(node->initialization())) == NULL) return; } @@ -527,7 +559,7 @@ void SemanticAnalysis::visit(ExpressionStatement *node) { - node->expression()->accept(this); + visitAndApplyType(node->expression()); } bool @@ -597,7 +629,11 @@ parameter->variable()->setType(type); } - Local returnType(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32)); + Local returnType(zone_); + if (node->hasExplicitReturn()) + returnType = zone_->types()->getPrimitive(PrimitiveType_Int32); + else + returnType = zone_->types()->getVoid(); if (!returnType) return false; @@ -630,8 +666,20 @@ { function_ = node->fun()->type(); scope_ = node->scope(); - if (node->body()) + + ControlScope control(&control_); + if (node->body()) { node->body()->accept(this); + + ControlStatus status = control.status(); + if (status.returns() == Returns_Sometimes) { + cc_.reportError(node->pos(), Message_NotAllPathsReturnValue); + } else if (status.returns() == Returns_Never) { + if (!function_->returnType()->isVoid()) + cc_.reportError(node->pos(), Message_MissingReturnValue); + } + } + scope_ = NULL; function_ = NULL; } @@ -772,6 +820,14 @@ if (!given) return; + // Since we skip a load, check for a call expression that returns void. + if (given->isVoid()) { + assert(expression->isCallExpression()); + CallExpression *call = expression->toCallExpression(); + cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue); + return; + } + // If it's an IndexExpression, we special case the ability to compute // a reference. if (expression->isIndexExpression()) @@ -801,6 +857,25 @@ } 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); +} + +void SemanticAnalysis::visit(IfStatement *node) { Local type(zone_, visitForLoad(node->condition())); @@ -810,15 +885,19 @@ if (!canTest(node, type)) return; - node->ifTrue()->accept(this); + ControlStatus trueBranch = visitForControl(node->ifTrue()); + ControlStatus falseBranch = ControlStatus(false, Returns_Never); + if (node->ifFalse()) - node->ifFalse()->accept(this); + falseBranch = visitForControl(node->ifFalse()); + + control_->merge(trueBranch, falseBranch); } void SemanticAnalysis::visit(IndexExpression *node) { - Local left(zone_, visitForRef(node->left())); + Local left(zone_, visitForLoad(node->left())); Local right(zone_, visitForLoad(node->right())); if (!left || !right) @@ -901,13 +980,29 @@ void SemanticAnalysis::visit(BreakStatement *node) { - if (loopDepth_ == 0) + if (!loop_) { cc_.reportError(node->pos(), Message_BreakOutsideLoop); + return; + } + + // Note: ignore breaks that occur in unreachable control-flow. + if (!control_->status().terminates()) + loop_->addBreak(); + + control_->terminate(Returns_Never); } void SemanticAnalysis::visit(ContinueStatement *node) { - if (loopDepth_ == 0) + if (!loop_) { cc_.reportError(node->pos(), Message_ContinueOutsideLoop); + return; + } + + // Note: ignore continues that occur in unreachable control-flow. + if (!control_->status().terminates()) + loop_->addContinue(); + + control_->terminate(Returns_Never); }