forked from OSchip/llvm-project
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:
parent
1bbf030b8e
commit
a626d645d5
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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 {};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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(); }
|
||||
}
|
||||
// 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_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 pr6884_h(int x) {
|
||||
switch (x) {
|
||||
default: {
|
||||
pr6884_abort_struct a;
|
||||
}
|
||||
int h(int x) {
|
||||
switch (x) { default: { pr6884_abort_struct a; } }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue