https://github.com/Snape3058 updated 
https://github.com/llvm/llvm-project/pull/187530

>From 1d87171dc76bab8fd78e60deb9b239874c5fd83b Mon Sep 17 00:00:00 2001
From: Ella Ma <[email protected]>
Date: Thu, 19 Mar 2026 14:15:11 +0100
Subject: [PATCH 1/6] wip-2026-03-19_16:24:09

---
 clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 14 +++++++++
 .../Analysis/issue-173210-self-assign-init.c  | 29 +++++++++++++++++++
 2 files changed, 43 insertions(+)
 create mode 100644 clang/test/Analysis/issue-173210-self-assign-init.c

diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp 
b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 67beed5dbb6fb..214f266e21e4c 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -624,6 +624,20 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, 
ExplodedNode *Pred,
     return;
   }
 
+  // Bypass a nop initialization that assign to itself at variable declaration.
+  // I.e., int x = x;
+  // This is an idiom in C code and GCC will not generate any assemblies for
+  // this self initialization, even under -O0, but Clang will.
+  // Since the frontend will warn in C++ code, and it is ill-formed for C++
+  // reference types, the bypass is effected to C code only.
+  if (getContext().getLangOpts().getCLangStd())
+    if (const Expr *EI = VD->getInit())
+      if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(EI->IgnoreImpCasts()))
+        if (VD == DR->getDecl()) {
+          Dst.insert(Pred);
+          return;
+        }
+
   // FIXME: all pre/post visits should eventually be handled by ::Visit().
   ExplodedNodeSet dstPreVisit;
   getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, DS, *this);
diff --git a/clang/test/Analysis/issue-173210-self-assign-init.c 
b/clang/test/Analysis/issue-173210-self-assign-init.c
new file mode 100644
index 0000000000000..c9e5e2be58875
--- /dev/null
+++ b/clang/test/Analysis/issue-173210-self-assign-init.c
@@ -0,0 +1,29 @@
+// RUN: %clang_analyze_cc1 %s \
+// RUN:   -analyzer-checker=core,debug.ExprInspection \
+// RUN:   -verify
+
+// Self assignment initialization in C code will be treated as nop.
+// We will not report the VarDecl, but the following DeclRefExpr if it has not
+// yet been initialized then.
+
+void clang_analyzer_warnIfReached();
+
+struct S { int x; };
+union U { int x; };
+
+void nowarn() {
+  int x = x; // no-warning
+  int *p = p; // no-warning
+  struct S s = s; // no-warning
+  union U u = u; // no-warning
+  // Ensure the analysis is not terminated sliently.
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+int warn() {
+  int x = x;
+  return x; // expected-warning{{Undefined or garbage value returned to 
caller}}
+}
+
+// NOTE: The self assignment of reference type is tested with 
stack-addr-ps.cpp.
+// I.e., `int& i = i;` in function f5

>From 90734881a4366bfcc80e05e1407caadbcec3056a Mon Sep 17 00:00:00 2001
From: Ella Ma <[email protected]>
Date: Fri, 15 May 2026 14:40:46 +0200
Subject: [PATCH 2/6] wip-2026-05-15_14:40:41

---
 clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 24 +++++++++++-------
 .../Analysis/issue-173210-self-assign-init.c  | 25 +++++++++++++------
 2 files changed, 32 insertions(+), 17 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp 
b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 214f266e21e4c..c003ad015bb1b 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -626,15 +626,21 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, 
ExplodedNode *Pred,
 
   // Bypass a nop initialization that assign to itself at variable declaration.
   // I.e., int x = x;
-  // This is an idiom in C code and GCC will not generate any assemblies for
-  // this self initialization, even under -O0, but Clang will.
-  // Since the frontend will warn in C++ code, and it is ill-formed for C++
-  // reference types, the bypass is effected to C code only.
-  if (getContext().getLangOpts().getCLangStd())
-    if (const Expr *EI = VD->getInit())
-      if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(EI->IgnoreImpCasts()))
-        if (VD == DR->getDecl()) {
-          Dst.insert(Pred);
+  // This is an idiom in C code, and GCC will not generate any assemblies for
+  // this self initialization, even under -O0, although Clang will.
+  // We therefore ignore all types for C code.
+  // For C++ code, Sema will not report for fundamental types and pointers.
+  // We hence also ignore them as in C, but leave the uninitialized variable
+  // report of references to the checker. For record types, as their AST
+  // structures are different in C++, they will not hit the filter here and
+  // will be checked by the checker.
+  if (const Expr *EI = VD->getInit())
+    if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(EI->IgnoreImpCasts()))
+      if (VD == DR->getDecl())
+        if (getContext().getLangOpts().getCLangStd() ||
+            (getContext().getLangOpts().getCPlusPlusLangStd() &&
+             !VD->getType()->isReferenceType())) {
+          Dst.Add(Pred);
           return;
         }
 
