diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index a247a9d194ebc8af55dceebe464a0b52db193409..77c30dd9873ba1c6ef66a9c652683ece95bc3a0f 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -320,7 +320,6 @@ private: AddStmtChoice asc); CFGBlock *VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *C, AddStmtChoice asc); - CFGBlock *VisitCXXMemberCallExpr(CXXMemberCallExpr *C, AddStmtChoice asc); CFGBlock *VisitCallExpr(CallExpr *C, AddStmtChoice asc); CFGBlock *VisitCaseStmt(CaseStmt *C); CFGBlock *VisitChooseExpr(ChooseExpr *C, AddStmtChoice asc); @@ -868,6 +867,7 @@ tryAgain: case Stmt::CallExprClass: case Stmt::CXXOperatorCallExprClass: + case Stmt::CXXMemberCallExprClass: return VisitCallExpr(cast<CallExpr>(S), asc); case Stmt::CaseStmtClass: @@ -903,9 +903,6 @@ tryAgain: case Stmt::CXXTemporaryObjectExprClass: return VisitCXXTemporaryObjectExpr(cast<CXXTemporaryObjectExpr>(S), asc); - case Stmt::CXXMemberCallExprClass: - return VisitCXXMemberCallExpr(cast<CXXMemberCallExpr>(S), asc); - case Stmt::CXXThrowExprClass: return VisitCXXThrowExpr(cast<CXXThrowExpr>(S)); @@ -1153,12 +1150,19 @@ static bool CanThrow(Expr *E, ASTContext &Ctx) { } CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) { - // If this is a call to a no-return function, this stops the block here. - bool NoReturn = false; - if (getFunctionExtInfo(*C->getCallee()->getType()).getNoReturn()) { - NoReturn = true; + // Compute the callee type. + QualType calleeType = C->getCallee()->getType(); + if (calleeType == Context->BoundMemberTy) { + QualType boundType = Expr::findBoundMemberType(C->getCallee()); + + // We should only get a null bound type if processing a dependent + // CFG. Recover by assuming nothing. + if (!boundType.isNull()) calleeType = boundType; } + // If this is a call to a no-return function, this stops the block here. + bool NoReturn = getFunctionExtInfo(*calleeType).getNoReturn(); + bool AddEHEdge = false; // Languages without exceptions are assumed to not throw. @@ -2691,13 +2695,6 @@ CFGBlock *CFGBuilder::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *C, return VisitChildren(C); } -CFGBlock *CFGBuilder::VisitCXXMemberCallExpr(CXXMemberCallExpr *C, - AddStmtChoice asc) { - autoCreateBlock(); - appendStmt(Block, C); - return VisitChildren(C); -} - CFGBlock *CFGBuilder::VisitImplicitCastExpr(ImplicitCastExpr *E, AddStmtChoice asc) { if (asc.alwaysAdd(*this, E)) { diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index e482172ca3eb94d488a638f913a48ea78ffb1547..9efae6103a4a957cfcaf110286ced604c0346a32 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -196,7 +196,12 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { continue; } Expr *CEE = C->getCallee()->IgnoreParenCasts(); - if (getFunctionExtInfo(CEE->getType()).getNoReturn()) { + QualType calleeType = CEE->getType(); + if (calleeType == AC.getASTContext().BoundMemberTy) { + calleeType = Expr::findBoundMemberType(CEE); + assert(!calleeType.isNull() && "analyzing unresolved call?"); + } + if (getFunctionExtInfo(calleeType).getNoReturn()) { NoReturnEdge = true; HasFakeEdge = true; } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) { diff --git a/test/SemaCXX/attr-noreturn.cpp b/test/SemaCXX/attr-noreturn.cpp index b7d39992b8fb1f7ff7257cb1e067a4f4a55e973e..eaf0d0c15ffd102c7c8e94dd2db1891074ec6715 100644 --- a/test/SemaCXX/attr-noreturn.cpp +++ b/test/SemaCXX/attr-noreturn.cpp @@ -1,5 +1,22 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s +// Reachability tests have to come first because they get suppressed +// if any errors have occurred. +namespace test5 { + struct A { + __attribute__((noreturn)) void fail(); + void nofail(); + } a; + + int &test1() { + a.nofail(); + } // expected-warning {{control reaches end of non-void function}} + + int &test2() { + a.fail(); + } +} + // PR5620 void f0() __attribute__((__noreturn__)); void f1(void (*)());