forked from OSchip/llvm-project
Change subexpressions to be visited in the CFG from left-to-right.
This is a more natural order of evaluation, and it is very important for visualization in the static analyzer. Within Xcode, the arrows will not jump from right to left, which looks very visually jarring. It also provides a more natural location for dataflow-based diagnostics. Along the way, we found a case in the analyzer diagnostics where we needed to indicate that a variable was "captured" by a block. -fsyntax-only timings on sqlite3.c show no visible performance change, although this is just one test case. Fixes <rdar://problem/13016513> llvm-svn: 174447
This commit is contained in:
parent
44a40ca143
commit
8ae67871b4
|
@ -2207,6 +2207,15 @@ public:
|
|||
return SubExprs+PREARGS_START+getNumPreArgs()+getNumArgs();
|
||||
}
|
||||
|
||||
/// This method provides fast access to all the subexpressions of
|
||||
/// a CallExpr without going through the slower virtual child_iterator
|
||||
/// interface. This provides efficient reverse iteration of the
|
||||
/// subexpressions. This is currently used for CFG construction.
|
||||
ArrayRef<Stmt*> getRawSubExprs() {
|
||||
return ArrayRef<Stmt*>(SubExprs,
|
||||
getNumPreArgs() + PREARGS_START + getNumArgs());
|
||||
}
|
||||
|
||||
/// getNumCommas - Return the number of commas that must have been present in
|
||||
/// this function call.
|
||||
unsigned getNumCommas() const { return NumArgs ? NumArgs - 1 : 0; }
|
||||
|
|
|
@ -662,6 +662,10 @@ public:
|
|||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/// Return the original region for a captured region, if
|
||||
/// one exists.
|
||||
const VarRegion *getOriginalRegion(const VarRegion *VR) const;
|
||||
|
||||
referenced_vars_iterator referenced_vars_begin() const;
|
||||
referenced_vars_iterator referenced_vars_end() const;
|
||||
|
|
|
@ -233,6 +233,43 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class reverse_children {
|
||||
llvm::SmallVector<Stmt *, 12> childrenBuf;
|
||||
ArrayRef<Stmt*> children;
|
||||
public:
|
||||
reverse_children(Stmt *S);
|
||||
|
||||
typedef ArrayRef<Stmt*>::reverse_iterator iterator;
|
||||
iterator begin() const { return children.rbegin(); }
|
||||
iterator end() const { return children.rend(); }
|
||||
};
|
||||
|
||||
|
||||
reverse_children::reverse_children(Stmt *S) {
|
||||
if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
|
||||
children = CE->getRawSubExprs();
|
||||
return;
|
||||
}
|
||||
switch (S->getStmtClass()) {
|
||||
case Stmt::InitListExprClass: {
|
||||
InitListExpr *IE = cast<InitListExpr>(S);
|
||||
children = llvm::makeArrayRef(reinterpret_cast<Stmt**>(IE->getInits()),
|
||||
IE->getNumInits());
|
||||
return;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Default case for all other statements.
|
||||
for (Stmt::child_range I = S->children(); I; ++I) {
|
||||
childrenBuf.push_back(*I);
|
||||
}
|
||||
|
||||
// This needs to be done *after* childrenBuf has been populated.
|
||||
children = childrenBuf;
|
||||
}
|
||||
|
||||
/// CFGBuilder - This class implements CFG construction from an AST.
|
||||
/// The builder is stateful: an instance of the builder should be used to only
|
||||
/// construct a single CFG.
|
||||
|
@ -1166,14 +1203,19 @@ CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) {
|
|||
}
|
||||
|
||||
/// VisitChildren - Visit the children of a Stmt.
|
||||
CFGBlock *CFGBuilder::VisitChildren(Stmt *Terminator) {
|
||||
CFGBlock *lastBlock = Block;
|
||||
for (Stmt::child_range I = Terminator->children(); I; ++I)
|
||||
if (Stmt *child = *I)
|
||||
if (CFGBlock *b = Visit(child))
|
||||
lastBlock = b;
|
||||
CFGBlock *CFGBuilder::VisitChildren(Stmt *S) {
|
||||
CFGBlock *B = Block;
|
||||
|
||||
return lastBlock;
|
||||
// Visit the children in their reverse order so that they appear in
|
||||
// left-to-right (natural) order in the CFG.
|
||||
reverse_children RChildren(S);
|
||||
for (reverse_children::iterator I = RChildren.begin(), E = RChildren.end();
|
||||
I != E; ++I) {
|
||||
if (Stmt *Child = *I)
|
||||
if (CFGBlock *R = Visit(Child))
|
||||
B = R;
|
||||
}
|
||||
return B;
|
||||
}
|
||||
|
||||
CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A,
|
||||
|
@ -3093,19 +3135,14 @@ tryAgain:
|
|||
|
||||
CFGBlock *CFGBuilder::VisitChildrenForTemporaryDtors(Stmt *E) {
|
||||
// When visiting children for destructors we want to visit them in reverse
|
||||
// order. Because there's no reverse iterator for children must to reverse
|
||||
// them in helper vector.
|
||||
typedef SmallVector<Stmt *, 4> ChildrenVect;
|
||||
ChildrenVect ChildrenRev;
|
||||
for (Stmt::child_range I = E->children(); I; ++I) {
|
||||
if (*I) ChildrenRev.push_back(*I);
|
||||
}
|
||||
|
||||
// order that they will appear in the CFG. Because the CFG is built
|
||||
// bottom-up, this means we visit them in their natural order, which
|
||||
// reverses them in the CFG.
|
||||
CFGBlock *B = Block;
|
||||
for (ChildrenVect::reverse_iterator I = ChildrenRev.rbegin(),
|
||||
L = ChildrenRev.rend(); I != L; ++I) {
|
||||
if (CFGBlock *R = VisitForTemporaryDtors(*I))
|
||||
B = R;
|
||||
for (Stmt::child_range I = E->children(); I; ++I) {
|
||||
if (Stmt *Child = *I)
|
||||
if (CFGBlock *R = VisitForTemporaryDtors(Child))
|
||||
B = R;
|
||||
}
|
||||
return B;
|
||||
}
|
||||
|
|
|
@ -433,42 +433,65 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
|
|||
llvm::raw_svector_ostream os(sbuf);
|
||||
|
||||
if (const PostStmt *PS = StoreSite->getLocationAs<PostStmt>()) {
|
||||
if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) {
|
||||
const Stmt *S = PS->getStmt();
|
||||
const char *action = 0;
|
||||
const DeclStmt *DS = dyn_cast<DeclStmt>(S);
|
||||
const VarRegion *VR = dyn_cast<VarRegion>(R);
|
||||
|
||||
if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
|
||||
os << "Variable '" << *VR->getDecl() << "' ";
|
||||
if (DS) {
|
||||
action = "initialized to ";
|
||||
} else if (isa<BlockExpr>(S)) {
|
||||
action = "captured by block as ";
|
||||
if (VR) {
|
||||
// See if we can get the BlockVarRegion.
|
||||
ProgramStateRef State = StoreSite->getState();
|
||||
SVal V = State->getSVal(S, PS->getLocationContext());
|
||||
if (const BlockDataRegion *BDR =
|
||||
dyn_cast_or_null<BlockDataRegion>(V.getAsRegion())) {
|
||||
if (const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) {
|
||||
V = State->getSVal(OriginalR);
|
||||
BR.addVisitor(new FindLastStoreBRVisitor(V, OriginalR));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (action) {
|
||||
if (!R)
|
||||
return 0;
|
||||
|
||||
os << "Variable '" << *VR->getDecl() << "' ";
|
||||
|
||||
if (isa<loc::ConcreteInt>(V)) {
|
||||
bool b = false;
|
||||
if (R->isBoundable()) {
|
||||
if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) {
|
||||
if (TR->getValueType()->isObjCObjectPointerType()) {
|
||||
os << "initialized to nil";
|
||||
os << action << "nil";
|
||||
b = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!b)
|
||||
os << "initialized to a null pointer value";
|
||||
os << action << "a null pointer value";
|
||||
}
|
||||
else if (isa<nonloc::ConcreteInt>(V)) {
|
||||
os << "initialized to " << cast<nonloc::ConcreteInt>(V).getValue();
|
||||
os << action << cast<nonloc::ConcreteInt>(V).getValue();
|
||||
}
|
||||
else if (V.isUndef()) {
|
||||
if (isa<VarRegion>(R)) {
|
||||
const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
|
||||
if (VD->getInit())
|
||||
os << "initialized to a garbage value";
|
||||
else
|
||||
os << "declared without an initial value";
|
||||
else if (DS) {
|
||||
if (V.isUndef()) {
|
||||
if (isa<VarRegion>(R)) {
|
||||
const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
|
||||
if (VD->getInit())
|
||||
os << "initialized to a garbage value";
|
||||
else
|
||||
os << "declared without an initial value";
|
||||
}
|
||||
}
|
||||
else {
|
||||
os << "initialized here";
|
||||
}
|
||||
}
|
||||
else {
|
||||
os << "initialized here";
|
||||
}
|
||||
}
|
||||
} else if (isa<CallEnter>(StoreSite->getLocation())) {
|
||||
|
|
|
@ -1302,3 +1302,13 @@ BlockDataRegion::referenced_vars_end() const {
|
|||
return BlockDataRegion::referenced_vars_iterator(Vec->end(),
|
||||
VecOriginal->end());
|
||||
}
|
||||
|
||||
const VarRegion *BlockDataRegion::getOriginalRegion(const VarRegion *R) const {
|
||||
for (referenced_vars_iterator I = referenced_vars_begin(),
|
||||
E = referenced_vars_end();
|
||||
I != E; ++I) {
|
||||
if (I.getCapturedRegion() == R)
|
||||
return I.getOriginalRegion();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -207,22 +207,22 @@ TestCtorInits::TestCtorInits()
|
|||
// CHECK: 14: int a = int(A().operator int()) + int(B().operator int());
|
||||
// CHECK: 15: ~B() (Temporary object destructor)
|
||||
// CHECK: 16: ~A() (Temporary object destructor)
|
||||
// CHECK: 17: A() (CXXConstructExpr, class A)
|
||||
// CHECK: 18: [B1.17] (BindTemporary)
|
||||
// CHECK: 19: [B1.18].operator int
|
||||
// CHECK: 20: [B1.19]()
|
||||
// CHECK: 21: [B1.20] (ImplicitCastExpr, UserDefinedConversion, int)
|
||||
// CHECK: 22: int([B1.21]) (CXXFunctionalCastExpr, NoOp, int)
|
||||
// CHECK: 23: B() (CXXConstructExpr, class B)
|
||||
// CHECK: 24: [B1.23] (BindTemporary)
|
||||
// CHECK: 25: [B1.24].operator int
|
||||
// CHECK: 26: [B1.25]()
|
||||
// CHECK: 27: [B1.26] (ImplicitCastExpr, UserDefinedConversion, int)
|
||||
// CHECK: 28: int([B1.27]) (CXXFunctionalCastExpr, NoOp, int)
|
||||
// CHECK: 29: [B1.22] + [B1.28]
|
||||
// CHECK: 30: foo
|
||||
// CHECK: 31: [B1.30] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int))
|
||||
// CHECK: 32: [B1.31]([B1.29])
|
||||
// CHECK: 17: foo
|
||||
// CHECK: 18: [B1.17] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int))
|
||||
// CHECK: 19: A() (CXXConstructExpr, class A)
|
||||
// CHECK: 20: [B1.19] (BindTemporary)
|
||||
// CHECK: 21: [B1.20].operator int
|
||||
// CHECK: 22: [B1.21]()
|
||||
// CHECK: 23: [B1.22] (ImplicitCastExpr, UserDefinedConversion, int)
|
||||
// CHECK: 24: int([B1.23]) (CXXFunctionalCastExpr, NoOp, int)
|
||||
// CHECK: 25: B() (CXXConstructExpr, class B)
|
||||
// CHECK: 26: [B1.25] (BindTemporary)
|
||||
// CHECK: 27: [B1.26].operator int
|
||||
// CHECK: 28: [B1.27]()
|
||||
// CHECK: 29: [B1.28] (ImplicitCastExpr, UserDefinedConversion, int)
|
||||
// CHECK: 30: int([B1.29]) (CXXFunctionalCastExpr, NoOp, int)
|
||||
// CHECK: 31: [B1.24] + [B1.30]
|
||||
// CHECK: 32: [B1.18]([B1.31])
|
||||
// CHECK: 33: ~B() (Temporary object destructor)
|
||||
// CHECK: 34: ~A() (Temporary object destructor)
|
||||
// CHECK: 35: int b;
|
||||
|
@ -242,11 +242,9 @@ TestCtorInits::TestCtorInits()
|
|||
// CHECK: Preds (1): B3
|
||||
// CHECK: Succs (1): B1
|
||||
// CHECK: [B3]
|
||||
// CHECK: 1: [B5.6] && [B4.5]
|
||||
// CHECK: 2: foo
|
||||
// CHECK: 3: [B3.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(_Bool))
|
||||
// CHECK: 4: [B3.3]([B3.1])
|
||||
// CHECK: T: [B5.6] && ...
|
||||
// CHECK: 1: [B5.8] && [B4.5]
|
||||
// CHECK: 2: [B5.3]([B3.1])
|
||||
// CHECK: T: [B5.8] && ...
|
||||
// CHECK: Preds (2): B4 B5
|
||||
// CHECK: Succs (2): B2 B1
|
||||
// CHECK: [B4]
|
||||
|
@ -259,12 +257,14 @@ TestCtorInits::TestCtorInits()
|
|||
// CHECK: Succs (1): B3
|
||||
// CHECK: [B5]
|
||||
// CHECK: 1: ~A() (Temporary object destructor)
|
||||
// CHECK: 2: A() (CXXConstructExpr, class A)
|
||||
// CHECK: 3: [B5.2] (BindTemporary)
|
||||
// CHECK: 4: [B5.3].operator _Bool
|
||||
// CHECK: 5: [B5.4]()
|
||||
// CHECK: 6: [B5.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
|
||||
// CHECK: T: [B5.6] && ...
|
||||
// CHECK: 2: foo
|
||||
// CHECK: 3: [B5.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(_Bool))
|
||||
// CHECK: 4: A() (CXXConstructExpr, class A)
|
||||
// CHECK: 5: [B5.4] (BindTemporary)
|
||||
// CHECK: 6: [B5.5].operator _Bool
|
||||
// CHECK: 7: [B5.6]()
|
||||
// CHECK: 8: [B5.7] (ImplicitCastExpr, UserDefinedConversion, _Bool)
|
||||
// CHECK: T: [B5.8] && ...
|
||||
// CHECK: Preds (2): B6 B7
|
||||
// CHECK: Succs (2): B4 B3
|
||||
// CHECK: [B6]
|
||||
|
@ -308,11 +308,9 @@ TestCtorInits::TestCtorInits()
|
|||
// CHECK: Preds (1): B3
|
||||
// CHECK: Succs (1): B1
|
||||
// CHECK: [B3]
|
||||
// CHECK: 1: [B5.6] || [B4.5]
|
||||
// CHECK: 2: foo
|
||||
// CHECK: 3: [B3.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(_Bool))
|
||||
// CHECK: 4: [B3.3]([B3.1])
|
||||
// CHECK: T: [B5.6] || ...
|
||||
// CHECK: 1: [B5.8] || [B4.5]
|
||||
// CHECK: 2: [B5.3]([B3.1])
|
||||
// CHECK: T: [B5.8] || ...
|
||||
// CHECK: Preds (2): B4 B5
|
||||
// CHECK: Succs (2): B1 B2
|
||||
// CHECK: [B4]
|
||||
|
@ -325,12 +323,14 @@ TestCtorInits::TestCtorInits()
|
|||
// CHECK: Succs (1): B3
|
||||
// CHECK: [B5]
|
||||
// CHECK: 1: ~A() (Temporary object destructor)
|
||||
// CHECK: 2: A() (CXXConstructExpr, class A)
|
||||
// CHECK: 3: [B5.2] (BindTemporary)
|
||||
// CHECK: 4: [B5.3].operator _Bool
|
||||
// CHECK: 5: [B5.4]()
|
||||
// CHECK: 6: [B5.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
|
||||
// CHECK: T: [B5.6] || ...
|
||||
// CHECK: 2: foo
|
||||
// CHECK: 3: [B5.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(_Bool))
|
||||
// CHECK: 4: A() (CXXConstructExpr, class A)
|
||||
// CHECK: 5: [B5.4] (BindTemporary)
|
||||
// CHECK: 6: [B5.5].operator _Bool
|
||||
// CHECK: 7: [B5.6]()
|
||||
// CHECK: 8: [B5.7] (ImplicitCastExpr, UserDefinedConversion, _Bool)
|
||||
// CHECK: T: [B5.8] || ...
|
||||
// CHECK: Preds (2): B6 B7
|
||||
// CHECK: Succs (2): B3 B4
|
||||
// CHECK: [B6]
|
||||
|
@ -370,17 +370,17 @@ TestCtorInits::TestCtorInits()
|
|||
// CHECK: Preds (2): B2 B3
|
||||
// CHECK: Succs (1): B0
|
||||
// CHECK: [B2]
|
||||
// CHECK: 1: 0
|
||||
// CHECK: 2: foo
|
||||
// CHECK: 3: [B2.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int))
|
||||
// CHECK: 4: [B2.3]([B2.1])
|
||||
// CHECK: 1: foo
|
||||
// CHECK: 2: [B2.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int))
|
||||
// CHECK: 3: 0
|
||||
// CHECK: 4: [B2.2]([B2.3])
|
||||
// CHECK: Preds (1): B4
|
||||
// CHECK: Succs (1): B1
|
||||
// CHECK: [B3]
|
||||
// CHECK: 1: 0
|
||||
// CHECK: 2: foo
|
||||
// CHECK: 3: [B3.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int))
|
||||
// CHECK: 4: [B3.3]([B3.1])
|
||||
// CHECK: 1: foo
|
||||
// CHECK: 2: [B3.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int))
|
||||
// CHECK: 3: 0
|
||||
// CHECK: 4: [B3.2]([B3.3])
|
||||
// CHECK: Preds (1): B4
|
||||
// CHECK: Succs (1): B1
|
||||
// CHECK: [B4]
|
||||
|
@ -474,13 +474,11 @@ TestCtorInits::TestCtorInits()
|
|||
// CHECK: Preds (1): B4
|
||||
// CHECK: Succs (1): B1
|
||||
// CHECK: [B4]
|
||||
// CHECK: 1: [B7.6] ? [B5.6] : [B6.15]
|
||||
// CHECK: 1: [B7.8] ? [B5.6] : [B6.15]
|
||||
// CHECK: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
|
||||
// CHECK: 3: [B4.2]
|
||||
// CHECK: 4: foo
|
||||
// CHECK: 5: [B4.4] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
|
||||
// CHECK: 6: [B4.5]([B4.3])
|
||||
// CHECK: T: [B7.6] ? ... : ...
|
||||
// CHECK: 4: [B7.3]([B4.3])
|
||||
// CHECK: T: [B7.8] ? ... : ...
|
||||
// CHECK: Preds (2): B5 B6
|
||||
// CHECK: Succs (2): B2 B3
|
||||
// CHECK: [B5]
|
||||
|
@ -512,12 +510,14 @@ TestCtorInits::TestCtorInits()
|
|||
// CHECK: Succs (1): B4
|
||||
// CHECK: [B7]
|
||||
// CHECK: 1: ~B() (Temporary object destructor)
|
||||
// CHECK: 2: B() (CXXConstructExpr, class B)
|
||||
// CHECK: 3: [B7.2] (BindTemporary)
|
||||
// CHECK: 4: [B7.3].operator _Bool
|
||||
// CHECK: 5: [B7.4]()
|
||||
// CHECK: 6: [B7.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
|
||||
// CHECK: T: [B7.6] ? ... : ...
|
||||
// CHECK: 2: foo
|
||||
// CHECK: 3: [B7.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
|
||||
// CHECK: 4: B() (CXXConstructExpr, class B)
|
||||
// CHECK: 5: [B7.4] (BindTemporary)
|
||||
// CHECK: 6: [B7.5].operator _Bool
|
||||
// CHECK: 7: [B7.6]()
|
||||
// CHECK: 8: [B7.7] (ImplicitCastExpr, UserDefinedConversion, _Bool)
|
||||
// CHECK: T: [B7.8] ? ... : ...
|
||||
// CHECK: Preds (2): B8 B9
|
||||
// CHECK: Succs (2): B5 B6
|
||||
// CHECK: [B8]
|
||||
|
@ -647,17 +647,15 @@ TestCtorInits::TestCtorInits()
|
|||
// CHECK: Preds (1): B4
|
||||
// CHECK: Succs (1): B1
|
||||
// CHECK: [B4]
|
||||
// CHECK: 1: [B7.3] ?: [B6.6]
|
||||
// CHECK: 1: [B7.5] ?: [B6.6]
|
||||
// CHECK: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
|
||||
// CHECK: 3: [B4.2]
|
||||
// CHECK: 4: foo
|
||||
// CHECK: 5: [B4.4] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
|
||||
// CHECK: 6: [B4.5]([B4.3])
|
||||
// CHECK: T: [B7.6] ? ... : ...
|
||||
// CHECK: 4: [B7.3]([B4.3])
|
||||
// CHECK: T: [B7.8] ? ... : ...
|
||||
// CHECK: Preds (2): B5 B6
|
||||
// CHECK: Succs (2): B2 B3
|
||||
// CHECK: [B5]
|
||||
// CHECK: 1: [B7.3] (ImplicitCastExpr, NoOp, const class A)
|
||||
// CHECK: 1: [B7.5] (ImplicitCastExpr, NoOp, const class A)
|
||||
// CHECK: 2: [B5.1]
|
||||
// CHECK: 3: [B5.2] (CXXConstructExpr, class A)
|
||||
// CHECK: 4: [B5.3] (BindTemporary)
|
||||
|
@ -674,12 +672,14 @@ TestCtorInits::TestCtorInits()
|
|||
// CHECK: Succs (1): B4
|
||||
// CHECK: [B7]
|
||||
// CHECK: 1: ~A() (Temporary object destructor)
|
||||
// CHECK: 2: A() (CXXConstructExpr, class A)
|
||||
// CHECK: 3: [B7.2] (BindTemporary)
|
||||
// CHECK: 4: [B7.3].operator _Bool
|
||||
// CHECK: 5: [B7.4]()
|
||||
// CHECK: 6: [B7.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
|
||||
// CHECK: T: [B7.6] ? ... : ...
|
||||
// CHECK: 2: foo
|
||||
// CHECK: 3: [B7.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
|
||||
// CHECK: 4: A() (CXXConstructExpr, class A)
|
||||
// CHECK: 5: [B7.4] (BindTemporary)
|
||||
// CHECK: 6: [B7.5].operator _Bool
|
||||
// CHECK: 7: [B7.6]()
|
||||
// CHECK: 8: [B7.7] (ImplicitCastExpr, UserDefinedConversion, _Bool)
|
||||
// CHECK: T: [B7.8] ? ... : ...
|
||||
// CHECK: Preds (2): B9 B8
|
||||
// CHECK: Succs (2): B5 B6
|
||||
// CHECK: [B8]
|
||||
|
@ -745,13 +745,13 @@ TestCtorInits::TestCtorInits()
|
|||
// CHECK: 3: [B1.2] (ImplicitCastExpr, NoOp, const class A)
|
||||
// CHECK: 4: [B1.3]
|
||||
// CHECK: 5: const A &a = A();
|
||||
// CHECK: 6: A() (CXXConstructExpr, class A)
|
||||
// CHECK: 7: [B1.6] (BindTemporary)
|
||||
// CHECK: 8: [B1.7] (ImplicitCastExpr, NoOp, const class A)
|
||||
// CHECK: 9: [B1.8]
|
||||
// CHECK: 10: foo
|
||||
// CHECK: 11: [B1.10] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
|
||||
// CHECK: 12: [B1.11]([B1.9])
|
||||
// CHECK: 6: foo
|
||||
// CHECK: 7: [B1.6] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
|
||||
// CHECK: 8: A() (CXXConstructExpr, class A)
|
||||
// CHECK: 9: [B1.8] (BindTemporary)
|
||||
// CHECK: 10: [B1.9] (ImplicitCastExpr, NoOp, const class A)
|
||||
// CHECK: 11: [B1.10]
|
||||
// CHECK: 12: [B1.7]([B1.11])
|
||||
// CHECK: 13: ~A() (Temporary object destructor)
|
||||
// CHECK: 14: int b;
|
||||
// CHECK: 15: [B1.5].~A() (Implicit destructor)
|
||||
|
@ -787,15 +787,15 @@ TestCtorInits::TestCtorInits()
|
|||
// CHECK: 5: [B1.4] (ImplicitCastExpr, NoOp, const class A)
|
||||
// CHECK: 6: [B1.5]
|
||||
// CHECK: 7: const A &a = A::make();
|
||||
// CHECK: 8: A::make
|
||||
// CHECK: 9: [B1.8] (ImplicitCastExpr, FunctionToPointerDecay, class A (*)(void))
|
||||
// CHECK: 10: [B1.9]()
|
||||
// CHECK: 11: [B1.10] (BindTemporary)
|
||||
// CHECK: 12: [B1.11] (ImplicitCastExpr, NoOp, const class A)
|
||||
// CHECK: 13: [B1.12]
|
||||
// CHECK: 14: foo
|
||||
// CHECK: 15: [B1.14] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
|
||||
// CHECK: 16: [B1.15]([B1.13])
|
||||
// CHECK: 8: foo
|
||||
// CHECK: 9: [B1.8] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
|
||||
// CHECK: 10: A::make
|
||||
// CHECK: 11: [B1.10] (ImplicitCastExpr, FunctionToPointerDecay, class A (*)(void))
|
||||
// CHECK: 12: [B1.11]()
|
||||
// CHECK: 13: [B1.12] (BindTemporary)
|
||||
// CHECK: 14: [B1.13] (ImplicitCastExpr, NoOp, const class A)
|
||||
// CHECK: 15: [B1.14]
|
||||
// CHECK: 16: [B1.9]([B1.15])
|
||||
// CHECK: 17: ~A() (Temporary object destructor)
|
||||
// CHECK: 18: int b;
|
||||
// CHECK: 19: [B1.7].~A() (Implicit destructor)
|
||||
|
|
|
@ -1418,12 +1418,12 @@ void test_inline_dispatch_once() {
|
|||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>190</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>24</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>190</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>15</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>24</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </array>
|
||||
|
@ -1435,6 +1435,35 @@ void test_inline_dispatch_once() {
|
|||
// CHECK-NEXT: <key>location</key>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>190</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>24</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <key>ranges</key>
|
||||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>190</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>24</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>194</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </array>
|
||||
// CHECK-NEXT: </array>
|
||||
// CHECK-NEXT: <key>depth</key><integer>0</integer>
|
||||
// CHECK-NEXT: <key>extended_message</key>
|
||||
// CHECK-NEXT: <string>Variable 'p' captured by block as a null pointer value</string>
|
||||
// CHECK-NEXT: <key>message</key>
|
||||
// CHECK-NEXT: <string>Variable 'p' captured by block as a null pointer value</string>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>kind</key><string>event</string>
|
||||
// CHECK-NEXT: <key>location</key>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>190</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
|
@ -1739,6 +1768,69 @@ void test_inline_dispatch_once() {
|
|||
// CHECK-NEXT: <string>Variable 'p' initialized to a null pointer value</string>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>kind</key><string>control</string>
|
||||
// CHECK-NEXT: <key>edges</key>
|
||||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>start</key>
|
||||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>200</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>200</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>5</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </array>
|
||||
// CHECK-NEXT: <key>end</key>
|
||||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>201</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>24</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>201</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>24</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </array>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </array>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>kind</key><string>event</string>
|
||||
// CHECK-NEXT: <key>location</key>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>201</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>24</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <key>ranges</key>
|
||||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>201</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>24</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>203</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </array>
|
||||
// CHECK-NEXT: </array>
|
||||
// CHECK-NEXT: <key>depth</key><integer>0</integer>
|
||||
// CHECK-NEXT: <key>extended_message</key>
|
||||
// CHECK-NEXT: <string>Variable 'p' captured by block as a null pointer value</string>
|
||||
// CHECK-NEXT: <key>message</key>
|
||||
// CHECK-NEXT: <string>Variable 'p' captured by block as a null pointer value</string>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>kind</key><string>event</string>
|
||||
// CHECK-NEXT: <key>location</key>
|
||||
// CHECK-NEXT: <dict>
|
||||
|
|
|
@ -80,8 +80,8 @@ void test2() {
|
|||
- // expected-warning {{will never be executed}}
|
||||
halt();
|
||||
case 8:
|
||||
i // expected-warning {{will never be executed}}
|
||||
+=
|
||||
i
|
||||
+= // expected-warning {{will never be executed}}
|
||||
halt();
|
||||
case 9:
|
||||
halt()
|
||||
|
@ -93,8 +93,8 @@ void test2() {
|
|||
case 11: {
|
||||
int a[5];
|
||||
live(),
|
||||
a[halt() // expected-warning {{will never be executed}}
|
||||
];
|
||||
a[halt()
|
||||
]; // expected-warning {{will never be executed}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue