Index: lib/Analysis/AnalysisDeclContext.cpp =================================================================== --- lib/Analysis/AnalysisDeclContext.cpp +++ lib/Analysis/AnalysisDeclContext.cpp @@ -239,6 +239,11 @@ E = C->init_end(); I != E; ++I) { PM->addStmt((*I)->getInit()); + if (const CXXDefaultInitExpr *DIE = + dyn_cast((*I)->getInit())) { + PM->addStmt(const_cast(DIE->getExpr())); + PM->setParent(DIE->getExpr(), DIE); + } } } if (builtCFG) Index: lib/Analysis/CFG.cpp =================================================================== --- lib/Analysis/CFG.cpp +++ lib/Analysis/CFG.cpp @@ -766,6 +766,17 @@ // generating destructors for the second time. return Visit(cast(Init)->getSubExpr()); } + if (CXXDefaultInitExpr *Default = dyn_cast(Init)) { + // In general, appending the expression wrapped by a CXXDefaultInitExpr + // may cause the same Expr to appear more than once in the CFG. Doing it + // here is safe because there's only one initializer per field. + autoCreateBlock(); + appendStmt(Block, Default); + if (Stmt *Child = Default->getExpr()) + if (CFGBlock *R = Visit(Child)) + Block = R; + return Block; + } return Visit(Init); } Index: lib/StaticAnalyzer/Core/BugReporter.cpp =================================================================== --- lib/StaticAnalyzer/Core/BugReporter.cpp +++ lib/StaticAnalyzer/Core/BugReporter.cpp @@ -246,29 +246,38 @@ } } +static bool isInDefaultInitExpr(ParentMap &PM, const Stmt *S) { + while (S) { + if (isa(S)) + return true; + S = PM.getParent(S); + } + return false; +} + /// Remove edges in and out of C++ default initializer expressions. These are /// for fields that have in-class initializers, as opposed to being initialized /// explicitly in a constructor or braced list. -static void removeEdgesToDefaultInitializers(PathPieces &Pieces) { +static void removeEdgesToDefaultInitializers(PathPieces &Pieces, ParentMap &PM) { for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E;) { if (PathDiagnosticCallPiece *C = dyn_cast(*I)) - removeEdgesToDefaultInitializers(C->path); + removeEdgesToDefaultInitializers(C->path, PM); if (PathDiagnosticMacroPiece *M = dyn_cast(*I)) - removeEdgesToDefaultInitializers(M->subPieces); + removeEdgesToDefaultInitializers(M->subPieces, PM); if (PathDiagnosticControlFlowPiece *CF = dyn_cast(*I)) { const Stmt *Start = CF->getStartLocation().asStmt(); const Stmt *End = CF->getEndLocation().asStmt(); - if (Start && isa(Start)) { + if (Start && isInDefaultInitExpr(PM, Start)) { I = Pieces.erase(I); continue; - } else if (End && isa(End)) { + } else if (End && isInDefaultInitExpr(PM, End)) { PathPieces::iterator Next = llvm::next(I); if (Next != E) { if (PathDiagnosticControlFlowPiece *NextCF = - dyn_cast(*Next)) { + dyn_cast(*Next)) { NextCF->setStartLocation(CF->getStartLocation()); } } @@ -3229,7 +3238,7 @@ // make sense. // We have to do this after edge optimization in the Extensive mode. removeRedundantMsgs(PD.getMutablePieces()); - removeEdgesToDefaultInitializers(PD.getMutablePieces()); + removeEdgesToDefaultInitializers(PD.getMutablePieces(), PDB.getParentMap()); } // We found a report and didn't suppress it. Index: test/Analysis/edges-new.mm =================================================================== --- test/Analysis/edges-new.mm +++ test/Analysis/edges-new.mm @@ -588,6 +588,14 @@ *(volatile int *)0 = 1; } }; + + class Bar { + int a = 1; + int b = a == 1 ? 2 : *(volatile int *)0; + + Bar() : + a(2) {} + }; } // CHECK: diagnostics @@ -19625,4 +19633,48 @@ // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line594 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line594 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line594 +// CHECK-NEXT: col43 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_hash4294967293 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line594 +// CHECK-NEXT: col26 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: // CHECK-NEXT: