[clang] [libcxx] [clang] Fix -Wuninitialized for values passed by const pointers (PR #147221)
Igor Kudrin via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 10 23:13:28 PDT 2025
https://github.com/igorkudrin updated https://github.com/llvm/llvm-project/pull/147221
>From f1e26fed6c5023ba59990112ec4a77b024247e4b Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Fri, 4 Jul 2025 23:55:41 -0700
Subject: [PATCH 1/3] [clang] Fix -Wuninitialized for values passed by const
pointers
This enables producing a "variable is uninitialized" warning when a
value is passed to a pointer-to-const argument:
```
void foo(const int *);
void test() {
int *v;
foo(v);
}
```
Fixes #37460
---
clang/lib/Analysis/UninitializedValues.cpp | 13 +++++--------
clang/test/SemaCXX/uninitialized.cpp | 8 ++++++--
2 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/clang/lib/Analysis/UninitializedValues.cpp b/clang/lib/Analysis/UninitializedValues.cpp
index b2a68b6c39a7e..540838f89f20c 100644
--- a/clang/lib/Analysis/UninitializedValues.cpp
+++ b/clang/lib/Analysis/UninitializedValues.cpp
@@ -438,13 +438,10 @@ void ClassifyRefs::VisitCallExpr(CallExpr *CE) {
return;
}
bool isTrivialBody = hasTrivialBody(CE);
- // If a value is passed by const pointer to a function,
- // we should not assume that it is initialized by the call, and we
- // conservatively do not assume that it is used.
- // If a value is passed by const reference to a function,
- // it should already be initialized.
- for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
- I != E; ++I) {
+ // A value passed by const pointer or reference to a function should already
+ // be initialized.
+ for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end(); I != E;
+ ++I) {
if ((*I)->isGLValue()) {
if ((*I)->getType().isConstQualified())
classify((*I), isTrivialBody ? Ignore : ConstRefUse);
@@ -453,7 +450,7 @@ void ClassifyRefs::VisitCallExpr(CallExpr *CE) {
const auto *UO = dyn_cast<UnaryOperator>(Ex);
if (UO && UO->getOpcode() == UO_AddrOf)
Ex = UO->getSubExpr();
- classify(Ex, Ignore);
+ classify(Ex, Use);
}
}
}
diff --git a/clang/test/SemaCXX/uninitialized.cpp b/clang/test/SemaCXX/uninitialized.cpp
index c7b987e2172e6..4a944ba830bc3 100644
--- a/clang/test/SemaCXX/uninitialized.cpp
+++ b/clang/test/SemaCXX/uninitialized.cpp
@@ -162,12 +162,16 @@ void test_const_ptr() {
int a;
int b; // expected-note {{initialize the variable 'b' to silence this warning}}
foo(&a);
- bar(&b);
- b = a + b; // expected-warning {{variable 'b' is uninitialized when used here}}
+ bar(&b); // expected-warning {{variable 'b' is uninitialized when used here}}
+ b = a + b;
int *ptr; //expected-note {{initialize the variable 'ptr' to silence this warning}}
const int *ptr2;
foo(ptr); // expected-warning {{variable 'ptr' is uninitialized when used here}}
foobar(&ptr2);
+ int *ptr3; // expected-note {{initialize the variable 'ptr3' to silence this warning}}
+ const int *ptr4; // expected-note {{initialize the variable 'ptr4' to silence this warning}}
+ bar(ptr3); // expected-warning {{variable 'ptr3' is uninitialized when used here}}
+ bar(ptr4); // expected-warning {{variable 'ptr4' is uninitialized when used here}}
}
}
>From d63b5dc783cfb9388515c3c9e7a736005e289b34 Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Sun, 6 Jul 2025 18:41:48 -0700
Subject: [PATCH 2/3] fixup! libcxx tests
---
.../ostream.inserters.arithmetic/pointer.pass.cpp | 4 ++--
.../ostream.inserters.arithmetic/pointer.volatile.pass.cpp | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/pointer.pass.cpp b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/pointer.pass.cpp
index 61fd0a804ecd3..f15f1b96b4b27 100644
--- a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/pointer.pass.cpp
+++ b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/pointer.pass.cpp
@@ -62,14 +62,14 @@ int main(int, char**)
{
testbuf<char> sb1;
std::ostream os1(&sb1);
- int n1;
+ int n1 = 0;
os1 << &n1;
assert(os1.good());
std::string s1(sb1.str());
testbuf<char> sb2;
std::ostream os2(&sb2);
- int n2;
+ int n2 = 0;
os2 << &n2;
assert(os2.good());
std::string s2(sb2.str());
diff --git a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/pointer.volatile.pass.cpp b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/pointer.volatile.pass.cpp
index 69d84f640d54e..6a1cde15a69bd 100644
--- a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/pointer.volatile.pass.cpp
+++ b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/pointer.volatile.pass.cpp
@@ -61,7 +61,7 @@ class testbuf : public std::basic_streambuf<CharT> {
int main(int, char**) {
testbuf<char> sb1;
std::ostream os1(&sb1);
- int n1;
+ int n1 = 0;
os1 << &n1;
assert(os1.good());
std::string s1 = sb1.str();
@@ -74,7 +74,7 @@ int main(int, char**) {
testbuf<char> sb3;
std::ostream os3(&sb3);
- volatile int n3;
+ volatile int n3 = 0;
os3 << &n3;
assert(os3.good());
std::string s3 = sb3.str();
>From 4ff02a7bdb6b92bcb5362436df3eb4e1341686a1 Mon Sep 17 00:00:00 2001
From: Igor Kudrin <ikudrin at accesssoftek.com>
Date: Mon, 7 Jul 2025 20:59:38 -0700
Subject: [PATCH 3/3] fixup! Do not detect passing a value by a constant
pointer Co-authored-by: Richard Smith <richard at metafoo.co.uk>
---
clang/lib/Analysis/UninitializedValues.cpp | 14 ++++++++------
clang/test/SemaCXX/uninitialized.cpp | 4 ++--
.../ostream.inserters.arithmetic/pointer.pass.cpp | 4 ++--
.../pointer.volatile.pass.cpp | 4 ++--
4 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/clang/lib/Analysis/UninitializedValues.cpp b/clang/lib/Analysis/UninitializedValues.cpp
index 540838f89f20c..bda0856a0b8c8 100644
--- a/clang/lib/Analysis/UninitializedValues.cpp
+++ b/clang/lib/Analysis/UninitializedValues.cpp
@@ -438,10 +438,13 @@ void ClassifyRefs::VisitCallExpr(CallExpr *CE) {
return;
}
bool isTrivialBody = hasTrivialBody(CE);
- // A value passed by const pointer or reference to a function should already
- // be initialized.
- for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end(); I != E;
- ++I) {
+ // If a value is passed by const pointer to a function,
+ // we should not assume that it is initialized by the call, and we
+ // conservatively do not assume that it is used.
+ // If a value is passed by const reference to a function,
+ // it should already be initialized.
+ for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
+ I != E; ++I) {
if ((*I)->isGLValue()) {
if ((*I)->getType().isConstQualified())
classify((*I), isTrivialBody ? Ignore : ConstRefUse);
@@ -449,8 +452,7 @@ void ClassifyRefs::VisitCallExpr(CallExpr *CE) {
const Expr *Ex = stripCasts(DC->getParentASTContext(), *I);
const auto *UO = dyn_cast<UnaryOperator>(Ex);
if (UO && UO->getOpcode() == UO_AddrOf)
- Ex = UO->getSubExpr();
- classify(Ex, Use);
+ classify(UO->getSubExpr(), Ignore);
}
}
}
diff --git a/clang/test/SemaCXX/uninitialized.cpp b/clang/test/SemaCXX/uninitialized.cpp
index 4a944ba830bc3..3ae24f1faa4ec 100644
--- a/clang/test/SemaCXX/uninitialized.cpp
+++ b/clang/test/SemaCXX/uninitialized.cpp
@@ -162,8 +162,8 @@ void test_const_ptr() {
int a;
int b; // expected-note {{initialize the variable 'b' to silence this warning}}
foo(&a);
- bar(&b); // expected-warning {{variable 'b' is uninitialized when used here}}
- b = a + b;
+ bar(&b);
+ b = a + b; // expected-warning {{variable 'b' is uninitialized when used here}}
int *ptr; //expected-note {{initialize the variable 'ptr' to silence this warning}}
const int *ptr2;
foo(ptr); // expected-warning {{variable 'ptr' is uninitialized when used here}}
diff --git a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/pointer.pass.cpp b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/pointer.pass.cpp
index f15f1b96b4b27..61fd0a804ecd3 100644
--- a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/pointer.pass.cpp
+++ b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/pointer.pass.cpp
@@ -62,14 +62,14 @@ int main(int, char**)
{
testbuf<char> sb1;
std::ostream os1(&sb1);
- int n1 = 0;
+ int n1;
os1 << &n1;
assert(os1.good());
std::string s1(sb1.str());
testbuf<char> sb2;
std::ostream os2(&sb2);
- int n2 = 0;
+ int n2;
os2 << &n2;
assert(os2.good());
std::string s2(sb2.str());
diff --git a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/pointer.volatile.pass.cpp b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/pointer.volatile.pass.cpp
index 6a1cde15a69bd..69d84f640d54e 100644
--- a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/pointer.volatile.pass.cpp
+++ b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/pointer.volatile.pass.cpp
@@ -61,7 +61,7 @@ class testbuf : public std::basic_streambuf<CharT> {
int main(int, char**) {
testbuf<char> sb1;
std::ostream os1(&sb1);
- int n1 = 0;
+ int n1;
os1 << &n1;
assert(os1.good());
std::string s1 = sb1.str();
@@ -74,7 +74,7 @@ int main(int, char**) {
testbuf<char> sb3;
std::ostream os3(&sb3);
- volatile int n3 = 0;
+ volatile int n3;
os3 << &n3;
assert(os3.good());
std::string s3 = sb3.str();
More information about the cfe-commits
mailing list