[llvm-branch-commits] [clang] Transparent functions for all gsl::Pointers (PR #177660)
Utkarsh Saxena via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Jan 27 03:47:32 PST 2026
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/177660
>From 24d1ecfb1b33fd631be02d02b6211a503d0ae740 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Fri, 23 Jan 2026 15:58:55 +0000
Subject: [PATCH] Transparent functions for all gsl::Pointers
---
.../LifetimeSafety/LifetimeAnnotations.cpp | 36 ++++-----
clang/test/Sema/warn-lifetime-safety.cpp | 75 +++++++++++++++++++
2 files changed, 94 insertions(+), 17 deletions(-)
diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
index dd925d2b8fe6e..4215a805dbf91 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
+#include "llvm/ADT/StringSet.h"
namespace clang::lifetimes {
@@ -115,35 +116,36 @@ bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee,
if (isGslPointerType(Conv->getConversionType()) &&
Callee->getParent()->hasAttr<OwnerAttr>())
return true;
- if (!isInStlNamespace(Callee->getParent()))
- return false;
if (!isGslPointerType(Callee->getFunctionObjectParameterType()) &&
!isGslOwnerType(Callee->getFunctionObjectParameterType()))
return false;
+ static const llvm::StringSet<> TransparentFns = {
+ // Begin and end iterators.
+ "begin", "end", "rbegin", "rend", "cbegin", "cend", "crbegin", "crend",
+ // Inner pointer getters.
+ "c_str", "data", "get",
+ // Map and set types.
+ "find", "equal_range", "lower_bound", "upper_bound"};
// Track dereference operator for GSL pointers in STL. Only do so for lifetime
// safety analysis and not for Sema's statement-local analysis as it starts
// to have false-positives.
if (RunningUnderLifetimeSafety &&
- isGslPointerType(Callee->getFunctionObjectParameterType()) &&
- (Callee->getOverloadedOperator() == OverloadedOperatorKind::OO_Star ||
- Callee->getOverloadedOperator() == OverloadedOperatorKind::OO_Arrow))
- return true;
+ isGslPointerType(Callee->getFunctionObjectParameterType())) {
+ if (Callee->getOverloadedOperator() == OverloadedOperatorKind::OO_Star ||
+ Callee->getOverloadedOperator() == OverloadedOperatorKind::OO_Arrow)
+ return true;
+ if (Callee->getIdentifier() && TransparentFns.contains(Callee->getName()))
+ return true;
+ }
+
+ if (!isInStlNamespace(Callee->getParent()))
+ return false;
if (isPointerLikeType(Callee->getReturnType())) {
if (!Callee->getIdentifier())
return false;
- return llvm::StringSwitch<bool>(Callee->getName())
- .Cases(
- {// Begin and end iterators.
- "begin", "end", "rbegin", "rend", "cbegin", "cend", "crbegin",
- "crend",
- // Inner pointer getters.
- "c_str", "data", "get",
- // Map and set types.
- "find", "equal_range", "lower_bound", "upper_bound"},
- true)
- .Default(false);
+ return TransparentFns.contains(Callee->getName());
}
if (Callee->getReturnType()->isReferenceType()) {
if (!Callee->getIdentifier()) {
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index d6064dea9e545..c80556715fedf 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -14,6 +14,7 @@ struct [[gsl::Owner]] MyObj {
MyObj operator+(MyObj);
View getView() const [[clang::lifetimebound]];
+ const int* getData() const [[clang::lifetimebound]];
};
struct [[gsl::Owner]] MyTrivialObj {
@@ -25,6 +26,10 @@ struct [[gsl::Pointer()]] View {
View(const MyTrivialObj &); // Borrows from MyTrivialObj
View();
void use() const;
+
+ const MyObj* data() const;
+ const MyObj& operator*() const;
+ const MyObj* operator->() const;
};
class TriviallyDestructedClass {
@@ -1455,6 +1460,76 @@ void bar() {
}
}
+namespace DereferenceViews {
+const MyObj& testDeref(MyObj obj) {
+ View v = obj; // expected-warning {{address of stack memory is returned later}}
+ return *v; // expected-note {{returned here}}
+}
+const MyObj* testDerefAddr(MyObj obj) {
+ View v = obj; // expected-warning {{address of stack memory is returned later}}
+ return &*v; // expected-note {{returned here}}
+}
+const MyObj* testData(MyObj obj) {
+ View v = obj; // expected-warning {{address of stack memory is returned later}}
+ return v.data(); // expected-note {{returned here}}
+}
+const int* testLifetimeboundAccessorOfMyObj(MyObj obj) {
+ View v = obj; // expected-warning {{address of stack memory is returned later}}
+ const MyObj* ptr = v.data();
+ return ptr->getData(); // expected-note {{returned here}}
+}
+const int* testLifetimeboundAccessorOfMyObjThroughDeref(MyObj obj) {
+ View v = obj; // expected-warning {{address of stack memory is returned later}}
+ return v->getData(); // expected-note {{returned here}}
+}
+} // namespace DereferenceViews
+
+namespace ViewsBeginEndIterators {
+template <typename T>
+struct [[gsl::Pointer]] Iterator {
+ Iterator operator++();
+ T& operator*() const;
+ T* operator->() const;
+ bool operator!=(const Iterator& other) const;
+};
+
+template <typename T>
+struct [[gsl::Owner]] Container {
+using It = Iterator<T>;
+It begin() const [[clang::lifetimebound]];
+It end() const [[clang::lifetimebound]];
+};
+
+MyObj Global;
+
+const MyObj& ContainerMyObjReturnRef(Container<MyObj> c) {
+ for (const MyObj& x : c) { // expected-warning {{address of stack memory is returned later}}
+ return x; // expected-note {{returned here}}
+ }
+ return Global;
+}
+
+View ContainerMyObjReturnView(Container<MyObj> c) {
+ for (const MyObj& x : c) { // expected-warning {{address of stack memory is returned later}}
+ return x; // expected-note {{returned here}}
+ }
+ for (View x : c) { // expected-warning {{address of stack memory is returned later}}
+ return x; // expected-note {{returned here}}
+ }
+ return Global;
+}
+
+View ContainerViewsOk(Container<View> c) {
+ for (View x : c) {
+ return x;
+ }
+ for (const View& x : c) {
+ return x;
+ }
+ return Global;
+}
+} // namespace ViewsBeginEndIterators
+
namespace reference_type_decl_ref_expr {
struct S {
S();
More information about the llvm-branch-commits
mailing list