diff --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h --- a/clang/include/clang/Analysis/CFG.h +++ b/clang/include/clang/Analysis/CFG.h @@ -1251,6 +1251,7 @@ bool AddRichCXXConstructors = false; bool MarkElidedCXXConstructors = false; bool AddVirtualBaseBranches = false; + bool OmitImplicitValueInitializers = false; BuildOptions() = default; diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -2135,6 +2135,11 @@ default: return VisitStmt(S, asc); + case Stmt::ImplicitValueInitExprClass: + if (BuildOpts.OmitImplicitValueInitializers) + return Block; + return VisitStmt(S, asc); + case Stmt::AddrLabelExprClass: return VisitAddrLabelExpr(cast(S), asc); diff --git a/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp --- a/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp @@ -43,6 +43,7 @@ CreateConstraintMgr(constraintmgr), CheckerMgr(checkerMgr), options(Options) { AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd(); + AnaCtxMgr.getCFGBuildOptions().OmitImplicitValueInitializers = true; } AnalysisManager::~AnalysisManager() { diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1321,6 +1321,11 @@ case Stmt::WhileStmtClass: case Expr::MSDependentExistsStmtClass: llvm_unreachable("Stmt should not be in analyzer evaluation loop"); + case Stmt::ImplicitValueInitExprClass: + // These nodes are shared in the CFG and would case caching out. + // Moreover, no additional evaluation required for them, the + // analyzer can reconstruct these values from the AST. + llvm_unreachable("Should be pruned from CFG"); case Stmt::ObjCSubscriptRefExprClass: case Stmt::ObjCPropertyRefExprClass: @@ -1391,7 +1396,6 @@ case Stmt::IntegerLiteralClass: case Stmt::FixedPointLiteralClass: case Stmt::CharacterLiteralClass: - case Stmt::ImplicitValueInitExprClass: case Stmt::CXXScalarValueInitExprClass: case Stmt::CXXBoolLiteralExprClass: case Stmt::ObjCBoolLiteralExprClass: diff --git a/clang/test/Analysis/designated-initializer-values.c b/clang/test/Analysis/designated-initializer-values.c new file mode 100644 --- /dev/null +++ b/clang/test/Analysis/designated-initializer-values.c @@ -0,0 +1,38 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c99 -verify %s + +void clang_analyzer_eval(int); + +void array_init() { + int a[5] = {[4] = 29, [2] = 15, [0] = 4}; + clang_analyzer_eval(a[0] == 4); // expected-warning{{TRUE}} + clang_analyzer_eval(a[1] == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(a[2] == 15); // expected-warning{{TRUE}} + clang_analyzer_eval(a[3] == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(a[4] == 29); // expected-warning{{TRUE}} + int b[5] = {[0 ... 2] = 1, [4] = 5}; + clang_analyzer_eval(b[0] == 1); // expected-warning{{TRUE}} + clang_analyzer_eval(b[1] == 1); // expected-warning{{TRUE}} + clang_analyzer_eval(b[2] == 1); // expected-warning{{TRUE}} + clang_analyzer_eval(b[3] == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(b[4] == 5); // expected-warning{{TRUE}} +} + +struct point { + int x, y; +}; + +void struct_init() { + struct point p = {.y = 5, .x = 3}; + clang_analyzer_eval(p.x == 3); // expected-warning{{TRUE}} + clang_analyzer_eval(p.y == 5); // expected-warning{{TRUE}} +} + +void array_of_struct() { + struct point ptarray[3] = { [2].y = 1, [2].x = 2, [0].x = 3 }; + clang_analyzer_eval(ptarray[0].x == 3); // expected-warning{{TRUE}} + clang_analyzer_eval(ptarray[0].y == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(ptarray[1].x == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(ptarray[1].y == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(ptarray[2].x == 2); // expected-warning{{TRUE}} + clang_analyzer_eval(ptarray[2].y == 1); // expected-warning{{TRUE}} +} diff --git a/clang/test/Analysis/designated-initializer.c b/clang/test/Analysis/designated-initializer.c --- a/clang/test/Analysis/designated-initializer.c +++ b/clang/test/Analysis/designated-initializer.c @@ -31,11 +31,10 @@ // CHECK: 11: struct LUQ var = {getUQ(), .uq.q.a = 100}; // CHECK: 12: 1 // CHECK: 13: 2 -// CHECK: 14: /*implicit*/(int)0 -// CHECK: 15: {[B1.12], [B1.13]} +// CHECK: 14: {[B1.12], [B1.13]} +// CHECK: 17: /*no init*/ // CHECK: 18: /*no init*/ -// CHECK: 19: /*no init*/ -// CHECK: 20: 3 -// CHECK: 21: {[B1.18], [B1.19], [B1.20]} -// CHECK: 22: {/*base*/[B1.17], /*updater*/[B1.21]} -// CHECK: 24: struct Q s[] = {[0] = (struct Q){1, 2}, [0].c = 3}; +// CHECK: 19: 3 +// CHECK: 20: {[B1.17], [B1.18], [B1.19]} +// CHECK: 21: {/*base*/[B1.16], /*updater*/[B1.20]} +// CHECK: 23: struct Q s[] = {[0] = (struct Q){1, 2}, [0].c = 3}; diff --git a/clang/test/Analysis/initializers-cfg-output.cpp b/clang/test/Analysis/initializers-cfg-output.cpp --- a/clang/test/Analysis/initializers-cfg-output.cpp +++ b/clang/test/Analysis/initializers-cfg-output.cpp @@ -126,14 +126,13 @@ // WARNINGS-NEXT: 5: (CXXConstructExpr, class A) // ANALYZER-NEXT: 5: (CXXConstructExpr, A() (Base initializer), class A) // CHECK-NEXT: 6: A([B1.5]) (Base initializer) -// CHECK-NEXT: 7: /*implicit*/(int)0 -// CHECK-NEXT: 8: i([B1.7]) (Member initializer) -// CHECK-NEXT: 9: this -// CHECK-NEXT: 10: [B1.9]->i -// CHECK-NEXT: 11: r([B1.10]) (Member initializer) -// WARNINGS-NEXT: 12: (CXXConstructExpr, class A) -// ANALYZER-NEXT: 12: (CXXConstructExpr, [B1.13], class A) -// CHECK-NEXT: 13: A a; +// CHECK-NEXT: 7: i(/*implicit*/(int)0) (Member initializer) +// CHECK-NEXT: 8: this +// CHECK-NEXT: 9: [B1.8]->i +// CHECK-NEXT: 10: r([B1.9]) (Member initializer) +// WARNINGS-NEXT: 11: (CXXConstructExpr, class A) +// ANALYZER-NEXT: 11: (CXXConstructExpr, [B1.12], class A) +// CHECK-NEXT: 12: A a; // CHECK-NEXT: Preds (2): B2 B3 // CHECK-NEXT: Succs (1): B0 // CHECK: [B2] diff --git a/clang/test/Analysis/temp-obj-dtors-cfg-output.cpp b/clang/test/Analysis/temp-obj-dtors-cfg-output.cpp --- a/clang/test/Analysis/temp-obj-dtors-cfg-output.cpp +++ b/clang/test/Analysis/temp-obj-dtors-cfg-output.cpp @@ -1224,8 +1224,7 @@ // CHECK: 16: a([B1.15]) (Member initializer) // CHECK: 17: ~B() (Temporary object destructor) // CHECK: 18: ~A() (Temporary object destructor) -// CHECK: 19: /*implicit*/(int)0 -// CHECK: 20: b([B1.19]) (Member initializer) +// CHECK: 19: b(/*implicit*/(int)0) (Member initializer) // CHECK: Preds (1): B2 // CHECK: Succs (1): B0 // CHECK: [B0 (EXIT)]