[clang] [Clang] Check for uninitialized use in lambda within CXXOperatorCallExpr (PR #129198)

via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 27 22:19:06 PST 2025


https://github.com/zhaohuiw42 created https://github.com/llvm/llvm-project/pull/129198

Fix #128058.
Track whether a LambdaExpr is an immediate operand of a CXXOperatorCallExpr using a new flag, isInCXXOperatorCall. This enables special handling of capture initializations to detect uninitialized variable uses, such as in `S s = [&]() { return s; }();`.

>From e52e53f5756172f02b8075f0480ee12f4eef9add Mon Sep 17 00:00:00 2001
From: zhaohui <zhaohuiw94 at gmail.com>
Date: Fri, 28 Feb 2025 14:12:39 +0800
Subject: [PATCH] [Clang] Check for uninitialized use in lambda within
 CXXOperatorCallExpr

---
 clang/lib/Sema/SemaDecl.cpp          | 22 ++++++++++++++++++++++
 clang/test/SemaCXX/uninitialized.cpp |  4 ++++
 2 files changed, 26 insertions(+)

diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 285bd27a35a76..ad93b4a858543 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -12597,6 +12597,12 @@ namespace {
     bool isRecordType;
     bool isPODType;
     bool isReferenceType;
+    // Tracks whether the current expression is being visited within a
+    // CXXOperatorCallExpr. This flag is set to true when entering a
+    // CXXOperatorCallExpr and reset to false upon exit. It is used to detect
+    // when a LambdaExpr is an operand of an operator call, enabling special
+    // handling of its capture initializations.
+    bool isInCXXOperatorCall;
 
     bool isInitList;
     llvm::SmallVector<unsigned, 4> InitFieldIndex;
@@ -12609,6 +12615,7 @@ namespace {
       isPODType = false;
       isRecordType = false;
       isReferenceType = false;
+      isInCXXOperatorCall = false;
       isInitList = false;
       if (ValueDecl *VD = dyn_cast<ValueDecl>(OrigDecl)) {
         isPODType = VD->getType().isPODType(S.Context);
@@ -12796,6 +12803,7 @@ namespace {
     }
 
     void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
+      isInCXXOperatorCall = true;
       Expr *Callee = E->getCallee();
 
       if (isa<UnresolvedLookupExpr>(Callee))
@@ -12804,6 +12812,20 @@ namespace {
       Visit(Callee);
       for (auto Arg: E->arguments())
         HandleValue(Arg->IgnoreParenImpCasts());
+      isInCXXOperatorCall = false;
+    }
+
+    void VisitLambdaExpr(LambdaExpr *E) {
+      if (isInCXXOperatorCall) {
+        for (const auto &init : E->capture_inits()) {
+          if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(init))
+            HandleDeclRefExpr(DRE);
+          else
+            Visit(init);
+        }
+        return;
+      }
+      Inherited::VisitLambdaExpr(E);
     }
 
     void VisitUnaryOperator(UnaryOperator *E) {
diff --git a/clang/test/SemaCXX/uninitialized.cpp b/clang/test/SemaCXX/uninitialized.cpp
index 4af2c998f082e..654d955b3cc72 100644
--- a/clang/test/SemaCXX/uninitialized.cpp
+++ b/clang/test/SemaCXX/uninitialized.cpp
@@ -892,6 +892,10 @@ namespace lambdas {
       return a1.x;
     });
     A a2([&] { return a2.x; }); // ok
+    A a3([=]{ return a3.x; }()); // expected-warning{{variable 'a3' is uninitialized when used within its own initialization}}
+    A a4([&]{ return a4.x; }()); // expected-warning{{variable 'a4' is uninitialized when used within its own initialization}}
+    A a5([&]{ return a5; }()); // expected-warning{{variable 'a5' is uninitialized when used within its own initialization}}
+    A a6([&]{ return a5.x; }()); // ok
   }
 }
 



More information about the cfe-commits mailing list