[clang] [analyzer] Ignoring `T v=v; ` idiom for uninitialized variable checker and dead store checker (PR #187530)
Ella Ma via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 14 05:24:42 PDT 2026
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 <alansnape3058 at gmail.com>
Date: Thu, 19 Mar 2026 14:15:11 +0100
Subject: [PATCH 1/9] 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 <alansnape3058 at gmail.com>
Date: Fri, 15 May 2026 14:40:46 +0200
Subject: [PATCH 2/9] 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 <alansnape3058 at gmail.com>
Date: Fri, 15 May 2026 15:41:52 +0200
Subject: [PATCH 3/9] 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 <alansnape3058 at gmail.com>
Date: Wed, 27 May 2026 19:30:20 +0200
Subject: [PATCH 4/9] 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 <alansnape3058 at gmail.com>
Date: Fri, 12 Jun 2026 13:55:15 +0200
Subject: [PATCH 5/9] 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 <alansnape3058 at gmail.com>
Date: Fri, 19 Jun 2026 15:33:50 +0200
Subject: [PATCH 6/9] 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
>From 6d39ce0468c9988e2b599b7524999cc8cb1cbf4a Mon Sep 17 00:00:00 2001
From: Ella Ma <alansnape3058 at gmail.com>
Date: Mon, 22 Jun 2026 23:16:47 +0200
Subject: [PATCH 7/9] update C++ test case execution config for the
-Wuninitialized warnings
---
clang/test/Analysis/issue-173210-self-assign-init.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/Analysis/issue-173210-self-assign-init.c b/clang/test/Analysis/issue-173210-self-assign-init.c
index daf4936d56756..60e3d7a082dd0 100644
--- a/clang/test/Analysis/issue-173210-self-assign-init.c
+++ b/clang/test/Analysis/issue-173210-self-assign-init.c
@@ -2,7 +2,7 @@
// 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: %clang_analyze_cc1 %s -verify -xc++ -Wno-uninitialized \
// RUN: -analyzer-checker=core,debug.ExprInspection,deadcode.DeadStores
// Self assignment initialization in C code will be treated as nop.
>From a18513fb62ddbcbd7893cf475da8a0c2b922d0a6 Mon Sep 17 00:00:00 2001
From: Ella Ma <alansnape3058 at gmail.com>
Date: Mon, 22 Jun 2026 23:35:20 +0200
Subject: [PATCH 8/9] fix comments
---
clang/test/Analysis/issue-173210-self-assign-init.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/Analysis/issue-173210-self-assign-init.c b/clang/test/Analysis/issue-173210-self-assign-init.c
index 60e3d7a082dd0..44e43a998022f 100644
--- a/clang/test/Analysis/issue-173210-self-assign-init.c
+++ b/clang/test/Analysis/issue-173210-self-assign-init.c
@@ -1,7 +1,7 @@
// 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.
+// Suppress the C++ -Wuninitialized warnings on struct and reference.
// RUN: %clang_analyze_cc1 %s -verify -xc++ -Wno-uninitialized \
// RUN: -analyzer-checker=core,debug.ExprInspection,deadcode.DeadStores
>From d6a182036afc53256056e29676a0626874bf80c3 Mon Sep 17 00:00:00 2001
From: Ella Ma <alansnape3058 at gmail.com>
Date: Tue, 14 Jul 2026 13:51:09 +0200
Subject: [PATCH 9/9] wip-2026-07-14_13:51:04
---
clang/docs/ReleaseNotes.md | 1 +
clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 18 ++++--
.../Analysis/issue-173210-self-assign-init.c | 60 ++++++++++++++++---
3 files changed, 66 insertions(+), 13 deletions(-)
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 9063e54b3e692..c5fd872bb75ce 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -1269,6 +1269,7 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
- Cross Translation Unit (CTU) import failures are now reported at the location where the imported symbol would be used, making it easier to understand why a cross-TU bug was missed. (#GH188795)
- Uninitialized-value diagnostics no longer emit a misleading "initialized here" note for a variable that was declared without an initializer; the note now reads "declared without an initial value". (#GH198345)
+- For self-assignments during initialization (`T v = v;`), `core.uninitialized.Assign` will not report them as uninitialized accesses (except C++ reference types), and the checks will be delayed until the first accesses of these variables; `deadcode.DeadStores` will not report them as dead stores. (#GH187530)
(release-notes-sanitizers)=
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 327a3f5df5981..8eb1b42600a81 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -597,12 +597,18 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
// 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 (!VD->getType()->isReferenceType()) {
- Dst.insert(Pred);
- return;
- }
+ // Ignore InitListExpr if exists.
+ if (const auto *IL = dyn_cast<InitListExpr>(EI);
+ IL && IL->getNumInits() == 1)
+ EI = IL->getInit(0);
+
+ // Ignore parentheses and implict casts.
+ if (const auto *DR = dyn_cast<DeclRefExpr>(EI->IgnoreParenImpCasts())) {
+ if (VD == DR->getDecl() && !VD->getType()->isReferenceType()) {
+ Dst.insert(Pred);
+ return;
+ }
+ }
}
// FIXME: all pre/post visits should eventually be handled by ::Visit().
diff --git a/clang/test/Analysis/issue-173210-self-assign-init.c b/clang/test/Analysis/issue-173210-self-assign-init.c
index 44e43a998022f..57f5c42bf69ab 100644
--- a/clang/test/Analysis/issue-173210-self-assign-init.c
+++ b/clang/test/Analysis/issue-173210-self-assign-init.c
@@ -20,23 +20,23 @@ enum T { TT };
// No need to test VarDecl of multiple variables, as they will be split into
// single ones when constructing the CFG.
-int warnvar() {
+int check_var() {
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 *check_ptr() {
int *p = p; // Same as warnvar.
return p; // expected-warning{{Undefined or garbage value returned to caller}}
}
-enum T warnenum() {
+enum T check_enum() {
enum T t = t; // Same as warnvar.
return t; // expected-warning{{Undefined or garbage value returned to caller}}
}
-int warnstruct() {
+int check_struct() {
// 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.
@@ -45,7 +45,7 @@ int warnstruct() {
}
#ifndef __cplusplus
-int warnunion() {
+int check_union() {
// 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
@@ -55,11 +55,57 @@ int warnunion() {
}
#endif // not __cplusplus
+#ifdef __cplusplus
+
// NOTE: The self assignment of reference type is also tested in stack-addr-ps.cpp.
// I.e., `int& i = i;` in function f5
// We only keep a simple regression confirmation here.
-#ifdef __cplusplus
-void warnref() {
+void check_ref() {
int &x = x; // expected-warning{{Assigned value is uninitialized}}
}
+
+// Confirmation for default member initializer.
+struct struct_self_assign {
+ int x = x; // no-warnings
+};
+int check_struct_self_assign() {
+ struct_self_assign s; // no-warnings
+ return s.x; // FIXME: there should be a warning.
+}
+
+// Confirmation for constructor initialization list.
+struct struct_init_list {
+ int x;
+ struct_init_list()
+ : x(x) // expected-warning{{Assigned value is uninitialized}}
+ {}
+};
+void check_struct_init_list() {
+ // Trigger the ctor call.
+ struct_init_list s;
+}
+
+// The below two have the same AST structure.
+int check_copy_list_initialization() {
+ int x = {x}; // no-warnings
+ return x; // expected-warning{{Undefined or garbage value returned to caller}}
+};
+int check_direct_list_initialization() {
+ int x {x}; // no-warnings
+ return x; // expected-warning{{Undefined or garbage value returned to caller}}
+};
+
+// Having the same AST structure as `int x = x;`, rather than `int x = (x);`.
+int check_direct_initialization() {
+ int x (x); // no-warnings
+ return x; // expected-warning{{Undefined or garbage value returned to caller}}
+}
+
#endif // __cplusplus
+
+// Ignore parentheses for the initialization-with-a-macro cases, such as
+// #define VAR_INIT(x) (x) and int x = VAR_INIT(x);
+int check_paren_init() {
+ int x = (x); // no-warnings
+ return x; // expected-warning{{Undefined or garbage value returned to caller}}
+}
More information about the cfe-commits
mailing list