https://github.com/mrcvtl updated 
https://github.com/llvm/llvm-project/pull/145164

>From b5146278ce5059b6bf0312f18f509022de5fd661 Mon Sep 17 00:00:00 2001
From: Marco Vitale <mar.vit...@icloud.com>
Date: Sat, 21 Jun 2025 14:01:53 +0200
Subject: [PATCH 1/2] [Sema] Fix lifetime extension for temporaries in
 range-based for loops in C++23

C++23 mandates that temporaries used in range-based for loops are 
lifetime-extended
to cover the full loop. This patch adds a check for loop variables and compiler-
generated `__range` bindings to apply the correct extension.

Includes test cases based on examples from CWG900/P2644R1.
---
 clang/docs/ReleaseNotes.rst                   |  4 +++
 clang/lib/Sema/CheckExprLifetime.cpp          |  5 ++++
 clang/lib/Sema/SemaStmt.cpp                   |  3 +++
 .../test/SemaCXX/range-for-lifetime-cxx23.cpp | 27 +++++++++++++++++++
 4 files changed, 39 insertions(+)
 create mode 100644 clang/test/SemaCXX/range-for-lifetime-cxx23.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index d9847fadc21e5..d79df8c9184be 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -648,6 +648,10 @@ Improvements to Clang's diagnostics
   #GH142457, #GH139913, #GH138850, #GH137867, #GH137860, #GH107840, #GH93308,
   #GH69470, #GH59391, #GH58172, #GH46215, #GH45915, #GH45891, #GH44490,
   #GH36703, #GH32903, #GH23312, #GH69874.
+  
+- Clang no longer emits a spurious -Wdangling-gsl warning in C++23 when
+  iterating over an element of a temporary container in a range-based
+  for loop.(#GH109793, #GH145164)
 
 - Clang now avoids issuing `-Wreturn-type` warnings in some cases where
   the final statement of a non-void function is a `throw` expression, or
diff --git a/clang/lib/Sema/CheckExprLifetime.cpp 
b/clang/lib/Sema/CheckExprLifetime.cpp
index 060ba31660556..114e4f989ed9f 100644
--- a/clang/lib/Sema/CheckExprLifetime.cpp
+++ b/clang/lib/Sema/CheckExprLifetime.cpp
@@ -57,6 +57,7 @@ enum LifetimeKind {
 };
 using LifetimeResult =
     llvm::PointerIntPair<const InitializedEntity *, 3, LifetimeKind>;
+
 } // namespace
 
 /// Determine the declaration which an initialized entity ultimately refers to,
@@ -1341,6 +1342,10 @@ checkExprLifetimeImpl(Sema &SemaRef, const 
InitializedEntity *InitEntity,
       }
 
       if (IsGslPtrValueFromGslTempOwner && DiagLoc.isValid()) {
+        if (SemaRef.getLangOpts().CPlusPlus23 &&
+            SemaRef.isInLifetimeExtendingContext())
+          return false;
+
         SemaRef.Diag(DiagLoc, diag::warn_dangling_lifetime_pointer)
             << DiagRange;
         return false;
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 923a9e81fbd6a..633f73946b729 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -2374,6 +2374,9 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl 
*Decl, Expr *Init,
       SemaRef.ObjC().inferObjCARCLifetime(Decl))
     Decl->setInvalidDecl();
 
+  if (SemaRef.getLangOpts().CPlusPlus23)
+    SemaRef.currentEvaluationContext().InLifetimeExtendingContext = true;
+
   SemaRef.AddInitializerToDecl(Decl, Init, /*DirectInit=*/false);
   SemaRef.FinalizeDeclaration(Decl);
   SemaRef.CurContext->addHiddenDecl(Decl);
diff --git a/clang/test/SemaCXX/range-for-lifetime-cxx23.cpp 
b/clang/test/SemaCXX/range-for-lifetime-cxx23.cpp
new file mode 100644
index 0000000000000..c36fd6c246347
--- /dev/null
+++ b/clang/test/SemaCXX/range-for-lifetime-cxx23.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify %s
+
+using size_t = decltype(sizeof(void *));
+
+namespace std {
+template <typename T> struct vector {
+  T &operator[](size_t I);
+};
+
+struct string {
+  const char *begin();
+  const char *end();
+};
+
+} // namespace std
+
+std::vector<std::string> getData();
+
+void foo() {
+  // Verifies we don't trigger a diagnostic from -Wdangling-gsl
+  // when iterating over a temporary in C++23.
+  for (auto c : getData()[0]) {
+    (void)c;
+  }
+}
+
+// expected-no-diagnostics

>From b2e1333c2b9e61ffb8b85d1613c137f8f96a73e4 Mon Sep 17 00:00:00 2001
From: Marco Vitale <mar.vit...@icloud.com>
Date: Sat, 28 Jun 2025 00:25:33 +0200
Subject: [PATCH 2/2] Add as a flag in VarDecl

