Skip to content

Commit 5db59d5

Browse files
committed
[Analyzer] support parenthesized list initialization
1 parent c36156d commit 5db59d5

File tree

5 files changed

+86
-7
lines changed

5 files changed

+86
-7
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,6 +1199,8 @@ Static Analyzer
11991199
---------------
12001200
- Fixed a crash when C++20 parenthesized initializer lists are used. This issue
12011201
was causing a crash in clang-tidy. (#GH136041)
1202+
- The Clang Static Analyzer now handles parenthesized initialization.
1203+
(#GH148875)
12021204

12031205
New features
12041206
^^^^^^^^^^^^

clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,9 @@ class ExprEngine {
586586
void VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, ExplodedNode *Pred,
587587
ExplodedNodeSet &Dst);
588588

589+
void VisitCXXParenListInitExpr(const CXXParenListInitExpr *PLIE,
590+
ExplodedNode *Pred, ExplodedNodeSet &Dst);
591+
589592
/// Create a C++ temporary object for an rvalue.
590593
void CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
591594
ExplodedNode *Pred,

clang/lib/StaticAnalyzer/Core/ExprEngine.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1941,7 +1941,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
19411941
case Stmt::ConceptSpecializationExprClass:
19421942
case Stmt::CXXRewrittenBinaryOperatorClass:
19431943
case Stmt::RequiresExprClass:
1944-
case Expr::CXXParenListInitExprClass:
19451944
case Stmt::EmbedExprClass:
19461945
// Fall through.
19471946

@@ -2321,6 +2320,12 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
23212320
Bldr.addNodes(Dst);
23222321
break;
23232322

2323+
case Expr::CXXParenListInitExprClass:
2324+
Bldr.takeNodes(Pred);
2325+
VisitCXXParenListInitExpr(cast<CXXParenListInitExpr>(S), Pred, Dst);
2326+
Bldr.addNodes(Dst);
2327+
break;
2328+
23242329
case Stmt::MemberExprClass:
23252330
Bldr.takeNodes(Pred);
23262331
VisitMemberExpr(cast<MemberExpr>(S), Pred, Dst);

clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,3 +1233,34 @@ void ExprEngine::VisitAttributedStmt(const AttributedStmt *A,
12331233

12341234
getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, A, *this);
12351235
}
1236+
1237+
void ExprEngine::VisitCXXParenListInitExpr(const CXXParenListInitExpr *E,
1238+
ExplodedNode *Pred,
1239+
ExplodedNodeSet &Dst) {
1240+
StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
1241+
1242+
ProgramStateRef S = Pred->getState();
1243+
QualType T = getContext().getCanonicalType(E->getType());
1244+
1245+
const LocationContext *LCtx = Pred->getLocationContext();
1246+
1247+
SmallVector<SVal, 4> ArgVals;
1248+
for (Expr *Arg : E->getInitExprs())
1249+
ArgVals.push_back(S->getSVal(Arg, LCtx));
1250+
1251+
if (!E->isGLValue() && (T->isRecordType() || T->isArrayType())) {
1252+
llvm::ImmutableList<SVal> ArgList = getBasicVals().getEmptySValList();
1253+
1254+
for (const SVal &V : llvm::reverse(ArgVals))
1255+
ArgList = getBasicVals().prependSVal(V, ArgList);
1256+
1257+
Bldr.generateNode(
1258+
E, Pred, S->BindExpr(E, LCtx, svalBuilder.makeCompoundVal(T, ArgList)));
1259+
} else {
1260+
Bldr.generateNode(E, Pred,
1261+
S->BindExpr(E, LCtx,
1262+
ArgVals.empty()
1263+
? getSValBuilder().makeZeroVal(T)
1264+
: ArgVals.front()));
1265+
}
1266+
}

clang/test/Analysis/div-zero.cpp

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,51 @@
1-
// RUN: %clang_analyze_cc1 -analyzer-checker=core.DivideZero -verify %s
1+
// RUN: %clang_analyze_cc1 -analyzer-checker=core.DivideZero -std=c++20 -verify %s
22

3-
int fooPR10616 (int qX ) {
3+
namespace GH10616 {
4+
int foo(int qX) {
45
int a, c, d;
56

6-
d = (qX-1);
7-
while ( d != 0 ) {
8-
d = c - (c/d) * d;
7+
d = (qX - 1);
8+
while (d != 0) {
9+
d = c - (c / d) * d;
910
}
1011

11-
return (a % (qX-1)); // expected-warning {{Division by zero}}
12+
return (a % (qX - 1)); // expected-warning {{Division by zero}}
13+
}
14+
} // namespace GH10616
15+
16+
namespace GH148875 {
17+
struct A {
18+
int x;
19+
A(int v) : x(v) {}
20+
};
21+
22+
struct B {
23+
int x;
24+
B() : x(0) {}
25+
};
26+
27+
struct C {
28+
int x, y;
29+
C(int a, int b) : x(a), y(b) {}
30+
};
31+
32+
int t1() {
33+
A a(42);
34+
return 1 / (a.x - 42); // expected-warning {{Division by zero}}
35+
}
36+
37+
int t2() {
38+
B b;
39+
return 1 / b.x; // expected-warning {{Division by zero}}
40+
}
41+
42+
int t3() {
43+
C c1(1, -1);
44+
return 1 / (c1.x + c1.y); // expected-warning {{Division by zero}}
45+
}
1246

47+
int t4() {
48+
C c2(0, 0);
49+
return 1 / (c2.x + c2.y); // expected-warning {{Division by zero}}
1350
}
51+
} // namespace GH148875

0 commit comments

Comments
 (0)