Skip to content

[clang] Add -Wuninitialized-const-pointer #148337

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 14, 2025

Conversation

igorkudrin
Copy link
Collaborator

@igorkudrin igorkudrin commented Jul 12, 2025

This option is similar to -Wuninitialized-const-reference, but diagnoses the passing of an uninitialized value via a const pointer, like in the following code:

void foo(const int *);
void test() {
  int v;
  foo(&v);
}

This is an extract from #147221 as suggested in this comment.

This option is similar to -Wuninitialized-const-reference, but diagnoses
the passing of an uninitialized value via a const pointer, like in the
following code:
```
void foo(const int *);
void test() {
  int v;
  foo(&v);
}
```
@igorkudrin igorkudrin requested a review from a team as a code owner July 12, 2025 06:23
@igorkudrin igorkudrin added clang Clang issues not falling into any other category clang:analysis labels Jul 12, 2025
@llvmbot llvmbot added libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Jul 12, 2025
@llvmbot
Copy link
Member

llvmbot commented Jul 12, 2025

@llvm/pr-subscribers-libcxx

@llvm/pr-subscribers-clang-analysis

Author: Igor Kudrin (igorkudrin)

Changes

This option is similar to -Wuninitialized-const-reference, but diagnoses the passing of an uninitialized value via a const pointer, like in the following code:

void foo(const int *);
void test() {
  int v;
  foo(&v);
}

Full diff: https://github.com/llvm/llvm-project/pull/148337.diff

9 Files Affected:

  • (modified) clang/include/clang/Analysis/Analyses/UninitializedValues.h (+6)
  • (modified) clang/include/clang/Basic/DiagnosticGroups.td (+3-1)
  • (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+4)
  • (modified) clang/lib/Analysis/UninitializedValues.cpp (+17-2)
  • (modified) clang/lib/Sema/AnalysisBasedWarnings.cpp (+17-4)
  • (modified) clang/test/Misc/warning-wall.c (+1)
  • (added) clang/test/SemaCXX/warn-uninitialized-const-pointer.cpp (+35)
  • (modified) libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/pointer.pass.cpp (+2-2)
  • (modified) libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/pointer.volatile.pass.cpp (+2-2)
diff --git a/clang/include/clang/Analysis/Analyses/UninitializedValues.h b/clang/include/clang/Analysis/Analyses/UninitializedValues.h
index b151bc3f58321..a9b9caf38e518 100644
--- a/clang/include/clang/Analysis/Analyses/UninitializedValues.h
+++ b/clang/include/clang/Analysis/Analyses/UninitializedValues.h
@@ -50,6 +50,9 @@ class UninitUse {
   /// Is this use a const reference to this variable?
   bool ConstRefUse = false;
 
+  /// Is this use a const pointer to this variable?
+  bool ConstPtrUse = false;
+
   /// This use is always uninitialized if it occurs after any of these branches
   /// is taken.
   SmallVector<Branch, 2> UninitBranches;
@@ -65,11 +68,14 @@ class UninitUse {
   void setUninitAfterCall() { UninitAfterCall = true; }
   void setUninitAfterDecl() { UninitAfterDecl = true; }
   void setConstRefUse() { ConstRefUse = true; }
+  void setConstPtrUse() { ConstPtrUse = true; }
 
   /// Get the expression containing the uninitialized use.
   const Expr *getUser() const { return User; }
 
   bool isConstRefUse() const { return ConstRefUse; }
+  bool isConstPtrUse() const { return ConstPtrUse; }
+  bool isConstRefOrPtrUse() const { return ConstRefUse || ConstPtrUse; }
 
   /// The kind of uninitialized use.
   enum Kind {
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 9a7a308600763..c28a919e35d08 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -952,9 +952,11 @@ def UninitializedMaybe : DiagGroup<"conditional-uninitialized">;
 def UninitializedSometimes : DiagGroup<"sometimes-uninitialized">;
 def UninitializedStaticSelfInit : DiagGroup<"static-self-init">;
 def UninitializedConstReference : DiagGroup<"uninitialized-const-reference">;
+def UninitializedConstPointer : DiagGroup<"uninitialized-const-pointer">;
 def Uninitialized  : DiagGroup<"uninitialized", [UninitializedSometimes,
                                                  UninitializedStaticSelfInit,
-                                                 UninitializedConstReference]>;
+                                                 UninitializedConstReference,
+                                                 UninitializedConstPointer]>;
 def IgnoredPragmaIntrinsic : DiagGroup<"ignored-pragma-intrinsic">;
 // #pragma optimize is often used to avoid to work around MSVC codegen bugs or
 // to disable inlining. It's not completely clear what alternative to suggest
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f1290738d46b2..42e351c3fd697 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2548,6 +2548,10 @@ def warn_uninit_const_reference : Warning<
   "variable %0 is uninitialized when passed as a const reference argument "
   "here">, InGroup<UninitializedConstReference>, DefaultIgnore;
 
+def warn_uninit_const_pointer : Warning<
+  "variable %0 is uninitialized when passed as a const pointer argument here">,
+  InGroup<UninitializedConstPointer>, DefaultIgnore;
+
 def warn_unsequenced_mod_mod : Warning<
   "multiple unsequenced modifications to %0">, InGroup<Unsequenced>;
 def warn_unsequenced_mod_use : Warning<
diff --git a/clang/lib/Analysis/UninitializedValues.cpp b/clang/lib/Analysis/UninitializedValues.cpp
index 8c9cf8dac79ed..9f031c402eddb 100644
--- a/clang/lib/Analysis/UninitializedValues.cpp
+++ b/clang/lib/Analysis/UninitializedValues.cpp
@@ -281,6 +281,7 @@ class ClassifyRefs : public StmtVisitor<ClassifyRefs> {
     Use,
     SelfInit,
     ConstRefUse,
+    ConstPtrUse,
     Ignore
   };
 
@@ -451,8 +452,9 @@ 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, Ignore);
+        classify(UO->getSubExpr(), isTrivialBody ? Ignore : ConstPtrUse);
+      else
+        classify(Ex, Ignore);
     }
   }
 }