diff --git a/clang/test/Analysis/issue-173210-self-assign-init.c 
b/clang/test/Analysis/issue-173210-self-assign-init.c
index c9e5e2be58875..bf943554f18a9 100644
--- a/clang/test/Analysis/issue-173210-self-assign-init.c
+++ b/clang/test/Analysis/issue-173210-self-assign-init.c
@@ -1,6 +1,9 @@
-// RUN: %clang_analyze_cc1 %s \
+// RUN: %clang_analyze_cc1 -xc %s \
 // RUN:   -analyzer-checker=core,debug.ExprInspection \
 // RUN:   -verify
+// RUN: %clang_analyze_cc1 -xc++ %s \
+// RUN:   -analyzer-checker=core,debug.ExprInspection \
+// RUN:   -verify -w
 
 // Self assignment initialization in C code will be treated as nop.
 // We will not report the VarDecl, but the following DeclRefExpr if it has not
@@ -12,18 +15,24 @@ struct S { int x; };
 union U { int x; };
 
 void nowarn() {
-  int x = x; // no-warning
-  int *p = p; // no-warning
-  struct S s = s; // no-warning
-  union U u = u; // no-warning
+  int x = x; // no-warnings for C/C++
+  int *p = p; // no-warnings for C/C++
+  struct S s = s; // no-warning for C, but C++ will not report
+  union U u = u; // no-warning for C, but C++ will not report
   // Ensure the analysis is not terminated sliently.
   clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
 }
 
 int warn() {
-  int x = x;
+  int x = x; // no-warnings for C/C++
   return x; // expected-warning{{Undefined or garbage value returned to 
caller}}
 }
 
-// NOTE: The self assignment of reference type is tested with 
stack-addr-ps.cpp.
-// I.e., `int& i = i;` in function f5
+// NOTE: The self assignment of reference type is also tested in 
stack-addr-ps.cpp.
+// E.g., `int& i = i;` in function f5
+// We only keep a simple regression confirmation here.
+#ifdef __cplusplus
+void warnref() {
+  int &x = x; // expected-warning{{Assigned value is uninitialized}}
+}
+#endif // __cplusplus

>From 832c8ab35525b2690db00269ad3b231ab1486087 Mon Sep 17 00:00:00 2001
From: Ella Ma <[email protected]>
Date: Fri, 15 May 2026 15:41:52 +0200
Subject: [PATCH 3/6] Add or insert? I am really confused :(

---
 clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp 
b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index c003ad015bb1b..e418423e2cccb 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -640,7 +640,7 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, 
ExplodedNode *Pred,
         if (getContext().getLangOpts().getCLangStd() ||
             (getContext().getLangOpts().getCPlusPlusLangStd() &&
              !VD->getType()->isReferenceType())) {
-          Dst.Add(Pred);
+          Dst.insert(Pred);
           return;
         }
 

>From b233e4b9a00ed5791e338bd45bfdb3fbc3744071 Mon Sep 17 00:00:00 2001
From: Ella Ma <[email protected]>
Date: Wed, 27 May 2026 19:30:20 +0200
Subject: [PATCH 4/6] add the fix for deadcode.DeadStores, reusing the test
 case

---
 clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp | 6 ++++++
 clang/test/Analysis/issue-173210-self-assign-init.c     | 4 ++--
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
index 48e358c1e6242..0d693a3e3ff3d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -431,6 +431,12 @@ class DeadStoreObs : public LiveVariables::Observer {
                   //  bug.
                   if (isa<ParmVarDecl>(VD) && VD->getType()->isScalarType())
                     return;
+                  // Special case: check for self-initializations.
+                  //
+                  //  e.g. int x = x;
+                  //
+                  if (VD == V)
+                    return;
                 }
 
               PathDiagnosticLocation Loc =
diff --git a/clang/test/Analysis/issue-173210-self-assign-init.c 
b/clang/test/Analysis/issue-173210-self-assign-init.c
index bf943554f18a9..50e47d3e1238b 100644
--- a/clang/test/Analysis/issue-173210-self-assign-init.c
+++ b/clang/test/Analysis/issue-173210-self-assign-init.c
@@ -1,8 +1,8 @@
 // RUN: %clang_analyze_cc1 -xc %s \
-// RUN:   -analyzer-checker=core,debug.ExprInspection \
+// RUN:   -analyzer-checker=core,debug.ExprInspection,deadcode.DeadStores \
 // RUN:   -verify
 // RUN: %clang_analyze_cc1 -xc++ %s \
-// RUN:   -analyzer-checker=core,debug.ExprInspection \
+// RUN:   -analyzer-checker=core,debug.ExprInspection,deadcode.DeadStores \
 // RUN:   -verify -w
 
 // Self assignment initialization in C code will be treated as nop.

>From 19da6560c9bd16324e08a08affbe0ffefe9f08a6 Mon Sep 17 00:00:00 2001
From: Ella Ma <[email protected]>
Date: Fri, 12 Jun 2026 13:55:15 +0200
Subject: [PATCH 5/6] address the reviews

---
 clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 23 ++++----
 .../Analysis/issue-173210-self-assign-init.c  | 53 ++++++++++++++-----
 2 files changed, 49 insertions(+), 27 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp 
b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 8cd13b3655c09..c8a78c434acfe 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -620,25 +620,20 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, 
ExplodedNode *Pred,
     return;
   }
 
