예제 #1
0
static void diagnoseMissingReturn(const UnreachableInst *UI,
                                  ASTContext &Context) {
  const SILBasicBlock *BB = UI->getParent();
  const SILFunction *F = BB->getParent();
  SILLocation FLoc = F->getLocation();

  Type ResTy;

  if (auto *FD = FLoc.getAsASTNode<FuncDecl>()) {
    ResTy = FD->getResultType();
  } else if (auto *CE = FLoc.getAsASTNode<ClosureExpr>()) {
    ResTy = CE->getResultType();
  } else {
    llvm_unreachable("unhandled case in MissingReturn");
  }

  bool isNoReturn = F->getLoweredFunctionType()->isNoReturn();

  // No action required if the function returns 'Void' or that the
  // function is marked 'noreturn'.
  if (ResTy->isVoid() || isNoReturn)
    return;

  SILLocation L = UI->getLoc();
  assert(L && ResTy);
  diagnose(Context,
           L.getEndSourceLoc(),
           diag::missing_return, ResTy,
           FLoc.isASTNode<ClosureExpr>() ? 1 : 0);
}
예제 #2
0
static void diagnoseMissingReturn(const UnreachableInst *UI,
                                  ASTContext &Context) {
  const SILBasicBlock *BB = UI->getParent();
  const SILFunction *F = BB->getParent();
  SILLocation FLoc = F->getLocation();

  Type ResTy;
  BraceStmt *BS;

  if (auto *FD = FLoc.getAsASTNode<FuncDecl>()) {
    ResTy = FD->getResultInterfaceType();
    BS = FD->getBody(/*canSynthesize=*/false);
  } else if (auto *CD = FLoc.getAsASTNode<ConstructorDecl>()) {
    ResTy = CD->getResultInterfaceType();
    BS = FD->getBody();
  } else if (auto *CE = FLoc.getAsASTNode<ClosureExpr>()) {
    ResTy = CE->getResultType();
    BS = CE->getBody();
  } else {
    llvm_unreachable("unhandled case in MissingReturn");
  }

  SILLocation L = UI->getLoc();
  assert(L && ResTy);
  auto numElements = BS->getNumElements();
  if (numElements > 0) {
    auto element = BS->getElement(numElements - 1);
    if (auto expr = element.dyn_cast<Expr *>()) {
      if (expr->getType()->getCanonicalType() == ResTy->getCanonicalType()) {
        Context.Diags.diagnose(
          expr->getStartLoc(),
          diag::missing_return_last_expr, ResTy,
          FLoc.isASTNode<ClosureExpr>() ? 1 : 0)
        .fixItInsert(expr->getStartLoc(), "return ");
        return;
      }
    }
  }
  auto diagID = F->isNoReturnFunction() ? diag::missing_never_call
                                        : diag::missing_return;
  diagnose(Context,
           L.getEndSourceLoc(),
           diagID, ResTy,
           FLoc.isASTNode<ClosureExpr>() ? 1 : 0);
}
예제 #3
0
static void diagnoseUnreachable(const SILInstruction *I,
                                ASTContext &Context) {
  if (auto *UI = dyn_cast<UnreachableInst>(I)){
    SILLocation L = UI->getLoc();

    // Invalid location means that the instruction has been generated by SIL
    // passes, such as DCE. FIXME: we might want to just introduce a separate
    // instruction kind, instead of keeping this invariant.
    //
    // We also do not want to emit diagnostics for code that was
    // transparently inlined. We should have already emitted these
    // diagnostics when we process the callee function prior to
    // inlining it.
    if (!L.hasASTLocation() || L.is<MandatoryInlinedLocation>())
      return;

    // The most common case of getting an unreachable instruction is a
    // missing return statement. In this case, we know that the instruction
    // location will be the enclosing function.
    if (L.isASTNode<AbstractFunctionDecl>() || L.isASTNode<ClosureExpr>()) {
      diagnoseMissingReturn(UI, Context);
      return;
    }

    // A non-exhaustive switch would also produce an unreachable instruction.
    if (L.isASTNode<SwitchStmt>()) {
      diagnose(Context, L.getEndSourceLoc(), diag::non_exhaustive_switch);
      return;
    }

    if (auto *Guard = L.getAsASTNode<GuardStmt>()) {
      diagnose(Context, Guard->getBody()->getEndLoc(),
               diag::guard_body_must_not_fallthrough);
      return;
    }
  }
}