@@ -496,6 +498,7 @@ class TransferFunctions : public StmtVisitor<TransferFunctions> {
 
   void reportUse(const Expr *ex, const VarDecl *vd);
   void reportConstRefUse(const Expr *ex, const VarDecl *vd);
+  void reportConstPtrUse(const Expr *ex, const VarDecl *vd);
 
   void VisitBinaryOperator(BinaryOperator *bo);
   void VisitBlockExpr(BlockExpr *be);
@@ -682,6 +685,15 @@ void TransferFunctions::reportConstRefUse(const Expr *ex, const VarDecl *vd) {
   }
 }
 
+void TransferFunctions::reportConstPtrUse(const Expr *ex, const VarDecl *vd) {
+  Value v = vals[vd];
+  if (isAlwaysUninit(v)) {
+    auto use = getUninitUse(ex, vd, v);
+    use.setConstPtrUse();
+    handler.handleUseOfUninitVariable(vd, use);
+  }
+}
+
 void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS) {
   // This represents an initialization of the 'element' value.
   if (const auto *DS = dyn_cast<DeclStmt>(FS->getElement())) {
@@ -754,6 +766,9 @@ void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
   case ClassifyRefs::ConstRefUse:
     reportConstRefUse(dr, cast<VarDecl>(dr->getDecl()));
     break;
+  case ClassifyRefs::ConstPtrUse:
+    reportConstPtrUse(dr, cast<VarDecl>(dr->getDecl()));
+    break;
   }
 }
 
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index ec8acbdff3b49..11e3a3cbd7909 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -993,6 +993,13 @@ static void DiagnoseUninitializedConstRefUse(Sema &S, const VarDecl *VD,
       << VD->getDeclName() << Use.getUser()->getSourceRange();
 }
 
+/// Diagnose uninitialized const pointer usages.
+static void DiagnoseUninitializedConstPtrUse(Sema &S, const VarDecl *VD,
+                                             const UninitUse &Use) {
+  S.Diag(Use.getUser()->getBeginLoc(), diag::warn_uninit_const_pointer)
+      << VD->getDeclName() << Use.getUser()->getSourceRange();
+}
+
 /// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an
 /// uninitialized variable. This manages the different forms of diagnostic
 /// emitted for particular types of uses. Returns true if the use was diagnosed
