[clang] [analyzer] Support parenthesized list initialization (CXXParenListInitExpr) (PR #148988)

2025-07-17 Thread Balazs Benics via cfe-commits

https://github.com/steakhal approved this pull request.

Lets land this. Thank you!

https://github.com/llvm/llvm-project/pull/148988
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Support parenthesized list initialization (CXXParenListInitExpr) (PR #148988)

2025-07-17 Thread Oleksandr T. via cfe-commits

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 
Date: Wed, 16 Jul 2025 02:09:37 +0300
Subject: [PATCH 1/9] [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(S), Pred, Dst);
+  Bldr.addNodes(Dst);
+  break;
+
 case Stmt::MemberExprClass:
   Bldr.takeNodes(Pred);
   VisitMemberExpr(cast(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 ArgVals;
+  for (Expr *Arg : E->getInitExprs())
+ArgVals.push_back(S->getSVal(Arg, LCtx));
+
+  if (!E->isGLValue() && (T->isRecordType() || T->isArrayType())) {
+llvm::ImmutableList 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 =

[clang] [analyzer] Support parenthesized list initialization (CXXParenListInitExpr) (PR #148988)

2025-07-17 Thread Oleksandr T. via cfe-commits

a-tarasyuk wrote:

@steakhal should other test cases be removed? 

https://github.com/llvm/llvm-project/pull/148988
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Support parenthesized list initialization (CXXParenListInitExpr) (PR #148988)

2025-07-17 Thread Oleksandr T. via cfe-commits


@@ -4114,3 +4124,35 @@ void 
*ProgramStateTrait::GDMIndex() {
 }
 
 void ExprEngine::anchor() { }
+
+void ExprEngine::ConstructInitList(const Expr *E, ArrayRef Args,
+   bool IsTransparent, ExplodedNode *Pred,
+   ExplodedNodeSet &Dst) {
+  assert((isa(E) || isa(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());

a-tarasyuk wrote:

@steakhal thanks, I've updated this condition

https://github.com/llvm/llvm-project/pull/148988
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Support parenthesized list initialization (CXXParenListInitExpr) (PR #148988)

2025-07-17 Thread Oleksandr T. via cfe-commits

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 
Date: Wed, 16 Jul 2025 02:09:37 +0300
Subject: [PATCH 1/8] [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(S), Pred, Dst);
+  Bldr.addNodes(Dst);
+  break;
+
 case Stmt::MemberExprClass:
   Bldr.takeNodes(Pred);
   VisitMemberExpr(cast(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 ArgVals;
+  for (Expr *Arg : E->getInitExprs())
+ArgVals.push_back(S->getSVal(Arg, LCtx));
+
+  if (!E->isGLValue() && (T->isRecordType() || T->isArrayType())) {
+llvm::ImmutableList 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 =

[clang] [analyzer] Support parenthesized list initialization (CXXParenListInitExpr) (PR #148988)

2025-07-17 Thread Balazs Benics via cfe-commits

steakhal wrote:

@a-tarasyuk Could you also add the test case from the issue as-is?

https://github.com/llvm/llvm-project/pull/148988
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Support parenthesized list initialization (CXXParenListInitExpr) (PR #148988)

2025-07-17 Thread Balazs Benics via cfe-commits


@@ -4114,3 +4124,35 @@ void 
*ProgramStateTrait::GDMIndex() {
 }
 
 void ExprEngine::anchor() { }
+
+void ExprEngine::ConstructInitList(const Expr *E, ArrayRef Args,
+   bool IsTransparent, ExplodedNode *Pred,
+   ExplodedNodeSet &Dst) {
+  assert((isa(E) || isa(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());

steakhal wrote:

By judging the name `IsCompound`, I was expecting `E->isPRValue()` being 
separated.

https://github.com/llvm/llvm-project/pull/148988
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Support parenthesized list initialization (CXXParenListInitExpr) (PR #148988)

2025-07-17 Thread Balazs Benics via cfe-commits

https://github.com/steakhal commented:

Looks really good. Thanks for going the extra mile with the refactor.

https://github.com/llvm/llvm-project/pull/148988
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Support parenthesized list initialization (CXXParenListInitExpr) (PR #148988)

2025-07-17 Thread Balazs Benics via cfe-commits

https://github.com/steakhal edited 
https://github.com/llvm/llvm-project/pull/148988
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Support parenthesized list initialization (CXXParenListInitExpr) (PR #148988)

2025-07-17 Thread Balazs Benics via cfe-commits


@@ -4114,3 +4124,35 @@ void 
*ProgramStateTrait::GDMIndex() {
 }
 
 void ExprEngine::anchor() { }
+
+void ExprEngine::ConstructInitList(const Expr *E, ArrayRef Args,
+   bool IsTransparent, ExplodedNode *Pred,
+   ExplodedNodeSet &Dst) {
+  assert((isa(E) || isa(E)) &&
+ "Expected InitListExpr or CXXParenListInitExpr");

steakhal wrote:

```suggestion
  assert((isa(E)));
```

https://github.com/llvm/llvm-project/pull/148988
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [analyzer] Support parenthesized list initialization (CXXParenListInitExpr) (PR #148988)

2025-07-17 Thread Oleksandr T. via cfe-commits

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 
Date: Wed, 16 Jul 2025 02:09:37 +0300
Subject: [PATCH 1/7] [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(S), Pred, Dst);
+  Bldr.addNodes(Dst);
+  break;
+
 case Stmt::MemberExprClass:
   Bldr.takeNodes(Pred);
   VisitMemberExpr(cast(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 ArgVals;
+  for (Expr *Arg : E->getInitExprs())
+ArgVals.push_back(S->getSVal(Arg, LCtx));
+
+  if (!E->isGLValue() && (T->isRecordType() || T->isArrayType())) {
+llvm::ImmutableList 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 =

[clang] [analyzer] Support parenthesized list initialization (CXXParenListInitExpr) (PR #148988)

2025-07-17 Thread Oleksandr T. via cfe-commits

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 
Date: Wed, 16 Jul 2025 02:09:37 +0300
Subject: [PATCH 1/7] [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(S), Pred, Dst);
+  Bldr.addNodes(Dst);
+  break;
+
 case Stmt::MemberExprClass:
   Bldr.takeNodes(Pred);
   VisitMemberExpr(cast(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 ArgVals;
+  for (Expr *Arg : E->getInitExprs())
+ArgVals.push_back(S->getSVal(Arg, LCtx));
+
+  if (!E->isGLValue() && (T->isRecordType() || T->isArrayType())) {
+llvm::ImmutableList 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 =

[clang] [analyzer] Support parenthesized list initialization (CXXParenListInitExpr) (PR #148988)

2025-07-17 Thread Oleksandr T. via cfe-commits

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 
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(S), Pred, Dst);
+  Bldr.addNodes(Dst);
+  break;
+
 case Stmt::MemberExprClass:
   Bldr.takeNodes(Pred);
   VisitMemberExpr(cast(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 ArgVals;
+  for (Expr *Arg : E->getInitExprs())
+ArgVals.push_back(S->getSVal(Arg, LCtx));
+
+  if (!E->isGLValue() && (T->isRecordType() || T->isArrayType())) {
+llvm::ImmutableList 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 =

[clang] [analyzer] Support parenthesized list initialization (CXXParenListInitExpr) (PR #148988)

2025-07-17 Thread Balazs Benics via cfe-commits

https://github.com/steakhal edited 
https://github.com/llvm/llvm-project/pull/148988
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits