https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/177660
>From 74edd157f2954877df7bf32f45b1419750278f77 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena <[email protected]> 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(); _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