@@ -1572,9 +1579,9 @@ class UninitValsDiagReporter : public UninitVariablesHandler {
         // guaranteed to produce them in line/column order, this will provide
         // a stable ordering.
         llvm::sort(*vec, [](const UninitUse &a, const UninitUse &b) {
-          // Move ConstRef uses to the back.
-          if (a.isConstRefUse() != b.isConstRefUse())
-            return b.isConstRefUse();
+          // Move ConstRef and ConstPtr uses to the back.
+          if (a.isConstRefOrPtrUse() != b.isConstRefOrPtrUse())
+            return b.isConstRefOrPtrUse();
           // Prefer a more confident report over a less confident one.
           if (a.getKind() != b.getKind())
             return a.getKind() > b.getKind();
@@ -1587,6 +1594,11 @@ class UninitValsDiagReporter : public UninitVariablesHandler {
             break;
           }
 
+          if (U.isConstPtrUse()) {
+            DiagnoseUninitializedConstPtrUse(S, vd, U);
+            break;
+          }
+
           // If we have self-init, downgrade all uses to 'may be uninitialized'.
           UninitUse Use = hasSelfInit ? UninitUse(U.getUser(), false) : U;
 
@@ -2820,7 +2832,8 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
   if (!Diags.isIgnored(diag::warn_uninit_var, D->getBeginLoc()) ||
       !Diags.isIgnored(diag::warn_sometimes_uninit_var, D->getBeginLoc()) ||
       !Diags.isIgnored(diag::warn_maybe_uninit_var, D->getBeginLoc()) ||
-      !Diags.isIgnored(diag::warn_uninit_const_reference, D->getBeginLoc())) {
+      !Diags.isIgnored(diag::warn_uninit_const_reference, D->getBeginLoc()) ||
+      !Diags.isIgnored(diag::warn_uninit_const_pointer, D->getBeginLoc())) {
     if (CFG *cfg = AC.getCFG()) {
       UninitValsDiagReporter reporter(S);
       UninitVariablesAnalysisStats stats;
diff --git a/clang/test/Misc/warning-wall.c b/clang/test/Misc/warning-wall.c
index 91de843f88c91..689868c62f6a7 100644
--- a/clang/test/Misc/warning-wall.c
+++ b/clang/test/Misc/warning-wall.c
@@ -66,6 +66,7 @@ CHECK-NEXT:    -Wuninitialized
 CHECK-NEXT:      -Wsometimes-uninitialized
 CHECK-NEXT:      -Wstatic-self-init
 CHECK-NEXT:      -Wuninitialized-const-reference
+CHECK-NEXT:      -Wuninitialized-const-pointer
 CHECK-NEXT:    -Wunknown-pragmas
 CHECK-NEXT:    -Wunused
 CHECK-NEXT:      -Wunused-argument
diff --git a/clang/test/SemaCXX/warn-uninitialized-const-pointer.cpp b/clang/test/SemaCXX/warn-uninitialized-const-pointer.cpp
new file mode 100644
index 0000000000000..62802ba7375cc
--- /dev/null
+++ b/clang/test/SemaCXX/warn-uninitialized-const-pointer.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -Wuninitialized-const-pointer -verify %s
+
+template <class T>
+void ignore_template(const T *) {}
+void ignore(const int *) {}
+void dont_ignore_non_empty(const int *) { ; } 
+void dont_ignore_block(const int *) { {} }
+void dont_ignore_try_block(const int *) try {
+} catch (...) {
+}
+int const_ptr_use(const int *);
+
+void f(int a) {
+  int i;
+  const_ptr_use(&i);             // expected-warning {{variable 'i' is uninitialized when passed as a const pointer argument here}}
+  int j = j + const_ptr_use(&j); // expected-warning {{variable 'j' is uninitialized when used within its own initialization}}
+  int k = k;                     // expected-warning {{variable 'k' is uninitialized when used within its own initialization}}
+  const_ptr_use(&k);
+
+  // Only report if a variable is always uninitialized at the point of use
+  int l;
+  if (a < 42)
+    l = 1;
+  const_ptr_use(&l);
+
+  // Don't report if the called function is known to be empty.
+  int m;
+  ignore_template(&m);
+  ignore(&m);
+  dont_ignore_non_empty(&m); // expected-warning {{variable 'm' is uninitialized when passed as a const pointer argument here}}
+  int n;
+  dont_ignore_block(&n); // expected-warning {{variable 'n' is uninitialized when passed as a const pointer argument here}}
+  int o;
+  dont_ignore_try_block(&o); // expected-warning {{variable 'o' is uninitialized when passed as a const pointer argument 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 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();

@llvmbot
Copy link
Member

llvmbot commented Jul 12, 2025

@llvm/pr-subscribers-clang

Author: Igor Kudrin (igorkudrin)

Changes

This option is similar to -Wuninitialized-const-reference, but diagnoses the passing of an uninitialized value via a const pointer, like in the following code:

void foo(const int *);
void test() {
  int v;
  foo(&amp;v);
}

Full diff: https://github.com/llvm/llvm-project/pull/148337.diff

9 Files Affected:

  • (modified) clang/include/clang/Analysis/Analyses/UninitializedValues.h (+6)
  • (modified) clang/include/clang/Basic/DiagnosticGroups.td (+3-1)
  • (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+4)
  • (modified) clang/lib/Analysis/UninitializedValues.cpp (+17-2)
  • (modified) clang/lib/Sema/AnalysisBasedWarnings.cpp (+17-4)
  • (modified) clang/test/Misc/warning-wall.c (+1)
  • (added) clang/test/SemaCXX/warn-uninitialized-const-pointer.cpp (+35)
  • (modified) libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/pointer.pass.cpp (+2-2)
  • (modified) libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/pointer.volatile.pass.cpp (+2-2)
diff --git a/clang/include/clang/Analysis/Analyses/UninitializedValues.h b/clang/include/clang/Analysis/Analyses/UninitializedValues.h
index b151bc3f58321..a9b9caf38e518 100644
--- a/clang/include/clang/Analysis/Analyses/UninitializedValues.h
+++ b/clang/include/clang/Analysis/Analyses/UninitializedValues.h
@@ -50,6 +50,9 @@ class UninitUse {
   /// Is this use a const reference to this variable?
   bool ConstRefUse = false;
 
+  /// Is this use a const pointer to this variable?
+  bool ConstPtrUse = false;
+
   /// This use is always uninitialized if it occurs after any of these branches
   /// is taken.
   SmallVector<Branch, 2> UninitBranches;
@@ -65,11 +68,14 @@ class UninitUse {
   void setUninitAfterCall() { UninitAfterCall = true; }
   void setUninitAfterDecl() { UninitAfterDecl = true; }
   void setConstRefUse() { ConstRefUse = true; }
+  void setConstPtrUse() { ConstPtrUse = true; }
 
   /// Get the expression containing the uninitialized use.
   const Expr *getUser() const { return User; }
 
   bool isConstRefUse() const { return ConstRefUse; }
+  bool isConstPtrUse() const { return ConstPtrUse; }
+  bool isConstRefOrPtrUse() const { return ConstRefUse || ConstPtrUse; }
 
   /// The kind of uninitialized use.
   enum Kind {
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 9a7a308600763..c28a919e35d08 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -952,9 +952,11 @@ def UninitializedMaybe : DiagGroup<"conditional-uninitialized">;
 def UninitializedSometimes : DiagGroup<"sometimes-uninitialized">;
 def UninitializedStaticSelfInit : DiagGroup<"static-self-init">;
 def UninitializedConstReference : DiagGroup<"uninitialized-const-reference">;
+def UninitializedConstPointer : DiagGroup<"uninitialized-const-pointer">;
 def Uninitialized  : DiagGroup<"uninitialized", [UninitializedSometimes,
                                                  UninitializedStaticSelfInit,
-                                                 UninitializedConstReference]>;
+                                                 UninitializedConstReference,
+                                                 UninitializedConstPointer]>;
 def IgnoredPragmaIntrinsic : DiagGroup<"ignored-pragma-intrinsic">;
 // #pragma optimize is often used to avoid to work around MSVC codegen bugs or
 // to disable inlining. It's not completely clear what alternative to suggest
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f1290738d46b2..42e351c3fd697 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2548,6 +2548,10 @@ def warn_uninit_const_reference : Warning<
   "variable %0 is uninitialized when passed as a const reference argument "
   "here">, InGroup<UninitializedConstReference>, DefaultIgnore;
 
+def warn_uninit_const_pointer : Warning<
+  "variable %0 is uninitialized when passed as a const pointer argument here">,
+  InGroup<UninitializedConstPointer>, DefaultIgnore;
+
 def warn_unsequenced_mod_mod : Warning<
   "multiple unsequenced modifications to %0">, InGroup<Unsequenced>;
 def warn_unsequenced_mod_use : Warning<
diff --git a/clang/lib/Analysis/UninitializedValues.cpp b/clang/lib/Analysis/UninitializedValues.cpp
index 8c9cf8dac79ed..9f031c402eddb 100644
--- a/clang/lib/Analysis/UninitializedValues.cpp
+++ b/clang/lib/Analysis/UninitializedValues.cpp
@@ -281,6 +281,7 @@ class ClassifyRefs : public StmtVisitor<ClassifyRefs> {
     Use,
     SelfInit,
     ConstRefUse,
+    ConstPtrUse,
     Ignore
   };
 
@@ -451,8 +452,9 @@ 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, Ignore);
+        classify(UO->getSubExpr(), isTrivialBody ? Ignore : ConstPtrUse);
+      else
+        classify(Ex, Ignore);
     }
   }
 }
@@ -496,6 +498,7 @@ class TransferFunctions : public StmtVisitor<TransferFunctions> {
 
   void reportUse(const Expr *ex, const VarDecl *vd);
   void reportConstRefUse(const Expr *ex, const VarDecl *vd);
+  void reportConstPtrUse(const Expr *ex, const VarDecl *vd);
 
   void VisitBinaryOperator(BinaryOperator *bo);
   void VisitBlockExpr(BlockExpr *be);
@@ -682,6 +685,15 @@ void TransferFunctions::reportConstRefUse(const Expr *ex, const VarDecl *vd) {
   }
 }
 
+void TransferFunctions::reportConstPtrUse(const Expr *ex, const VarDecl *vd) {
+  Value v = vals[vd];
+  if (isAlwaysUninit(v)) {
+    auto use = getUninitUse(ex, vd, v);
+    use.setConstPtrUse();
+    handler.handleUseOfUninitVariable(vd, use);
+  }
+}
+
 void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS) {
   // This represents an initialization of the 'element' value.
   if (const auto *DS = dyn_cast<DeclStmt>(FS->getElement())) {
@@ -754,6 +766,9 @@ void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
   case ClassifyRefs::ConstRefUse:
     reportConstRefUse(dr, cast<VarDecl>(dr->getDecl()));
     break;
+  case ClassifyRefs::ConstPtrUse:
+    reportConstPtrUse(dr, cast<VarDecl>(dr->getDecl()));
+    break;
   }
 }
 
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index ec8acbdff3b49..11e3a3cbd7909 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -993,6 +993,13 @@ static void DiagnoseUninitializedConstRefUse(Sema &S, const VarDecl *VD,
       << VD->getDeclName() << Use.getUser()->getSourceRange();
 }
 
+/// Diagnose uninitialized const pointer usages.
+static void DiagnoseUninitializedConstPtrUse(Sema &S, const VarDecl *VD,
+                                             const UninitUse &Use) {
+  S.Diag(Use.getUser()->getBeginLoc(), diag::warn_uninit_const_pointer)
+      << VD->getDeclName() << Use.getUser()->getSourceRange();
+}
+
 /// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an
 /// uninitialized variable. This manages the different forms of diagnostic
 /// emitted for particular types of uses. Returns true if the use was diagnosed
@@ -1572,9 +1579,9 @@ class UninitValsDiagReporter : public UninitVariablesHandler {
         // guaranteed to produce them in line/column order, this will provide
         // a stable ordering.
         llvm::sort(*vec, [](const UninitUse &a, const UninitUse &b) {
-          // Move ConstRef uses to the back.
-          if (a.isConstRefUse() != b.isConstRefUse())
-            return b.isConstRefUse();
+          // Move ConstRef and ConstPtr uses to the back.
+          if (a.isConstRefOrPtrUse() != b.isConstRefOrPtrUse())
+            return b.isConstRefOrPtrUse();
           // Prefer a more confident report over a less confident one.
           if (a.getKind() != b.getKind())
             return a.getKind() > b.getKind();
@@ -1587,6 +1594,11 @@ class UninitValsDiagReporter : public UninitVariablesHandler {
             break;
           }
 
+          if (U.isConstPtrUse()) {
+            DiagnoseUninitializedConstPtrUse(S, vd, U);
+            break;
+          }
+
           // If we have self-init, downgrade all uses to 'may be uninitialized'.
           UninitUse Use = hasSelfInit ? UninitUse(U.getUser(), false) : U;
 
@@ -2820,7 +2832,8 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
   if (!Diags.isIgnored(diag::warn_uninit_var, D->getBeginLoc()) ||
       !Diags.isIgnored(diag::warn_sometimes_uninit_var, D->getBeginLoc()) ||
       !Diags.isIgnored(diag::warn_maybe_uninit_var, D->getBeginLoc()) ||
-      !Diags.isIgnored(diag::warn_uninit_const_reference, D->getBeginLoc())) {
+      !Diags.isIgnored(diag::warn_uninit_const_reference, D->getBeginLoc()) ||
+      !Diags.isIgnored(diag::warn_uninit_const_pointer, D->getBeginLoc())) {
     if (CFG *cfg = AC.getCFG()) {
       UninitValsDiagReporter reporter(S);
       UninitVariablesAnalysisStats stats;
diff --git a/clang/test/Misc/warning-wall.c b/clang/test/Misc/warning-wall.c
index 91de843f88c91..689868c62f6a7 100644
--- a/clang/test/Misc/warning-wall.c
+++ b/clang/test/Misc/warning-wall.c
@@ -66,6 +66,7 @@ CHECK-NEXT:    -Wuninitialized
 CHECK-NEXT:      -Wsometimes-uninitialized
 CHECK-NEXT:      -Wstatic-self-init
 CHECK-NEXT:      -Wuninitialized-const-reference
+CHECK-NEXT:      -Wuninitialized-const-pointer
 CHECK-NEXT:    -Wunknown-pragmas
 CHECK-NEXT:    -Wunused
 CHECK-NEXT:      -Wunused-argument
diff --git a/clang/test/SemaCXX/warn-uninitialized-const-pointer.cpp b/clang/test/SemaCXX/warn-uninitialized-const-pointer.cpp
new file mode 100644
index 0000000000000..62802ba7375cc
--- /dev/null
+++ b/clang/test/SemaCXX/warn-uninitialized-const-pointer.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -Wuninitialized-const-pointer -verify %s
+
+template <class T>
+void ignore_template(const T *) {}
+void ignore(const int *) {}
+void dont_ignore_non_empty(const int *) { ; } 
+void dont_ignore_block(const int *) { {} }
+void dont_ignore_try_block(const int *) try {
+} catch (...) {
+}
+int const_ptr_use(const int *);
+
+void f(int a) {
+  int i;
+  const_ptr_use(&i);             // expected-warning {{variable 'i' is uninitialized when passed as a const pointer argument here}}
+  int j = j + const_ptr_use(&j); // expected-warning {{variable 'j' is uninitialized when used within its own initialization}}
+  int k = k;                     // expected-warning {{variable 'k' is uninitialized when used within its own initialization}}
+  const_ptr_use(&k);
+
+  // Only report if a variable is always uninitialized at the point of use
+  int l;
+  if (a < 42)
+    l = 1;
+  const_ptr_use(&l);
+
+  // Don't report if the called function is known to be empty.
+  int m;
+  ignore_template(&m);
+  ignore(&m);
+  dont_ignore_non_empty(&m); // expected-warning {{variable 'm' is uninitialized when passed as a const pointer argument here}}
+  int n;
+  dont_ignore_block(&n); // expected-warning {{variable 'n' is uninitialized when passed as a const pointer argument here}}
+  int o;
+  dont_ignore_try_block(&o); // expected-warning {{variable 'o' is uninitialized when passed as a const pointer argument 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 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();

@igorkudrin
Copy link
Collaborator Author

igorkudrin commented Jul 12, 2025

This fixes an additional case reported by @rnapier in #37460, only apply_config() should be made non-empty.

Copy link

github-actions bot commented Jul 12, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@igorkudrin igorkudrin merged commit 00dacf8 into llvm:main Jul 14, 2025
67 of 73 checks passed
@igorkudrin igorkudrin deleted the uninitialized-pass-via-const-ptr branch July 14, 2025 22:44
searlmc1 pushed a commit to ROCm/llvm-project that referenced this pull request Jul 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:analysis clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants