Extend the Stmt AST to make it easier to look through label, default,

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.

llvm-svn: 139437
This commit is contained in:
Chandler Carruth 2011-09-10 00:02:34 +00:00
parent 1bbf030b8e
commit a626d645d5
4 changed files with 54 additions and 22 deletions

View File

@ -296,6 +296,12 @@ public:
/// statement, such as ExprWithCleanups or ImplicitCastExpr nodes. /// statement, such as ExprWithCleanups or ImplicitCastExpr nodes.
Stmt *IgnoreImplicit(); Stmt *IgnoreImplicit();
const Stmt *stripLabelLikeStatements() const;
Stmt *stripLabelLikeStatements() {
return const_cast<Stmt*>(
const_cast<const Stmt*>(this)->stripLabelLikeStatements());
}
// Implement isa<T> support. // Implement isa<T> support.
static bool classof(const Stmt *) { return true; } static bool classof(const Stmt *) { return true; }

View File

@ -97,6 +97,22 @@ Stmt *Stmt::IgnoreImplicit() {
return s; 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 { namespace {
struct good {}; struct good {};
struct bad {}; struct bad {};

View File

@ -723,9 +723,7 @@ void CFGBuilder::addLocalScopeForStmt(Stmt *S) {
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) { if (CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) {
for (CompoundStmt::body_iterator BI = CS->body_begin(), BE = CS->body_end() for (CompoundStmt::body_iterator BI = CS->body_begin(), BE = CS->body_end()
; BI != BE; ++BI) { ; BI != BE; ++BI) {
Stmt *SI = *BI; Stmt *SI = (*BI)->stripLabelLikeStatements();
if (LabelStmt *LS = dyn_cast<LabelStmt>(SI))
SI = LS->getSubStmt();
if (DeclStmt *DS = dyn_cast<DeclStmt>(SI)) if (DeclStmt *DS = dyn_cast<DeclStmt>(SI))
Scope = addLocalScopeForDeclStmt(DS, Scope); 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 // For any other statement scope will be implicit and as such will be
// interesting only for DeclStmt. // interesting only for DeclStmt.
if (LabelStmt *LS = dyn_cast<LabelStmt>(S)) if (DeclStmt *DS = dyn_cast<DeclStmt>(S->stripLabelLikeStatements()))
S = LS->getSubStmt();
if (DeclStmt *DS = dyn_cast<DeclStmt>(S))
addLocalScopeForDeclStmt(DS); addLocalScopeForDeclStmt(DS);
} }

View File

@ -8,23 +8,37 @@ struct pr6884_abort_struct {
~pr6884_abort_struct() __attribute__((noreturn)) { pr6884_abort(); } ~pr6884_abort_struct() __attribute__((noreturn)) { pr6884_abort(); }
}; };
int pr6884_f(int x) { // Ensure that destructors from objects are properly modeled in the CFG despite
switch (x) { default: pr6884_abort(); } // 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_g(int x) { int h(int x) {
switch (x) { default: pr6884_abort_struct(); } switch (x) { default: { pr6884_abort_struct a; } }
}
int pr6884_g_positive(int x) {
switch (x) { default: ; }
} // expected-warning {{control reaches end of non-void function}}
int pr6884_h(int x) {
switch (x) {
default: {
pr6884_abort_struct a;
}
} }
} }