[clang] [analyzer] Support parenthesized list initialization (CXXParenListInitExpr) (PR #148988)
Oleksandr T. via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 17 07:39:11 PDT 2025
https://github.com/a-tarasyuk updated https://github.com/llvm/llvm-project/pull/148988
>From 5db59d5b7f9b834762f86aa69040314e8faeb649 Mon Sep 17 00:00:00 2001
From: Oleksandr Tarasiuk <oleksandr.tarasiuk at outlook.com>
Date: Wed, 16 Jul 2025 02:09:37 +0300
Subject: [PATCH 1/6] [Analyzer] support parenthesized list initialization
---
clang/docs/ReleaseNotes.rst | 2 +
.../Core/PathSensitive/ExprEngine.h | 3 ++
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 7 ++-
.../lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 31 ++++++++++++
clang/test/Analysis/div-zero.cpp | 50 ++++++++++++++++---
5 files changed, 86 insertions(+), 7 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 1eb3e369a302e..06a41700081a9 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -1199,6 +1199,8 @@ Static Analyzer
---------------
- Fixed a crash when C++20 parenthesized initializer lists are used. This issue
was causing a crash in clang-tidy. (#GH136041)
+- The Clang Static Analyzer now handles parenthesized initialization.
+ (#GH148875)
New features
^^^^^^^^^^^^
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 6370586e218ef..79d86aef8a0c6 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -586,6 +586,9 @@ class ExprEngine {
void VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
+ void VisitCXXParenListInitExpr(const CXXParenListInitExpr *PLIE,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
+
/// Create a C++ temporary object for an rvalue.
void CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
ExplodedNode *Pred,
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index c77ef26da568d..8f0cdd46045d0 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1941,7 +1941,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::ConceptSpecializationExprClass:
case Stmt::CXXRewrittenBinaryOperatorClass:
case Stmt::RequiresExprClass:
- case Expr::CXXParenListInitExprClass:
case Stmt::EmbedExprClass:
// Fall through.
@@ -2321,6 +2320,12 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
Bldr.addNodes(Dst);
break;
+ case Expr::CXXParenListInitExprClass:
+ Bldr.takeNodes(Pred);
+ VisitCXXParenListInitExpr(cast<CXXParenListInitExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
+ break;
+
case Stmt::MemberExprClass:
Bldr.takeNodes(Pred);
VisitMemberExpr(cast<MemberExpr>(S), Pred, Dst);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 85353848aa124..059a435bd3e9e 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -1233,3 +1233,34 @@ void ExprEngine::VisitAttributedStmt(const AttributedStmt *A,
getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, A, *this);
}
+
+void ExprEngine::VisitCXXParenListInitExpr(const CXXParenListInitExpr *E,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
+
+ ProgramStateRef S = Pred->getState();
+ QualType T = getContext().getCanonicalType(E->getType());
+
+ const LocationContext *LCtx = Pred->getLocationContext();
+
+ SmallVector<SVal, 4> ArgVals;
+ for (Expr *Arg : E->getInitExprs())
+ ArgVals.push_back(S->getSVal(Arg, LCtx));
+
+ if (!E->isGLValue() && (T->isRecordType() || T->isArrayType())) {
+ llvm::ImmutableList<SVal> ArgList = getBasicVals().getEmptySValList();
+
+ for (const SVal &V : llvm::reverse(ArgVals))
+ ArgList = getBasicVals().prependSVal(V, ArgList);
+
+ Bldr.generateNode(
+ E, Pred, S->BindExpr(E, LCtx, svalBuilder.makeCompoundVal(T, ArgList)));
+ } else {
+ Bldr.generateNode(E, Pred,
+ S->BindExpr(E, LCtx,
+ ArgVals.empty()
+ ? getSValBuilder().makeZeroVal(T)
+ : ArgVals.front()));
+ }
+}
diff --git a/clang/test/Analysis/div-zero.cpp b/clang/test/Analysis/div-zero.cpp
index 063450d8883b0..2a44ad132d4a5 100644
--- a/clang/test/Analysis/div-zero.cpp
+++ b/clang/test/Analysis/div-zero.cpp
@@ -1,13 +1,51 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core.DivideZero -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core.DivideZero -std=c++20 -verify %s
-int fooPR10616 (int qX ) {
+namespace GH10616 {
+int foo(int qX) {
int a, c, d;
- d = (qX-1);
- while ( d != 0 ) {
- d = c - (c/d) * d;
+ d = (qX - 1);
+ while (d != 0) {
+ d = c - (c / d) * d;
}
- return (a % (qX-1)); // expected-warning {{Division by zero}}
+ return (a % (qX - 1)); // expected-warning {{Division by zero}}
+}
+} // namespace GH10616
+
+namespace GH148875 {
+struct A {
+ int x;
+ A(int v) : x(v) {}
+};
+
+struct B {
+ int x;
+ B() : x(0) {}
+};
+
+struct C {
+ int x, y;
+ C(int a, int b) : x(a), y(b) {}
+};
+
+int t1() {
+ A a(42);
+ return 1 / (a.x - 42); // expected-warning {{Division by zero}}
+}
+
+int t2() {
+ B b;
+ return 1 / b.x; // expected-warning {{Division by zero}}
+}
+
+int t3() {
+ C c1(1, -1);
+ return 1 / (c1.x + c1.y); // expected-warning {{Division by zero}}
+}
+int t4() {
+ C c2(0, 0);
+ return 1 / (c2.x + c2.y); // expected-warning {{Division by zero}}
}
+} // namespace GH148875
>From a2a7346a4770e5a857b2e6234124170f71019695 Mon Sep 17 00:00:00 2001
From: Oleksandr Tarasiuk <oleksandr.tarasiuk at outlook.com>
Date: Wed, 16 Jul 2025 16:44:25 +0300
Subject: [PATCH 2/6] add additinal tests
---
clang/test/Analysis/div-zero.cpp | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/clang/test/Analysis/div-zero.cpp b/clang/test/Analysis/div-zero.cpp
index 2a44ad132d4a5..cdfac210e174e 100644
--- a/clang/test/Analysis/div-zero.cpp
+++ b/clang/test/Analysis/div-zero.cpp
@@ -29,6 +29,15 @@ struct C {
C(int a, int b) : x(a), y(b) {}
};
+struct D {
+ int x;
+};
+
+struct E {
+ D d;
+ E(int a) : d(a) {}
+};
+
int t1() {
A a(42);
return 1 / (a.x - 42); // expected-warning {{Division by zero}}
@@ -48,4 +57,9 @@ int t4() {
C c2(0, 0);
return 1 / (c2.x + c2.y); // expected-warning {{Division by zero}}
}
+
+int t5() {
+ E e = 32;
+ return 1 / (e.d.x - 32); // expected-warning {{Division by zero}}
+}
} // namespace GH148875
>From 8bb56ceae99e43b62b6635b8c8143e530313efb4 Mon Sep 17 00:00:00 2001
From: Oleksandr Tarasiuk <oleksandr.tarasiuk at outlook.com>
Date: Wed, 16 Jul 2025 16:46:06 +0300
Subject: [PATCH 3/6] remove redundant vector
---
.../lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 27 +++++++++----------
1 file changed, 12 insertions(+), 15 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 059a435bd3e9e..fde3939a07e29 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -1237,30 +1237,27 @@ void ExprEngine::VisitAttributedStmt(const AttributedStmt *A,
void ExprEngine::VisitCXXParenListInitExpr(const CXXParenListInitExpr *E,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
+ const LocationContext *LC = Pred->getLocationContext();
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
ProgramStateRef S = Pred->getState();
- QualType T = getContext().getCanonicalType(E->getType());
- const LocationContext *LCtx = Pred->getLocationContext();
+ QualType T = E->getType().getCanonicalType();
+ ArrayRef<Expr *> Inits = E->getInitExprs();
- SmallVector<SVal, 4> ArgVals;
- for (Expr *Arg : E->getInitExprs())
- ArgVals.push_back(S->getSVal(Arg, LCtx));
-
- if (!E->isGLValue() && (T->isRecordType() || T->isArrayType())) {
+ if (Inits.size() > 1 ||
+ (E->isPRValue() && (T->isRecordType() || T->isArrayType()))) {
llvm::ImmutableList<SVal> ArgList = getBasicVals().getEmptySValList();
-
- for (const SVal &V : llvm::reverse(ArgVals))
- ArgList = getBasicVals().prependSVal(V, ArgList);
+ for (Expr *E : llvm::reverse(Inits))
+ ArgList = getBasicVals().prependSVal(S->getSVal(E, LC), ArgList);
Bldr.generateNode(
- E, Pred, S->BindExpr(E, LCtx, svalBuilder.makeCompoundVal(T, ArgList)));
+ E, Pred, S->BindExpr(E, LC, svalBuilder.makeCompoundVal(T, ArgList)));
} else {
Bldr.generateNode(E, Pred,
- S->BindExpr(E, LCtx,
- ArgVals.empty()
+ S->BindExpr(E, LC,
+ Inits.size() == 0
? getSValBuilder().makeZeroVal(T)
- : ArgVals.front()));
+ : S->getSVal(Inits.front(), LC)));
}
}
>From 6d3dd39d4c68f1b0cfbb6f51b4cc2c6acd4d7318 Mon Sep 17 00:00:00 2001
From: Oleksandr Tarasiuk <oleksandr.tarasiuk at outlook.com>
Date: Wed, 16 Jul 2025 18:20:04 +0300
Subject: [PATCH 4/6] revert test
---
clang/test/Analysis/div-zero.cpp | 64 +++-----------------------------
1 file changed, 6 insertions(+), 58 deletions(-)
diff --git a/clang/test/Analysis/div-zero.cpp b/clang/test/Analysis/div-zero.cpp
index cdfac210e174e..063450d8883b0 100644
--- a/clang/test/Analysis/div-zero.cpp
+++ b/clang/test/Analysis/div-zero.cpp
@@ -1,65 +1,13 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core.DivideZero -std=c++20 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core.DivideZero -verify %s
-namespace GH10616 {
-int foo(int qX) {
+int fooPR10616 (int qX ) {
int a, c, d;
- d = (qX - 1);
- while (d != 0) {
- d = c - (c / d) * d;
+ d = (qX-1);
+ while ( d != 0 ) {
+ d = c - (c/d) * d;
}
- return (a % (qX - 1)); // expected-warning {{Division by zero}}
-}
-} // namespace GH10616
-
-namespace GH148875 {
-struct A {
- int x;
- A(int v) : x(v) {}
-};
-
-struct B {
- int x;
- B() : x(0) {}
-};
-
-struct C {
- int x, y;
- C(int a, int b) : x(a), y(b) {}
-};
-
-struct D {
- int x;
-};
-
-struct E {
- D d;
- E(int a) : d(a) {}
-};
-
-int t1() {
- A a(42);
- return 1 / (a.x - 42); // expected-warning {{Division by zero}}
-}
-
-int t2() {
- B b;
- return 1 / b.x; // expected-warning {{Division by zero}}
-}
-
-int t3() {
- C c1(1, -1);
- return 1 / (c1.x + c1.y); // expected-warning {{Division by zero}}
-}
-
-int t4() {
- C c2(0, 0);
- return 1 / (c2.x + c2.y); // expected-warning {{Division by zero}}
-}
+ return (a % (qX-1)); // expected-warning {{Division by zero}}
-int t5() {
- E e = 32;
- return 1 / (e.d.x - 32); // expected-warning {{Division by zero}}
}
-} // namespace GH148875
>From 64de252d3d87e87a9c1aa05b5f22fe51b099fcfc Mon Sep 17 00:00:00 2001
From: Oleksandr Tarasiuk <oleksandr.tarasiuk at outlook.com>
Date: Wed, 16 Jul 2025 18:20:20 +0300
Subject: [PATCH 5/6] add test relaetd to c++20 only
---
clang/test/Analysis/div-zero-cxx20.cpp | 52 ++++++++++++++++++++++++++
1 file changed, 52 insertions(+)
create mode 100644 clang/test/Analysis/div-zero-cxx20.cpp
diff --git a/clang/test/Analysis/div-zero-cxx20.cpp b/clang/test/Analysis/div-zero-cxx20.cpp
new file mode 100644
index 0000000000000..efc54a275e874
--- /dev/null
+++ b/clang/test/Analysis/div-zero-cxx20.cpp
@@ -0,0 +1,52 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core.DivideZero -std=c++20 -verify %s
+
+namespace GH148875 {
+struct A {
+ int x;
+ A(int v) : x(v) {}
+};
+
+struct B {
+ int x;
+ B() : x(0) {}
+};
+
+struct C {
+ int x, y;
+ C(int a, int b) : x(a), y(b) {}
+};
+
+struct D {
+ int x;
+};
+
+struct E {
+ D d;
+ E(int a) : d(a) {}
+};
+
+int t1() {
+ A a(42);
+ return 1 / (a.x - 42); // expected-warning {{Division by zero}}
+}
+
+int t2() {
+ B b;
+ return 1 / b.x; // expected-warning {{Division by zero}}
+}
+
+int t3() {
+ C c1(1, -1);
+ return 1 / (c1.x + c1.y); // expected-warning {{Division by zero}}
+}
+
+int t4() {
+ C c2(0, 0);
+ return 1 / (c2.x + c2.y); // expected-warning {{Division by zero}}
+}
+
+int t5() {
+ E e = 32;
+ return 1 / (e.d.x - 32); // expected-warning {{Division by zero}}
+}
+} // namespace GH148875
>From db6f5d6a90b7fe1ed49983d181bc0fae4daa5297 Mon Sep 17 00:00:00 2001
From: Oleksandr Tarasiuk <oleksandr.tarasiuk at outlook.com>
Date: Thu, 17 Jul 2025 17:38:15 +0300
Subject: [PATCH 6/6] share initializer list modeling between VisitInitListExpr
and VisitCXXParenListInitExpr
---
.../Core/PathSensitive/ExprEngine.h | 4 +
clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 77 ++++++++-----------
.../lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 25 +-----
clang/test/Analysis/div-zero-cxx20.cpp | 10 +--
clang/test/Analysis/div-zero.cpp | 51 ++++++++++++
5 files changed, 96 insertions(+), 71 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 79d86aef8a0c6..2810e10e0bec8 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -594,6 +594,10 @@ class ExprEngine {
ExplodedNode *Pred,
ExplodedNodeSet &Dst);
+ void CreateInitializationList(const Expr *Source, ArrayRef<Expr *> Args,
+ bool IsTransparent, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
/// evalEagerlyAssumeBifurcation - Given the nodes in 'Src', eagerly assume
/// concrete boolean values for 'Ex', storing the resulting nodes in 'Dst'.
void evalEagerlyAssumeBifurcation(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index fa8e669b6bb2f..997d8f0186765 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -774,49 +774,7 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
void ExprEngine::VisitInitListExpr(const InitListExpr *IE,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- StmtNodeBuilder B(Pred, Dst, *currBldrCtx);
-
- ProgramStateRef state = Pred->getState();
- const LocationContext *LCtx = Pred->getLocationContext();
- QualType T = getContext().getCanonicalType(IE->getType());
- unsigned NumInitElements = IE->getNumInits();
-
- if (!IE->isGLValue() && !IE->isTransparent() &&
- (T->isArrayType() || T->isRecordType() || T->isVectorType() ||
- T->isAnyComplexType())) {
- llvm::ImmutableList<SVal> vals = getBasicVals().getEmptySValList();
-
- // Handle base case where the initializer has no elements.
- // e.g: static int* myArray[] = {};
- if (NumInitElements == 0) {
- SVal V = svalBuilder.makeCompoundVal(T, vals);
- B.generateNode(IE, Pred, state->BindExpr(IE, LCtx, V));
- return;
- }
-
- for (const Stmt *S : llvm::reverse(*IE)) {
- SVal V = state->getSVal(cast<Expr>(S), LCtx);
- vals = getBasicVals().prependSVal(V, vals);
- }
-
- B.generateNode(IE, Pred,
- state->BindExpr(IE, LCtx,
- svalBuilder.makeCompoundVal(T, vals)));
- return;
- }
-
- // Handle scalars: int{5} and int{} and GLvalues.
- // Note, if the InitListExpr is a GLvalue, it means that there is an address
- // representing it, so it must have a single init element.
- assert(NumInitElements <= 1);
-
- SVal V;
- if (NumInitElements == 0)
- V = getSValBuilder().makeZeroVal(T);
- else
- V = state->getSVal(IE->getInit(0), LCtx);
-
- B.generateNode(IE, Pred, state->BindExpr(IE, LCtx, V));
+ CreateInitializationList(IE, IE->inits(), IE->isTransparent(), Pred, Dst);
}
void ExprEngine::VisitGuardedExpr(const Expr *Ex,
@@ -1197,3 +1155,36 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
}
Dst.insert(Dst2);
}
+
+void ExprEngine::CreateInitializationList(const Expr *E, ArrayRef<Expr *> Args,
+ bool IsTransparent,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ assert((isa<InitListExpr>(E) || isa<CXXParenListInitExpr>(E)) &&
+ "Expected InitListExpr or CXXParenListInitExpr");
+
+ const LocationContext *LC = Pred->getLocationContext();
+
+ StmtNodeBuilder B(Pred, Dst, *currBldrCtx);
+ ProgramStateRef S = Pred->getState();
+ QualType T = E->getType().getCanonicalType();
+
+ bool IsCompound =
+ E->isPRValue() && (T->isArrayType() || T->isRecordType() ||
+ T->isAnyComplexType() || T->isVectorType());
+
+ if (Args.size() > 1 || (IsCompound && !IsTransparent)) {
+ llvm::ImmutableList<SVal> ArgList = getBasicVals().getEmptySValList();
+ for (Expr *E : llvm::reverse(Args))
+ ArgList = getBasicVals().prependSVal(S->getSVal(E, LC), ArgList);
+
+ B.generateNode(E, Pred,
+ S->BindExpr(E, LC, svalBuilder.makeCompoundVal(T, ArgList)));
+ } else {
+ B.generateNode(E, Pred,
+ S->BindExpr(E, LC,
+ Args.size() == 0
+ ? getSValBuilder().makeZeroVal(T)
+ : S->getSVal(Args.front(), LC)));
+ }
+}
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index fde3939a07e29..08b334ec1f13b 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -1237,27 +1237,6 @@ void ExprEngine::VisitAttributedStmt(const AttributedStmt *A,
void ExprEngine::VisitCXXParenListInitExpr(const CXXParenListInitExpr *E,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- const LocationContext *LC = Pred->getLocationContext();
-
- StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
- ProgramStateRef S = Pred->getState();
-
- QualType T = E->getType().getCanonicalType();
- ArrayRef<Expr *> Inits = E->getInitExprs();
-
- if (Inits.size() > 1 ||
- (E->isPRValue() && (T->isRecordType() || T->isArrayType()))) {
- llvm::ImmutableList<SVal> ArgList = getBasicVals().getEmptySValList();
- for (Expr *E : llvm::reverse(Inits))
- ArgList = getBasicVals().prependSVal(S->getSVal(E, LC), ArgList);
-
- Bldr.generateNode(
- E, Pred, S->BindExpr(E, LC, svalBuilder.makeCompoundVal(T, ArgList)));
- } else {
- Bldr.generateNode(E, Pred,
- S->BindExpr(E, LC,
- Inits.size() == 0
- ? getSValBuilder().makeZeroVal(T)
- : S->getSVal(Inits.front(), LC)));
- }
+ CreateInitializationList(E, E->getInitExprs(), /*IsTransparent*/ false, Pred,
+ Dst);
}
diff --git a/clang/test/Analysis/div-zero-cxx20.cpp b/clang/test/Analysis/div-zero-cxx20.cpp
index efc54a275e874..adc75344970d2 100644
--- a/clang/test/Analysis/div-zero-cxx20.cpp
+++ b/clang/test/Analysis/div-zero-cxx20.cpp
@@ -26,27 +26,27 @@ struct E {
};
int t1() {
- A a(42);
+ A a{42};
return 1 / (a.x - 42); // expected-warning {{Division by zero}}
}
int t2() {
- B b;
+ B b{};
return 1 / b.x; // expected-warning {{Division by zero}}
}
int t3() {
- C c1(1, -1);
+ C c1{1, -1};
return 1 / (c1.x + c1.y); // expected-warning {{Division by zero}}
}
int t4() {
- C c2(0, 0);
+ C c2{0, 0};
return 1 / (c2.x + c2.y); // expected-warning {{Division by zero}}
}
int t5() {
- E e = 32;
+ E e{32};
return 1 / (e.d.x - 32); // expected-warning {{Division by zero}}
}
} // namespace GH148875
diff --git a/clang/test/Analysis/div-zero.cpp b/clang/test/Analysis/div-zero.cpp
index 063450d8883b0..498ad159afab0 100644
--- a/clang/test/Analysis/div-zero.cpp
+++ b/clang/test/Analysis/div-zero.cpp
@@ -11,3 +11,54 @@ int fooPR10616 (int qX ) {
return (a % (qX-1)); // expected-warning {{Division by zero}}
}
+
+namespace GH148875 {
+ struct A {
+ int x;
+ A(int v) : x(v) {}
+};
+
+struct B {
+ int x;
+ B() : x(0) {}
+};
+
+struct C {
+ int x, y;
+ C(int a, int b) : x(a), y(b) {}
+};
+
+struct D {
+ int x;
+};
+
+struct E {
+ D d;
+ E(int a) : d{a} {}
+};
+
+int t1() {
+ A a{42};
+ return 1 / (a.x - 42); // expected-warning {{Division by zero}}
+}
+
+int t2() {
+ B b{};
+ return 1 / b.x; // expected-warning {{Division by zero}}
+}
+
+int t3() {
+ C c1{1, -1};
+ return 1 / (c1.x + c1.y); // expected-warning {{Division by zero}}
+}
+
+int t4() {
+ C c2{0, 0};
+ return 1 / (c2.x + c2.y); // expected-warning {{Division by zero}}
+}
+
+int t5() {
+ E e{32};
+ return 1 / (e.d.x - 32); // expected-warning {{Division by zero}}
+}
+}
More information about the cfe-commits
mailing list