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/2] 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/2] 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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
