From: Ted Kremenek Date: Wed, 2 Mar 2011 20:32:29 +0000 (+0000) Subject: Introduce CFGImplicitDtor::isNoReturn() to query whether a destructor actually return... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c9f8f5a726bbb562e4b2d4b19d66e6202dcb2657;p=clang Introduce CFGImplicitDtor::isNoReturn() to query whether a destructor actually returns. Use this for -Wreturn-type to prune false positives reported in PR 6884. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126875 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h index d135286d30..992b32a6d7 100644 --- a/include/clang/Analysis/CFG.h +++ b/include/clang/Analysis/CFG.h @@ -130,6 +130,7 @@ protected: public: const CXXDestructorDecl *getDestructorDecl() const; + bool isNoReturn() const; static bool classof(const CFGElement *E) { Kind kind = E->getKind(); diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 1357653934..2818cf6d62 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -2773,7 +2773,40 @@ CFG* CFG::buildCFG(const Decl *D, Stmt* Statement, ASTContext *C, } const CXXDestructorDecl *CFGImplicitDtor::getDestructorDecl() const { - return 0; + switch (getKind()) { + case CFGElement::Invalid: + case CFGElement::Statement: + case CFGElement::Initializer: + llvm_unreachable("getDestructorDecl should only be used with " + "ImplicitDtors"); + case CFGElement::AutomaticObjectDtor: { + const VarDecl *var = cast(this)->getVarDecl(); + QualType ty = var->getType(); + const RecordType *recordType = ty->getAs(); + const CXXRecordDecl *classDecl = + cast(recordType->getDecl()); + return classDecl->getDestructor(); + } + case CFGElement::TemporaryDtor: { + const CXXBindTemporaryExpr *bindExpr = + cast(this)->getBindTemporaryExpr(); + const CXXTemporary *temp = bindExpr->getTemporary(); + return temp->getDestructor(); + } + case CFGElement::BaseDtor: + case CFGElement::MemberDtor: + + // Not yet supported. + return 0; + } +} + +bool CFGImplicitDtor::isNoReturn() const { + if (const CXXDestructorDecl *cdecl = getDestructorDecl()) { + QualType ty = cdecl->getType(); + return cast(ty)->getNoReturnAttr(); + } + return false; } //===----------------------------------------------------------------------===// diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index 6a422242a9..84efbd50d1 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -129,12 +129,27 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { // normal. We need to look pass the destructors for the return // statement (if it exists). CFGBlock::const_reverse_iterator ri = B.rbegin(), re = B.rend(); + bool hasNoReturnDtor = false; + for ( ; ri != re ; ++ri) { CFGElement CE = *ri; + + // FIXME: The right solution is to just sever the edges in the + // CFG itself. + if (const CFGImplicitDtor *iDtor = ri->getAs()) + if (iDtor->isNoReturn()) { + hasNoReturnDtor = true; + HasFakeEdge = true; + break; + } + if (isa(CE)) break; } + if (hasNoReturnDtor) + continue; + // No more CFGElements in the block? if (ri == re) { if (B.getTerminator() && isa(B.getTerminator())) { diff --git a/test/SemaCXX/return-noreturn.cpp b/test/SemaCXX/return-noreturn.cpp index 7e0a69c266..890fb9017c 100644 --- a/test/SemaCXX/return-noreturn.cpp +++ b/test/SemaCXX/return-noreturn.cpp @@ -1,18 +1,29 @@ // RUN: %clang_cc1 %s -fsyntax-only -verify -Wreturn-type -Wmissing-noreturn -Wno-unreachable-code -// XFAIL: * // A destructor may be marked noreturn and should still influence the CFG. -namespace PR6884 { - struct abort_struct { - abort_struct() {} // Make this non-POD so the destructor is invoked. - ~abort_struct() __attribute__((noreturn)); - }; +void pr6884_abort() __attribute__((noreturn)); - int f() { - abort_struct(); - } +struct pr6884_abort_struct { + pr6884_abort_struct() {} + ~pr6884_abort_struct() __attribute__((noreturn)) { pr6884_abort(); } +}; + +int pr6884_f(int x) { + switch (x) { default: pr6884_abort(); } +} + +int pr6884_g(int x) { + switch (x) { default: pr6884_abort_struct(); } +} + +int pr6884_g_positive(int x) { + switch (x) { default: ; } +} // expected-warning {{control reaches end of non-void function}} - int f2() { - abort_struct s; +int pr6884_h(int x) { + switch (x) { + default: { + pr6884_abort_struct a; + } } }