]> granicus.if.org Git - clang/commitdiff
Extend the Stmt AST to make it easier to look through label, default,
authorChandler Carruth <chandlerc@gmail.com>
Sat, 10 Sep 2011 00:02:34 +0000 (00:02 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Sat, 10 Sep 2011 00:02:34 +0000 (00:02 +0000)
and case statements. Use this to make the logic in the CFG builder more
robust at finding the actual statements within a compound statement,
even when there are many layers of labels obscuring it.

Also extend the test cases for a large chunk of PR10063. Still more work
to do here though.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@139437 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Stmt.h
lib/AST/Stmt.cpp
lib/Analysis/CFG.cpp
test/SemaCXX/return-noreturn.cpp

index 0e696a9781296882ad132bf903c5565f4e99b64f..34b8a12f40e98e918b8eb619b35366e48faa2e31 100644 (file)
@@ -296,6 +296,12 @@ public:
   /// statement, such as ExprWithCleanups or ImplicitCastExpr nodes.
   Stmt *IgnoreImplicit();
 
+  const Stmt *stripLabelLikeStatements() const;
+  Stmt *stripLabelLikeStatements() {
+    return const_cast<Stmt*>(
+      const_cast<const Stmt*>(this)->stripLabelLikeStatements());
+  }
+
   // Implement isa<T> support.
   static bool classof(const Stmt *) { return true; }
 
index 9e4be940110d4c511f1782fb58c81bf2f39eb721..e7b87e4db6795049e2664e849ef8549f34828337 100644 (file)
@@ -97,6 +97,22 @@ Stmt *Stmt::IgnoreImplicit() {
   return s;
 }
 
+/// \brief Strip off all label-like statements.
+///
+/// This will strip off label statements, case statements, and default
+/// statements recursively.
+const Stmt *Stmt::stripLabelLikeStatements() const {
+  const Stmt *S = this;
+  while (true) {
+    if (const LabelStmt *LS = dyn_cast<LabelStmt>(S))
+      S = LS->getSubStmt();
+    else if (const SwitchCase *SC = dyn_cast<SwitchCase>(S))
+      S = SC->getSubStmt();
+    else
+      return S;
+  }
+}
+
 namespace {
   struct good {};
   struct bad {};
index 393feffdadad9b9684badcfd98e75e748ff93926..d385420a56770e3211df6461996995646bea2c7a 100644 (file)
@@ -723,9 +723,7 @@ void CFGBuilder::addLocalScopeForStmt(Stmt *S) {
   if (CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) {
     for (CompoundStmt::body_iterator BI = CS->body_begin(), BE = CS->body_end()
         ; BI != BE; ++BI) {
-      Stmt *SI = *BI;
-      if (LabelStmt *LS = dyn_cast<LabelStmt>(SI))
-        SI = LS->getSubStmt();
+      Stmt *SI = (*BI)->stripLabelLikeStatements();
       if (DeclStmt *DS = dyn_cast<DeclStmt>(SI))
         Scope = addLocalScopeForDeclStmt(DS, Scope);
     }
@@ -734,9 +732,7 @@ void CFGBuilder::addLocalScopeForStmt(Stmt *S) {
 
   // For any other statement scope will be implicit and as such will be
   // interesting only for DeclStmt.
-  if (LabelStmt *LS = dyn_cast<LabelStmt>(S))
-    S = LS->getSubStmt();
-  if (DeclStmt *DS = dyn_cast<DeclStmt>(S))
+  if (DeclStmt *DS = dyn_cast<DeclStmt>(S->stripLabelLikeStatements()))
     addLocalScopeForDeclStmt(DS);
 }
 
index 53ed0d724527231a80e5339d1d2749517987abbd..1a10c2aa1687cbb81649c6b10ff804b5303a8a91 100644 (file)
@@ -8,23 +8,37 @@ 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}}
+// Ensure that destructors from objects are properly modeled in the CFG despite
+// the presence of switches, case statements, labels, and blocks. These tests
+// try to cover bugs reported in both PR6884 and PR10063.
+namespace abort_struct_complex_cfgs {
+  int basic(int x) {
+    switch (x) { default: pr6884_abort(); }
+  }
+  int f1(int x) {
+    switch (x) default: pr6884_abort_struct();
+  }
+  int f2(int x) {
+    switch (x) { default: pr6884_abort_struct(); }
+  }
+  int f2_positive(int x) {
+    switch (x) { default: ; }
+  } // expected-warning {{control reaches end of non-void function}}
+  int f3(int x) {
+    switch (x) { default: { pr6884_abort_struct(); } }
+  }
+  int f4(int x) {
+    switch (x) default: L1: L2: case 4: pr6884_abort_struct();
+  }
+  int f5(int x) {
+    switch (x) default: L1: { L2: case 4: pr6884_abort_struct(); }
+  }
+  int f6(int x) {
+    switch (x) default: L1: L2: case 4: { pr6884_abort_struct(); }
+  }
 
-int pr6884_h(int x) {
-  switch (x) {
-    default: {
-      pr6884_abort_struct a;
-    }
+  int h(int x) {
+    switch (x) { default: { pr6884_abort_struct a; } }
   }
 }