---
 clang/include/clang/AST/Decl.h            | 19 +++++++++++++++++++
 clang/lib/Sema/CheckExprLifetime.cpp      |  9 ++++++---
 clang/lib/Sema/SemaStmt.cpp               |  1 +
 clang/lib/Serialization/ASTReaderDecl.cpp |  1 +
 clang/lib/Serialization/ASTWriterDecl.cpp |  2 ++
 5 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index c4202f1f3d07e..eee925b01d9e8 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -1086,6 +1086,11 @@ class VarDecl : public DeclaratorDecl, public 
Redeclarable<VarDecl> {
 
     LLVM_PREFERRED_TYPE(bool)
     unsigned IsCXXCondDecl : 1;
+
+    /// Whether this variable is the implicit __range variable in a for-range
+    /// loop.
+    LLVM_PREFERRED_TYPE(bool)
+    unsigned IsCXXForRangeImplicitVar : 1;
   };
 
   union {
@@ -1585,6 +1590,20 @@ class VarDecl : public DeclaratorDecl, public 
Redeclarable<VarDecl> {
     NonParmVarDeclBits.IsCXXCondDecl = true;
   }
 
+  /// Determine whether this variable is the compiler-generated '__range'
+  /// variable used to hold the range expression in a C++11 and later for-range
+  /// statement.
+  bool isCXXForRangeImplicitVar() const {
+    return isa<ParmVarDecl>(this) ? false
+                                  : 
NonParmVarDeclBits.IsCXXForRangeImplicitVar;
+  }
+
+  void setCXXForRangeImplicitVar(bool FRV) {
+    assert(!isa<ParmVarDecl>(this) &&
+           "Cannot set IsCXXForRangeRangeVar on ParmVarDecl");
+    NonParmVarDeclBits.IsCXXForRangeImplicitVar = FRV;
+  }
+
   /// Determines if this variable's alignment is dependent.
   bool hasDependentAlignment() const;
 
diff --git a/clang/lib/Sema/CheckExprLifetime.cpp 
b/clang/lib/Sema/CheckExprLifetime.cpp
index 114e4f989ed9f..fc52de1e6bd89 100644
--- a/clang/lib/Sema/CheckExprLifetime.cpp
+++ b/clang/lib/Sema/CheckExprLifetime.cpp
@@ -1342,9 +1342,12 @@ checkExprLifetimeImpl(Sema &SemaRef, const 
InitializedEntity *InitEntity,
       }
 
       if (IsGslPtrValueFromGslTempOwner && DiagLoc.isValid()) {
-        if (SemaRef.getLangOpts().CPlusPlus23 &&
-            SemaRef.isInLifetimeExtendingContext())
-          return false;
+
+        if (SemaRef.getLangOpts().CPlusPlus23) {
+          if (const VarDecl *VD = cast<VarDecl>(InitEntity->getDecl());
+              VD && VD->isCXXForRangeImplicitVar())
+            return false;
+        }
 
         SemaRef.Diag(DiagLoc, diag::warn_dangling_lifetime_pointer)
             << DiagRange;
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 633f73946b729..ef0aff1b2838f 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -2426,6 +2426,7 @@ VarDecl *BuildForRangeVarDecl(Sema &SemaRef, 
SourceLocation Loc,
   VarDecl *Decl = VarDecl::Create(SemaRef.Context, DC, Loc, Loc, II, Type,
                                   TInfo, SC_None);
   Decl->setImplicit();
+  Decl->setCXXForRangeImplicitVar(true);
   return Decl;
 }
 
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp 
b/clang/lib/Serialization/ASTReaderDecl.cpp
index 0ffd78424be0d..e6a8a0a243401 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -1637,6 +1637,7 @@ RedeclarableResult 
ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
         VarDeclBits.getNextBits(/*Width*/ 3);
 
     VD->NonParmVarDeclBits.ObjCForDecl = VarDeclBits.getNextBit();
+    VD->NonParmVarDeclBits.IsCXXForRangeImplicitVar = VarDeclBits.getNextBit();
   }
 
   // If this variable has a deduced type, defer reading that type until we are
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp 
b/clang/lib/Serialization/ASTWriterDecl.cpp
index 7457c4920dd10..8064ccae1a64e 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -1319,6 +1319,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
       VarDeclBits.addBits(0, /*Width=*/3);
 
     VarDeclBits.addBit(D->isObjCForDecl());
+    VarDeclBits.addBit(D->isCXXForRangeImplicitVar());
   }
 
   Record.push_back(VarDeclBits);
@@ -2740,6 +2741,7 @@ void ASTWriter::WriteDeclAbbrevs() {
             // isInline, isInlineSpecified, isConstexpr,
             // isInitCapture, isPrevDeclInSameScope, hasInitWithSideEffects,
             // EscapingByref, HasDeducedType, ImplicitParamKind, isObjCForDecl
+            // isCXXForRangeDecl
   Abv->Add(BitCodeAbbrevOp(0));                         // VarKind (local enum)
   // Type Source Info
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to