compiler/resolution/lowerIterators.cpp
// Adjust an error handling exit in two cases:
// 1. the GotoStmt points outside of this function
// 2. the error variable updated is outside of this function.
// In both cases, we need to change it to update this function's
// error_out argument and exit this function.
Adjust an error handling exit in two cases:
1. the GotoStmt points outside of this function
2. the error variable updated is outside of this function.
In both cases, we need to change it to update this function's
error_out argument and exit this function.
Adjust an error handling exit in two cases : 1 . the GotoStmt points outside of this function 2 . the error variable updated is outside of this function . In both cases we need to change it to update this function ' s error_out argument and exit this function .
void
fixupErrorHandlingExits(BlockStmt* body, bool& adjustCaller) {
  FnSymbol* fn = toFnSymbol(body->parentSymbol);
  INT_ASSERT(fn);
  std::vector<GotoStmt*> gotos;
  collectGotoStmts(body, gotos);
  for_vector(GotoStmt, g, gotos) {
    if (g->gotoTag == GOTO_ERROR_HANDLING ||
        g->gotoTag == GOTO_BREAK_ERROR_HANDLING ||
        g->gotoTag == GOTO_RETURN) {
      LabelSymbol* target = g->gotoTarget();
      INT_ASSERT(target->defPoint->parentSymbol);
      bool fixTarget = (target->defPoint->parentSymbol != body->parentSymbol);
      bool fixError = false;
      Expr* oldErrorSrc = NULL;
      Expr* oldErrorDst = NULL;
      CallExpr* prevMoveErr = NULL;
      Expr* cur = g->prev;
      while (cur != NULL) {
        if (CallExpr* call = toCallExpr(cur)) {
          if ((call->isPrimitive(PRIM_MOVE) ||
               call->isPrimitive(PRIM_ASSIGN)) &&
              call->get(1)->typeInfo() == dtError) {
            prevMoveErr = call;
            break;
          }
        }
        cur = cur->prev;
      }
      if (prevMoveErr != NULL) {
        oldErrorDst = prevMoveErr->get(1);
        oldErrorSrc = prevMoveErr->get(2);
        INT_ASSERT(oldErrorDst);
        INT_ASSERT(oldErrorDst->typeInfo() == dtError);
        SymExpr* dstSe = toSymExpr(oldErrorDst);
        INT_ASSERT(dstSe);
        Symbol* dstSym = dstSe->symbol();
        INT_ASSERT(dstSym->defPoint->parentSymbol);
        if (dstSym->defPoint->parentSymbol != fn)
          fixError = true;
      }
      if (fixTarget || fixError) {
        LabelSymbol* epilogue = fn->getOrCreateEpilogueLabel();
        ArgSymbol* errorArg = findErrorFormalForFn(fn);
        if (errorArg == NULL) {
          errorArg = addDummyErrorFormalToFn(fn);
          adjustCaller = true;
        }
        INT_ASSERT(errorArg != NULL);
        if (oldErrorDst && oldErrorSrc) {
          oldErrorDst->remove();
          oldErrorSrc->remove();
          prevMoveErr->replace(new CallExpr(PRIM_ASSIGN, errorArg, oldErrorSrc));
        }
        GotoStmt* newGoto = new GotoStmt(GOTO_RETURN, epilogue);
        g->replace(newGoto);
      }
    }
  }
}
void fixupErrorHandlingExits ( BlockStmt * body , bool & adjustCaller ) { FnSymbol * fn = toFnSymbol ( body -> parentSymbol ) ; INT_ASSERT ( fn ) ; std :: vector < GotoStmt * > gotos ; collectGotoStmts ( body , gotos ) ; for_vector ( GotoStmt , g , gotos ) { if ( g -> gotoTag == GOTO_ERROR_HANDLING || g -> gotoTag == GOTO_BREAK_ERROR_HANDLING || g -> gotoTag == GOTO_RETURN ) { LabelSymbol * target = g -> gotoTarget ( ) ; INT_ASSERT ( target -> defPoint -> parentSymbol ) ; bool fixTarget = ( target -> defPoint -> parentSymbol != body -> parentSymbol ) ; bool fixError = false ; Expr * oldErrorSrc = NULL ; Expr * oldErrorDst = NULL ; CallExpr * prevMoveErr = NULL ; Expr * cur = g -> prev ; while ( cur != NULL ) { if ( CallExpr * call = toCallExpr ( cur ) ) { if ( ( call -> isPrimitive ( PRIM_MOVE ) || call -> isPrimitive ( PRIM_ASSIGN ) ) && call -> get ( 1 ) -> typeInfo ( ) == dtError ) { prevMoveErr = call ; break ; } } cur = cur -> prev ; } if ( prevMoveErr != NULL ) { oldErrorDst = prevMoveErr -> get ( 1 ) ; oldErrorSrc = prevMoveErr -> get ( 2 ) ; INT_ASSERT ( oldErrorDst ) ; INT_ASSERT ( oldErrorDst -> typeInfo ( ) == dtError ) ; SymExpr * dstSe = toSymExpr ( oldErrorDst ) ; INT_ASSERT ( dstSe ) ; Symbol * dstSym = dstSe -> symbol ( ) ; INT_ASSERT ( dstSym -> defPoint -> parentSymbol ) ; if ( dstSym -> defPoint -> parentSymbol != fn ) fixError = true ; } if ( fixTarget || fixError ) { LabelSymbol * epilogue = fn -> getOrCreateEpilogueLabel ( ) ; ArgSymbol * errorArg = findErrorFormalForFn ( fn ) ; if ( errorArg == NULL ) { errorArg = addDummyErrorFormalToFn ( fn ) ; adjustCaller = true ; } INT_ASSERT ( errorArg != NULL ) ; if ( oldErrorDst && oldErrorSrc ) { oldErrorDst -> remove ( ) ; oldErrorSrc -> remove ( ) ; prevMoveErr -> replace ( new CallExpr ( PRIM_ASSIGN , errorArg , oldErrorSrc ) ) ; } GotoStmt * newGoto = new GotoStmt ( GOTO_RETURN , epilogue ) ; g -> replace ( newGoto ) ; } } } }
Adjust an error handling exit in two cases:
1. the GotoStmt points outside of this function
2. the error variable updated is outside of this function.
Adjust an error handling exit in two cases : 1 . the GotoStmt points outside of this function 2 . the error variable updated is outside of this function .
// Does the target of this Goto exist within the same function? // Do we need to fix the Goto because it points outside the function? // Do we need to fix the error handling because it uses an Error // variable outside of this function? // Find the PRIM_MOVE/PRIM_ASSIGN setting the error variable // TODO -- only consider errors with FLAG_ERROR_VAR? // Is it possible for user code to look like this? // Find the function epilogue // Find the formal to store the error // ... find the (last) error argument // Replace it with assign / goto return