-  // Bypass a nop initialization that assign to itself at variable declaration.
-  // I.e., int x = x;
-  // This is an idiom in C code, and GCC will not generate any assemblies for
-  // this self initialization, even under -O0, although Clang will.
-  // We therefore ignore all types for C code.
-  // For C++ code, Sema will not report for fundamental types and pointers.
-  // We hence also ignore them as in C, but leave the uninitialized variable
-  // report of references to the checker. For record types, as their AST
-  // structures are different in C++, they will not hit the filter here and
-  // will be checked by the checker.
-  if (const Expr *EI = VD->getInit())
+  // Self-assignment initialization in variable declaration,
+  // i.e., `int x = x;`,
+  // is a C idiom to suppress warnings of unused variables.
+  // This filter will not match variables of C++ record types, but will match
+  // C++ references. Allow references continuing here to make the undefined
+  // value checker report self-assignments of C++ references.
+  if (const Expr *EI = VD->getInit()) {
     if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(EI->IgnoreImpCasts()))
       if (VD == DR->getDecl())
-        if (getContext().getLangOpts().getCLangStd() ||
-            (getContext().getLangOpts().getCPlusPlusLangStd() &&
-             !VD->getType()->isReferenceType())) {
+        if (!VD->getType()->isReferenceType()) {
           Dst.insert(Pred);
           return;
         }
+  }
 
   // FIXME: all pre/post visits should eventually be handled by ::Visit().
   ExplodedNodeSet dstPreVisit;
diff --git a/clang/test/Analysis/issue-173210-self-assign-init.c 
b/clang/test/Analysis/issue-173210-self-assign-init.c
index 50e47d3e1238b..c53b9afdd0f30 100644
--- a/clang/test/Analysis/issue-173210-self-assign-init.c
+++ b/clang/test/Analysis/issue-173210-self-assign-init.c
@@ -6,30 +6,57 @@
 // RUN:   -verify -w
 
 // Self assignment initialization in C code will be treated as nop.
-// We will not report the VarDecl, but the following DeclRefExpr if it has not
-// yet been initialized then.
+// We will report the VarDecl only if it was left uninitialized by the time of
+// a subsequent DeclRefExpr.
+
+// NOTE: No warnings from the deadcode.DeadStores checker.
 
 void clang_analyzer_warnIfReached();
 
 struct S { int x; };
 union U { int x; };
+enum T { TT };
 
-void nowarn() {
-  int x = x; // no-warnings for C/C++
-  int *p = p; // no-warnings for C/C++
-  struct S s = s; // no-warning for C, but C++ will not report
-  union U u = u; // no-warning for C, but C++ will not report
-  // Ensure the analysis is not terminated sliently.
-  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
-}
+// No need to test VarDecl of multiple variables, as they will be split into
+// single ones when constructing the CFG.
 
-int warn() {
-  int x = x; // no-warnings for C/C++
+int warnvar() {
+  int x = x; // no-warnings for C/C++, binding is skipped via the
+             // self-assignment filter.
   return x; // expected-warning{{Undefined or garbage value returned to 
caller}}
 }
 
