aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Stmt.h6
-rw-r--r--lib/AST/Stmt.cpp16
-rw-r--r--lib/Analysis/CFG.cpp8
-rw-r--r--test/SemaCXX/return-noreturn.cpp46
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; } }
}
}