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 01/10] 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 02/10] 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 03/10] 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 04/10] 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 05/10] 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 06/10] 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 <[email protected]> Date: Mon, 22 Jun 2026 23:16:47 +0200 Subject: [PATCH 07/10] 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 <[email protected]> Date: Mon, 22 Jun 2026 23:35:20 +0200 Subject: [PATCH 08/10] 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 <[email protected]> Date: Tue, 14 Jul 2026 13:51:09 +0200 Subject: [PATCH 09/10] 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}} +} >From de4898b6e71c0737f49bfdaa0ebddf78e08d6ef5 Mon Sep 17 00:00:00 2001 From: Ella Ma <[email protected]> Date: Wed, 15 Jul 2026 09:48:29 +0200 Subject: [PATCH 10/10] reland release note --- clang/docs/ReleaseNotes.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 760c973eb6a73..e61455acc12a4 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -203,6 +203,7 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the % - New checkers and features % - Improvements % - Moved checkers +% - Diagnostic changes #### Improvements @@ -211,6 +212,10 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the #### Moved checkers +#### Diagnostic changes + +- 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)= ### Sanitizers _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