+int *warnptr() {
+  int *p = p; // Same as warnvar.
+  return p; // expected-warning{{Undefined or garbage value returned to 
caller}}
+}
+
+enum T warnenum() {
+  enum T t = t; // Same as warnvar.
+  return t; // expected-warning{{Undefined or garbage value returned to 
caller}}
+}
+
+int warnstruct() {
+  struct S s = s; // no-warnings for C/C++
+                  // In C, same as warnvar.
+                  // In C++, binding is handled in the ctor call and s.x is
+                  // bound to an Undefined.
+  return s.x; // expected-warning{{Undefined or garbage value returned to 
caller}}
+}
+
+#ifndef __cplusplus
+int warnunion() {
+  union U u = u; // no-warnings for C/C++
+                 // In C, same as warnvar.
+                 // In C++, binding is handled in the ctor call and u is bound
+                 // to a lazyCompoundVal, which will not trigger an undefined
+                 // usage warning.
+  return u.x; // expected-warning{{Undefined or garbage value returned to 
caller}}
+}
+#endif // not __cplusplus
+
 // NOTE: The self assignment of reference type is also tested in 
stack-addr-ps.cpp.
-// E.g., `int& i = i;` in function f5
+// I.e., `int& i = i;` in function f5
 // We only keep a simple regression confirmation here.
 #ifdef __cplusplus
 void warnref() {

>From 5b3b53e2bcb83f7fdebf7e183b7528743f6f9ad8 Mon Sep 17 00:00:00 2001
From: Ella Ma <[email protected]>
Date: Fri, 19 Jun 2026 15:33:50 +0200
Subject: [PATCH 6/6] apply suggestions 2026-06-19

---
 .../Analysis/issue-173210-self-assign-init.c  | 30 +++++++++----------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/clang/test/Analysis/issue-173210-self-assign-init.c 
b/clang/test/Analysis/issue-173210-self-assign-init.c
index c53b9afdd0f30..daf4936d56756 100644
--- a/clang/test/Analysis/issue-173210-self-assign-init.c
+++ b/clang/test/Analysis/issue-173210-self-assign-init.c
@@ -1,9 +1,9 @@
-// RUN: %clang_analyze_cc1 -xc %s \
-// RUN:   -analyzer-checker=core,debug.ExprInspection,deadcode.DeadStores \
-// RUN:   -verify
-// RUN: %clang_analyze_cc1 -xc++ %s \
-// RUN:   -analyzer-checker=core,debug.ExprInspection,deadcode.DeadStores \
-// RUN:   -verify -w
+// RUN: %clang_analyze_cc1 %s -verify -xc \
+// RUN:   -analyzer-checker=core,debug.ExprInspection,deadcode.DeadStores
+
+// Use -w to suppress the C++ -Wuninitialized warnings on struct and reference.
+// RUN: %clang_analyze_cc1 %s -verify -xc++ -w \
+// RUN:   -analyzer-checker=core,debug.ExprInspection,deadcode.DeadStores
 
 // Self assignment initialization in C code will be treated as nop.
 // We will report the VarDecl only if it was left uninitialized by the time of
@@ -37,20 +37,20 @@ enum T warnenum() {
 }
 
 int warnstruct() {
-  struct S s = s; // no-warnings for C/C++
-                  // In C, same as warnvar.
-                  // In C++, binding is handled in the ctor call and s.x is
-                  // bound to an Undefined.
+  // no-warnings for C/C++:
+  // In C, same as warnvar.
+  // In C++, binding is handled in the ctor call and 's.x' is bound to an 
Undefined.
+  struct S s = s; // no-warnings
   return s.x; // expected-warning{{Undefined or garbage value returned to 
caller}}
 }
 
 #ifndef __cplusplus
 int warnunion() {
-  union U u = u; // no-warnings for C/C++
-                 // In C, same as warnvar.
-                 // In C++, binding is handled in the ctor call and u is bound
-                 // to a lazyCompoundVal, which will not trigger an undefined
-                 // usage warning.
+  // no-warnings for C/C++:
+  // In C, same as warnvar.
+  // In C++, binding is handled in the ctor call and 'u' is bound to a
+  // lazyCompoundVal, which will not trigger an undefined usage warning.
+  union U u = u; // no-warnings
   return u.x; // expected-warning{{Undefined or garbage value returned to 
caller}}
 }
 #endif // not __cplusplus

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to