Index: clang/include/clang/Analysis/CFG.h =================================================================== --- clang/include/clang/Analysis/CFG.h +++ clang/include/clang/Analysis/CFG.h @@ -1248,6 +1248,7 @@ bool AddStaticInitBranches = false; bool AddCXXNewAllocator = false; bool AddCXXDefaultInitExprInCtors = false; + bool AddCXXDefaultInitExprInAggregates = false; bool AddRichCXXConstructors = false; bool MarkElidedCXXConstructors = false; bool AddVirtualBaseBranches = false; Index: clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def =================================================================== --- clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def +++ clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def @@ -112,6 +112,11 @@ bool, ShouldIncludeScopesInCFG, "cfg-scopes", "Whether or not scope information should be included in the CFG.", false) +ANALYZER_OPTION(bool, ShouldIncludeDefaultInitForAggregates, "cfg-aggr-definit", + "Whether or not inline CXXDefaultInitializers for aggregat " + "initialization in the CFG.", + false) + ANALYZER_OPTION( bool, MayInlineTemplateFunctions, "c++-template-inlining", "Whether or not templated functions may be considered for inlining.", true) Index: clang/lib/Analysis/CFG.cpp =================================================================== --- clang/lib/Analysis/CFG.cpp +++ clang/lib/Analysis/CFG.cpp @@ -542,6 +542,7 @@ private: // Visitors to walk an AST and construct the CFG. + CFGBlock *VisitInitListExpr(InitListExpr *ILE, AddStmtChoice asc); CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc); CFGBlock *VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc); CFGBlock *VisitBreakStmt(BreakStmt *B); @@ -2140,6 +2141,9 @@ return Block; return VisitStmt(S, asc); + case Stmt::InitListExprClass: + return VisitInitListExpr(cast(S), asc); + case Stmt::AddrLabelExprClass: return VisitAddrLabelExpr(cast(S), asc); @@ -2355,6 +2359,29 @@ return B; } +CFGBlock *CFGBuilder::VisitInitListExpr(InitListExpr *ILE, AddStmtChoice asc) { + if (asc.alwaysAdd(*this, ILE)) { + autoCreateBlock(); + appendStmt(Block, ILE); + } + CFGBlock *B = Block; + + reverse_children RChildren(ILE); + for (reverse_children::iterator I = RChildren.begin(), E = RChildren.end(); + I != E; ++I) { + if (Stmt *Child = *I) + if (CFGBlock *R = Visit(Child)) + B = R; + if (BuildOpts.AddCXXDefaultInitExprInAggregates) { + if (auto *DIE = dyn_cast_or_null(*I)) + if (Stmt *Child = DIE->getExpr()) + if (CFGBlock *R = Visit(Child)) + B = R; + } + } + return B; +} + CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc) { AddressTakenLabels.insert(A->getLabel()); Index: clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp +++ clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp @@ -44,6 +44,8 @@ options(Options) { AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd(); AnaCtxMgr.getCFGBuildOptions().OmitImplicitValueInitializers = true; + AnaCtxMgr.getCFGBuildOptions().AddCXXDefaultInitExprInAggregates = + Options.ShouldIncludeDefaultInitForAggregates; } AnalysisManager::~AnalysisManager() { Index: clang/test/Analysis/aggrinit-cfg-output.cpp =================================================================== --- /dev/null +++ clang/test/Analysis/aggrinit-cfg-output.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -analyzer-config cfg-aggr-definit=true %s > %t 2>&1 +// RUN: FileCheck --input-file=%t %s + +static char a[] = "foobar"; + +struct StringRef { + const char *member = nullptr; + int len = 3; +}; + +int main() { + StringRef s{a}; + (void)s; +} + +// CHECK: [B1] +// CHECK-NEXT: 1: a +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, ArrayToPointerDecay, char *) +// CHECK-NEXT: 3: [B1.2] (ImplicitCastExpr, NoOp, const char *) +// CHECK-NEXT: 4: 3 +// CHECK-NEXT: 5: +// CHECK-NEXT: 6: {[B1.1]} +// CHECK-NEXT: 7: StringRef s{a}; +// CHECK-NEXT: 8: s +// CHECK-NEXT: 9: (void)[B1.8] (CStyleCastExpr, ToVoid, void) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 + Index: clang/test/Analysis/analyzer-config.c =================================================================== --- clang/test/Analysis/analyzer-config.c +++ clang/test/Analysis/analyzer-config.c @@ -18,6 +18,7 @@ // CHECK-NEXT: c++-stdlib-inlining = true // CHECK-NEXT: c++-temp-dtor-inlining = true // CHECK-NEXT: c++-template-inlining = true +// CHECK-NEXT: cfg-aggr-definit = false // CHECK-NEXT: cfg-conditional-static-initializers = true // CHECK-NEXT: cfg-implicit-dtors = true // CHECK-NEXT: cfg-lifetime = false @@ -98,4 +99,4 @@ // CHECK-NEXT: unroll-loops = false // CHECK-NEXT: widen-loops = false // CHECK-NEXT: [stats] -// CHECK-NEXT: num-entries = 95 +// CHECK-NEXT: num-entries = 96