]> granicus.if.org Git - clang/commitdiff
Introduce CFGImplicitDtor::isNoReturn() to query whether a destructor actually return...
authorTed Kremenek <kremenek@apple.com>
Wed, 2 Mar 2011 20:32:29 +0000 (20:32 +0000)
committerTed Kremenek <kremenek@apple.com>
Wed, 2 Mar 2011 20:32:29 +0000 (20:32 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126875 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Analysis/CFG.h
lib/Analysis/CFG.cpp
lib/Sema/AnalysisBasedWarnings.cpp
test/SemaCXX/return-noreturn.cpp

index d135286d30f8a738f02686c1028bb366f1c1dcd8..992b32a6d74a86c2e2fa127037d13bd715c17c32 100644 (file)
@@ -130,6 +130,7 @@ protected:
 
 public:
   const CXXDestructorDecl *getDestructorDecl() const;
+  bool isNoReturn() const;
 
   static bool classof(const CFGElement *E) {
     Kind kind = E->getKind();
index 1357653934888abb4b605490fb39198b61c27c57..2818cf6d6206e62c4bd5523ac47cadd69d3ac085 100644 (file)
@@ -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<CFGAutomaticObjDtor>(this)->getVarDecl();
+      QualType ty = var->getType();
+      const RecordType *recordType = ty->getAs<RecordType>();
+      const CXXRecordDecl *classDecl =
+        cast<CXXRecordDecl>(recordType->getDecl());
+      return classDecl->getDestructor();      
+    }
+    case CFGElement::TemporaryDtor: {
+      const CXXBindTemporaryExpr *bindExpr =
+        cast<CFGTemporaryDtor>(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<FunctionType>(ty)->getNoReturnAttr();
+  }
+  return false;
 }
 
 //===----------------------------------------------------------------------===//
index 6a422242a9d4d9bd69da42d278488545b1ebd9fa..84efbd50d1a5b807567f91a59aa43fe1ca56ad6e 100644 (file)
@@ -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<CFGImplicitDtor>())
+        if (iDtor->isNoReturn()) {
+          hasNoReturnDtor = true;
+          HasFakeEdge = true;
+          break;
+        }
+      
       if (isa<CFGStmt>(CE))
         break;
     }
     
+    if (hasNoReturnDtor)
+      continue;
+    
     // No more CFGElements in the block?
     if (ri == re) {
       if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) {
index 7e0a69c266b53eefa53af892125919e1bbe1575e..890fb9017ca662ffa72230b44f85efcb6eeea555 100644 (file)
@@ -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;
+    }
   }
 }