[clang] [clang][analyzer] Improved message in uninitialized.Assign at default assignment (PR #208173)
Balázs Kéri via cfe-commits
cfe-commits at lists.llvm.org
Mon Jul 13 03:37:07 PDT 2026
https://github.com/balazske updated https://github.com/llvm/llvm-project/pull/208173
>From 2891ff62aa1dae5b4371e273be2c63e2f2eae073 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= <balazs.keri at ericsson.com>
Date: Wed, 8 Jul 2026 09:26:19 +0200
Subject: [PATCH 1/2] [clang][analyzer] Improved message in
uninitialized.Assign at default assignment
---
.../Checkers/UndefinedAssignmentChecker.cpp | 14 +++++++++++++
clang/test/Analysis/operator-calls.cpp | 20 +++++++++++++++----
2 files changed, 30 insertions(+), 4 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
index 7f8923c7c09fc..f97dd8ee67d57 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
@@ -73,6 +73,20 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
}
}
+ if (const auto *MD =
+ dyn_cast<CXXMethodDecl>(C.getStackFrame()->getDecl())) {
+ if ((MD->isCopyAssignmentOperator() ||
+ MD->isMoveAssignmentOperator()) &&
+ MD->isDefaulted() && B->isAssignmentOp()) {
+ OS << "Value assigned to field '"
+ << cast<MemberExpr>(B->getRHS()->IgnoreImpCasts())
+ ->getMemberDecl()
+ ->getName()
+ << "' in " << (!MD->isImplicit() ? "default" : "implicit")
+ << " assignment operator is uninitialized";
+ break;
+ }
+ }
ex = B->getRHS();
break;
}
diff --git a/clang/test/Analysis/operator-calls.cpp b/clang/test/Analysis/operator-calls.cpp
index a89624d44ac42..5af0d72b60bc0 100644
--- a/clang/test/Analysis/operator-calls.cpp
+++ b/clang/test/Analysis/operator-calls.cpp
@@ -111,6 +111,11 @@ namespace SynthesizedAssignment {
B& operator=(B&&) = default;
};
+ struct C {
+ int x;
+ A a[3];
+ };
+
// This used to produce a warning about the iteration variable in the
// synthesized assignment operator being undefined.
//
@@ -121,16 +126,16 @@ namespace SynthesizedAssignment {
void testNoWarning() {
B v, u;
- u = v; // expected-warning at 110{{Assigned value is uninitialized}}
+ u = v; // expected-warning at 110{{Value assigned to field 'x' in default assignment operator is uninitialized}}
// expected-note at -1{{Calling defaulted copy assignment operator for 'B'}}
- // expected-note at 110{{Assigned value is uninitialized}}
+ // expected-note at 110{{Value assigned to field 'x' in default assignment operator is uninitialized}}
}
void testNoWarningMove() {
B v, u;
- u = static_cast<B &&>(v); // expected-warning at 111{{Assigned value is uninitialized}}
+ u = static_cast<B &&>(v); // expected-warning at 111{{Value assigned to field 'x' in default assignment operator is uninitialized}}
// expected-note at -1{{Calling defaulted move assignment operator for 'B'}}
- // expected-note at 111{{Assigned value is uninitialized}}
+ // expected-note at 111{{Value assigned to field 'x' in default assignment operator is uninitialized}}
}
void testConsistency() {
@@ -162,4 +167,11 @@ namespace SynthesizedAssignment {
clang_analyzer_eval(u.a[2].a == 43); // expected-warning{{TRUE}}
// expected-note at -1{{TRUE}}
}
+
+ void testImplicitAssign() {
+ C c1, c2;
+ c1 = c2; // expected-warning at 114{{Value assigned to field 'x' in implicit assignment operator is uninitialized}}
+ // expected-note at -1{{Calling implicit copy assignment operator for 'C'}}
+ // expected-note at 114{{Value assigned to field 'x' in implicit assignment operator is uninitialized}}
+ }
}
>From 0c3ef2a8006a564d55dceb1f89ed09778b370426 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= <balazs.keri at ericsson.com>
Date: Mon, 13 Jul 2026 12:36:33 +0200
Subject: [PATCH 2/2] safer MemberExpr check, using label in test
---
.../Checkers/UndefinedAssignmentChecker.cpp | 5 +++--
clang/test/Analysis/operator-calls.cpp | 18 +++++++++---------
2 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
index f97dd8ee67d57..331df5d8c750d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
@@ -77,9 +77,10 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
dyn_cast<CXXMethodDecl>(C.getStackFrame()->getDecl())) {
if ((MD->isCopyAssignmentOperator() ||
MD->isMoveAssignmentOperator()) &&
- MD->isDefaulted() && B->isAssignmentOp()) {
+ MD->isDefaulted() && B->isAssignmentOp() &&
+ isa<MemberExpr>(B->getLHS()->IgnoreImpCasts())) {
OS << "Value assigned to field '"
- << cast<MemberExpr>(B->getRHS()->IgnoreImpCasts())
+ << cast<MemberExpr>(B->getLHS()->IgnoreImpCasts())
->getMemberDecl()
->getName()
<< "' in " << (!MD->isImplicit() ? "default" : "implicit")
diff --git a/clang/test/Analysis/operator-calls.cpp b/clang/test/Analysis/operator-calls.cpp
index 5af0d72b60bc0..57da7cdc16923 100644
--- a/clang/test/Analysis/operator-calls.cpp
+++ b/clang/test/Analysis/operator-calls.cpp
@@ -107,11 +107,11 @@ namespace SynthesizedAssignment {
struct B {
int x;
A a[3];
- B& operator=(B&) = default;
- B& operator=(B&&) = default;
+ B& operator=(B&) = default; // #b_copy_assign
+ B& operator=(B&&) = default; // #b_move_assign
};
- struct C {
+ struct C { // #c_definition
int x;
A a[3];
};
@@ -126,16 +126,16 @@ namespace SynthesizedAssignment {
void testNoWarning() {
B v, u;
- u = v; // expected-warning at 110{{Value assigned to field 'x' in default assignment operator is uninitialized}}
+ u = v; // expected-warning@#b_copy_assign{{Value assigned to field 'x' in default assignment operator is uninitialized}}
// expected-note at -1{{Calling defaulted copy assignment operator for 'B'}}
- // expected-note at 110{{Value assigned to field 'x' in default assignment operator is uninitialized}}
+ // expected-note@#b_copy_assign{{Value assigned to field 'x' in default assignment operator is uninitialized}}
}
void testNoWarningMove() {
B v, u;
- u = static_cast<B &&>(v); // expected-warning at 111{{Value assigned to field 'x' in default assignment operator is uninitialized}}
+ u = static_cast<B &&>(v); // expected-warning@#b_move_assign{{Value assigned to field 'x' in default assignment operator is uninitialized}}
// expected-note at -1{{Calling defaulted move assignment operator for 'B'}}
- // expected-note at 111{{Value assigned to field 'x' in default assignment operator is uninitialized}}
+ // expected-note@#b_move_assign{{Value assigned to field 'x' in default assignment operator is uninitialized}}
}
void testConsistency() {
@@ -170,8 +170,8 @@ namespace SynthesizedAssignment {
void testImplicitAssign() {
C c1, c2;
- c1 = c2; // expected-warning at 114{{Value assigned to field 'x' in implicit assignment operator is uninitialized}}
+ c1 = c2; // expected-warning@#c_definition{{Value assigned to field 'x' in implicit assignment operator is uninitialized}}
// expected-note at -1{{Calling implicit copy assignment operator for 'C'}}
- // expected-note at 114{{Value assigned to field 'x' in implicit assignment operator is uninitialized}}
+ // expected-note@#c_definition{{Value assigned to field 'x' in implicit assignment operator is uninitialized}}
}
}
More information about the cfe-commits
mailing list