https://github.com/Xazax-hun created 
https://github.com/llvm/llvm-project/pull/204379

VisitBinaryOperator had no comma case, so a comma expression carried none of 
its right operand's loans and a borrow used via a comma result (e.g. `g = (f(), 
p)`) was silently dropped. Flow the RHS's origin into the result.

Assisted-by: Claude Opus 4.8

From 170b89cba393618724a97cc78a7759a34d2a1f5c Mon Sep 17 00:00:00 2001
From: Gabor Horvath <[email protected]>
Date: Wed, 17 Jun 2026 17:23:46 +0100
Subject: [PATCH] [LifetimeSafety] Propagate loans through the comma operator

VisitBinaryOperator had no comma case, so a comma expression carried
none of its right operand's loans and a borrow used via a comma result
(e.g. `g = (f(), p)`) was silently dropped. Flow the RHS's origin into
the result.

Assisted-by: Claude Opus 4.8
---
 .../LifetimeSafety/FactsGenerator.cpp         |  4 ++
 .../Sema/LifetimeSafety/dangling-global.cpp   |  8 +++-
 clang/test/Sema/LifetimeSafety/safety.cpp     | 37 +++++++++++++++++++
 3 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp 
b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index be0577b0f3f8f..10339a9f2e3c5 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -450,6 +450,10 @@ void FactsGenerator::handlePointerArithmetic(const 
BinaryOperator *BO) {
 }
 
 void FactsGenerator::VisitBinaryOperator(const BinaryOperator *BO) {
+  if (BO->getOpcode() == BO_Comma) {
+    killAndFlowOrigin(*BO, *BO->getRHS());
+    return;
+  }
   if (BO->isCompoundAssignmentOp())
     return;
   if (BO->getType()->isPointerType() && BO->isAdditiveOp())
diff --git a/clang/test/Sema/LifetimeSafety/dangling-global.cpp 
b/clang/test/Sema/LifetimeSafety/dangling-global.cpp
index 98f8905d0e2da..f419ff4416023 100644
--- a/clang/test/Sema/LifetimeSafety/dangling-global.cpp
+++ b/clang/test/Sema/LifetimeSafety/dangling-global.cpp
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wno-dangling -verify %s
 
-int *global; // expected-note {{this global dangles}}
+int *global; // expected-note 2 {{this global dangles}}
 int *global_backup; // expected-note {{this global dangles}}
 
 struct ObjWithStaticField {
@@ -32,6 +32,12 @@ void store_local_in_global() {
   global = &local; // expected-warning {{stack memory associated with local 
variable 'local' escapes to the global variable 'global' which will dangle}}
 }
 
+int side();
+void store_local_in_global_via_comma() {
+  int local;
+  global = (side(), &local); // expected-warning {{stack memory associated 
with local variable 'local' escapes to the global variable 'global' which will 
dangle}}
+}
+
 void store_then_clear() {
   int local;
   global = &local;
diff --git a/clang/test/Sema/LifetimeSafety/safety.cpp 
b/clang/test/Sema/LifetimeSafety/safety.cpp
index 3c954cebda820..6fc275b51a9d0 100644
--- a/clang/test/Sema/LifetimeSafety/safety.cpp
+++ b/clang/test/Sema/LifetimeSafety/safety.cpp
@@ -1250,6 +1250,43 @@ void conditional_operator_lifetimebound_nested_deep(bool 
cond) {
   (void)*p;  // expected-note 4 {{later used here}}
 }
 
+// Comma operator.
+int side();
+void comma_use_after_scope() {
+  MyObj* p;
+  {
+    MyObj temp;
+    p = (side(), &temp);  // expected-warning {{local variable 'temp' does not 
live long enough}}
+  }                       // expected-note {{destroyed here}}
+  (void)*p;               // expected-note {{later used here}}
+}
+
+void comma_nested() {
+  MyObj* p;
+  {
+    MyObj temp;
+    p = (side(), (side(), &temp));  // expected-warning {{local variable 
'temp' does not live long enough}}
+  }                                 // expected-note {{destroyed here}}
+  (void)*p;                         // expected-note {{later used here}}
+}
+
+void comma_masked_by_conditional(bool cond) {
+  MyObj safe;
+  MyObj* keep = &safe;
+  MyObj* p;
+  {
+    MyObj temp;
+    p = cond ? keep : (side(), &temp);  // expected-warning {{local variable 
'temp' does not live long enough}}
+  }                                     // expected-note {{destroyed here}}
+  (void)*p;                             // expected-note {{later used here}}
+}
+
+void comma_safe() {
+  MyObj safe;
+  MyObj* p = (side(), &safe);
+  (void)*p;  // no-warning
+}
+
 // FIXME: Diagnostic output does not handle ParenExpr correctly, causing alias
 // information to be missed (local variable 'p' aliases the storage of local 
variable 'b').
 void simpleparen() {

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to