diff options
-rw-r--r-- | include/clang/AST/Stmt.h | 6 | ||||
-rw-r--r-- | lib/AST/Stmt.cpp | 16 | ||||
-rw-r--r-- | lib/Analysis/CFG.cpp | 8 | ||||
-rw-r--r-- | test/SemaCXX/return-noreturn.cpp | 46 |
4 files changed, 54 insertions, 22 deletions
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 0e696a9781..34b8a12f40 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -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; } diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 9e4be94011..e7b87e4db6 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -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 {}; diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 393feffdad..d385420a56 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -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); } diff --git a/test/SemaCXX/return-noreturn.cpp b/test/SemaCXX/return-noreturn.cpp index 53ed0d7245..1a10c2aa16 100644 --- a/test/SemaCXX/return-noreturn.cpp +++ b/test/SemaCXX/return-noreturn.cpp @@ -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; } } } } |