[clang] [clang] Check specialization for annotation (PR #117315)

Utkarsh Saxena via cfe-commits cfe-commits at lists.llvm.org
Thu Nov 28 03:41:50 PST 2024


https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/117315

>From e30ae8a6e0c1df8e33c2add6502342cb269c1cfd Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Fri, 22 Nov 2024 11:02:49 +0000
Subject: [PATCH 1/8] [clang] Check specialization for annotation

---
 clang/lib/Sema/CheckExprLifetime.cpp | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp
index 8886e5e307ddf8..64dc4794b6235a 100644
--- a/clang/lib/Sema/CheckExprLifetime.cpp
+++ b/clang/lib/Sema/CheckExprLifetime.cpp
@@ -253,9 +253,12 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
                                                   LocalVisitor Visit);
 
 template <typename T> static bool isRecordWithAttr(QualType Type) {
-  if (auto *RD = Type->getAsCXXRecordDecl())
-    return RD->hasAttr<T>();
-  return false;
+  auto *RD = Type->getAsCXXRecordDecl();
+  if (!RD)
+    return false;
+  if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
+    RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
+  return RD->hasAttr<T>();
 }
 
 // Decl::isInStdNamespace will return false for iterators in some STL

>From db163394b70054694734c269f5fd61ef438eda3b Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Thu, 28 Nov 2024 09:01:25 +0000
Subject: [PATCH 2/8] move to Sema.h

---
 clang/include/clang/Sema/Sema.h      | 12 ++++++++
 clang/lib/Sema/CheckExprLifetime.cpp | 45 ++++++++++------------------
 clang/lib/Sema/SemaAttr.cpp          |  5 ++++
 3 files changed, 33 insertions(+), 29 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 6ea6c67447b6f0..9029d54e90f028 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1760,6 +1760,18 @@ class Sema final : public SemaBase {
   /// Add [[gsl::Pointer]] attributes for std:: types.
   void inferGslPointerAttribute(TypedefNameDecl *TD);
 
+  template <typename T> static bool isRecordWithAttr(QualType Type) {
+    auto *RD = Type->getAsCXXRecordDecl();
+    if (!RD)
+      return false;
+    if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
+      RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
+    return RD->hasAttr<T>();
+  }
+
+  /// ....
+  static bool isPointerLikeType(QualType Type);
+
   LifetimeCaptureByAttr *ParseLifetimeCaptureByAttr(const ParsedAttr &AL,
                                                     StringRef ParamName);
   // Processes the argument 'X' in [[clang::lifetime_capture_by(X)]]. Since 'X'
diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp
index 64dc4794b6235a..e18651d8e12ab9 100644
--- a/clang/lib/Sema/CheckExprLifetime.cpp
+++ b/clang/lib/Sema/CheckExprLifetime.cpp
@@ -252,15 +252,6 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
                                                   Expr *Init, ReferenceKind RK,
                                                   LocalVisitor Visit);
 
-template <typename T> static bool isRecordWithAttr(QualType Type) {
-  auto *RD = Type->getAsCXXRecordDecl();
-  if (!RD)
-    return false;
-  if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
-    RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
-  return RD->hasAttr<T>();
-}
-
 // Decl::isInStdNamespace will return false for iterators in some STL
 // implementations due to them being defined in a namespace outside of the std
 // namespace.
@@ -279,11 +270,6 @@ static bool isInStlNamespace(const Decl *D) {
   return DC->isStdNamespace();
 }
 
-static bool isPointerLikeType(QualType Type) {
-  return isRecordWithAttr<PointerAttr>(Type) || Type->isPointerType() ||
-         Type->isNullPtrType();
-}
-
 // Returns true if the given Record decl is a form of `GSLOwner<Pointer>`
 // type, e.g. std::vector<string_view>, std::optional<string_view>.
 static bool isContainerOfPointer(const RecordDecl *Container) {
@@ -293,7 +279,7 @@ static bool isContainerOfPointer(const RecordDecl *Container) {
       return false;
     const auto &TAs = CTSD->getTemplateArgs();
     return TAs.size() > 0 && TAs[0].getKind() == TemplateArgument::Type &&
-           isPointerLikeType(TAs[0].getAsType());
+           Sema::isPointerLikeType(TAs[0].getAsType());
   }
   return false;
 }
@@ -306,7 +292,7 @@ static bool isContainerOfOwner(const RecordDecl *Container) {
     return false;
   const auto &TAs = CTSD->getTemplateArgs();
   return TAs.size() > 0 && TAs[0].getKind() == TemplateArgument::Type &&
-         isRecordWithAttr<OwnerAttr>(TAs[0].getAsType());
+         Sema::isRecordWithAttr<OwnerAttr>(TAs[0].getAsType());
 }
 
 // Returns true if the given Record is `std::initializer_list<pointer>`.
@@ -317,23 +303,24 @@ static bool isStdInitializerListOfPointer(const RecordDecl *RD) {
     return isInStlNamespace(RD) && RD->getIdentifier() &&
            RD->getName() == "initializer_list" && TAs.size() > 0 &&
            TAs[0].getKind() == TemplateArgument::Type &&
-           isPointerLikeType(TAs[0].getAsType());
+           Sema::isPointerLikeType(TAs[0].getAsType());
   }
   return false;
 }
 
 static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) {
   if (auto *Conv = dyn_cast_or_null<CXXConversionDecl>(Callee))
-    if (isRecordWithAttr<PointerAttr>(Conv->getConversionType()) &&
+    if (Sema::isRecordWithAttr<PointerAttr>(Conv->getConversionType()) &&
         Callee->getParent()->hasAttr<OwnerAttr>())
       return true;
   if (!isInStlNamespace(Callee->getParent()))
     return false;
-  if (!isRecordWithAttr<PointerAttr>(
+  if (!Sema::isRecordWithAttr<PointerAttr>(
           Callee->getFunctionObjectParameterType()) &&
-      !isRecordWithAttr<OwnerAttr>(Callee->getFunctionObjectParameterType()))
+      !Sema::isRecordWithAttr<OwnerAttr>(
+          Callee->getFunctionObjectParameterType()))
     return false;
-  if (isPointerLikeType(Callee->getReturnType())) {
+  if (Sema::isPointerLikeType(Callee->getReturnType())) {
     if (!Callee->getIdentifier())
       return false;
     return llvm::StringSwitch<bool>(Callee->getName())
@@ -366,7 +353,7 @@ static bool shouldTrackFirstArgument(const FunctionDecl *FD) {
   if (!RD->hasAttr<PointerAttr>() && !RD->hasAttr<OwnerAttr>())
     return false;
   if (FD->getReturnType()->isPointerType() ||
-      isRecordWithAttr<PointerAttr>(FD->getReturnType())) {
+      Sema::isRecordWithAttr<PointerAttr>(FD->getReturnType())) {
     return llvm::StringSwitch<bool>(FD->getName())
         .Cases("begin", "rbegin", "cbegin", "crbegin", true)
         .Cases("end", "rend", "cend", "crend", true)
@@ -438,7 +425,7 @@ shouldTrackFirstArgumentForConstructor(const CXXConstructExpr *Ctor) {
     return true;
 
   // RHS must be an owner.
-  if (!isRecordWithAttr<OwnerAttr>(RHSArgType))
+  if (!Sema::isRecordWithAttr<OwnerAttr>(RHSArgType))
     return false;
 
   // Bail out if the RHS is Owner<Pointer>.
@@ -565,7 +552,7 @@ static void visitFunctionCallArguments(IndirectLocalPath &Path, Expr *Call,
     // Once we initialized a value with a non gsl-owner reference, it can no
     // longer dangle.
     if (ReturnType->isReferenceType() &&
-        !isRecordWithAttr<OwnerAttr>(ReturnType->getPointeeType())) {
+        !Sema::isRecordWithAttr<OwnerAttr>(ReturnType->getPointeeType())) {
       for (const IndirectLocalPathEntry &PE : llvm::reverse(Path)) {
         if (PE.Kind == IndirectLocalPathEntry::GslReferenceInit ||
             PE.Kind == IndirectLocalPathEntry::LifetimeBoundCall)
@@ -1111,7 +1098,7 @@ static bool shouldRunGSLAssignmentAnalysis(const Sema &SemaRef,
   bool EnableGSLAssignmentWarnings = !SemaRef.getDiagnostics().isIgnored(
       diag::warn_dangling_lifetime_pointer_assignment, SourceLocation());
   return (EnableGSLAssignmentWarnings &&
-          (isRecordWithAttr<PointerAttr>(Entity.LHS->getType()) ||
+          (Sema::isRecordWithAttr<PointerAttr>(Entity.LHS->getType()) ||
            isAssignmentOperatorLifetimeBound(Entity.AssignmentOperator)));
 }
 
@@ -1146,12 +1133,12 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
         //   someContainer.add(std::move(localUniquePtr));
         //   return p;
         if (pathContainsInit(Path) ||
-            !isRecordWithAttr<OwnerAttr>(L->getType()))
+            !Sema::isRecordWithAttr<OwnerAttr>(L->getType()))
           return false;
       } else {
         IsGslPtrValueFromGslTempOwner =
             MTE && !MTE->getExtendingDecl() &&
-            isRecordWithAttr<OwnerAttr>(MTE->getType());
+            Sema::isRecordWithAttr<OwnerAttr>(MTE->getType());
         // Skipping a chain of initializing gsl::Pointer annotated objects.
         // We are looking only for the final source to find out if it was
         // a local or temporary owner or the address of a local variable/param.
@@ -1280,7 +1267,7 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
         auto *DRE = dyn_cast<DeclRefExpr>(L);
         // Suppress false positives for code like the one below:
         //   Ctor(unique_ptr<T> up) : pointer(up.get()), owner(move(up)) {}
-        if (DRE && isRecordWithAttr<OwnerAttr>(DRE->getType()))
+        if (DRE && Sema::isRecordWithAttr<OwnerAttr>(DRE->getType()))
           return false;
 
         auto *VD = DRE ? dyn_cast<VarDecl>(DRE->getDecl()) : nullptr;
@@ -1441,7 +1428,7 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
     break;
   }
   case LK_LifetimeCapture: {
-    if (isPointerLikeType(Init->getType()))
+    if (Sema::isPointerLikeType(Init->getType()))
       Path.push_back({IndirectLocalPathEntry::GslPointerInit, Init});
     break;
   }
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 9fbad7ed67ccbe..9d21a01cd1b186 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -215,6 +215,11 @@ void Sema::inferGslOwnerPointerAttribute(CXXRecordDecl *Record) {
   inferGslPointerAttribute(Record, Record);
 }
 
+bool Sema::isPointerLikeType(QualType Type) {
+  return isRecordWithAttr<PointerAttr>(Type) || Type->isPointerType() ||
+         Type->isNullPtrType();
+}
+
 void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
   if (FD->getNumParams() == 0)
     return;

>From 9b412ba242f47f2d16f53615dba6cbd2392a5042 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Thu, 28 Nov 2024 09:12:46 +0000
Subject: [PATCH 3/8] reuse in lifetime capture by

---
 clang/lib/Sema/SemaAttr.cpp | 14 +-------------
 1 file changed, 1 insertion(+), 13 deletions(-)

diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index ba87262fc6d435..53a7387ad69353 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -274,18 +274,6 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
   }
 }
 
-static bool isPointerLikeType(QualType QT) {
-  QT = QT.getNonReferenceType();
-  if (QT->isPointerType())
-    return true;
-  auto *RD = QT->getAsCXXRecordDecl();
-  if (!RD)
-    return false;
-  if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
-    RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
-  return RD->hasAttr<PointerAttr>();
-}
-
 void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) {
   if (!FD)
     return;
@@ -304,7 +292,7 @@ void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) {
     if (PVD->hasAttr<LifetimeCaptureByAttr>())
       return;
   for (ParmVarDecl *PVD : MD->parameters()) {
-    if (isPointerLikeType(PVD->getType())) {
+    if (isPointerLikeType(PVD->getType().getNonReferenceType())) {
       int CaptureByThis[] = {LifetimeCaptureByAttr::THIS};
       PVD->addAttr(
           LifetimeCaptureByAttr::CreateImplicit(Context, CaptureByThis, 1));

>From f9f863f14bb8d65cfeaf34afad8c101b96b46eca Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Thu, 28 Nov 2024 10:45:56 +0000
Subject: [PATCH 4/8] address comments

---
 clang/include/clang/Sema/Sema.h      | 12 +-------
 clang/lib/Sema/CheckExprLifetime.cpp | 43 ++++++++++++++++++++--------
 clang/lib/Sema/SemaAttr.cpp          |  6 ----
 3 files changed, 32 insertions(+), 29 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index ebf09aa40d592f..c2182ddf7abff6 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1763,17 +1763,7 @@ class Sema final : public SemaBase {
   /// Add [[gsl::Pointer]] attributes for std:: types.
   void inferGslPointerAttribute(TypedefNameDecl *TD);
 
-  template <typename T> static bool isRecordWithAttr(QualType Type) {
-    auto *RD = Type->getAsCXXRecordDecl();
-    if (!RD)
-      return false;
-    if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
-      RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
-    return RD->hasAttr<T>();
-  }
-
-  /// ....
-  static bool isPointerLikeType(QualType Type);
+  static bool isPointerLikeType(QualType QT);
 
   LifetimeCaptureByAttr *ParseLifetimeCaptureByAttr(const ParsedAttr &AL,
                                                     StringRef ParamName);
diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp
index 6318e044ffdb77..7f069393a3a00f 100644
--- a/clang/lib/Sema/CheckExprLifetime.cpp
+++ b/clang/lib/Sema/CheckExprLifetime.cpp
@@ -9,6 +9,7 @@
 #include "CheckExprLifetime.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
 #include "clang/Basic/DiagnosticSema.h"
 #include "clang/Sema/Initialization.h"
 #include "clang/Sema/Sema.h"
@@ -252,6 +253,24 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
                                                   Expr *Init, ReferenceKind RK,
                                                   LocalVisitor Visit);
 
+template <typename T> static bool isRecordWithAttr(QualType Type) {
+  auto *RD = Type->getAsCXXRecordDecl();
+  if (!RD)
+    return false;
+  if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
+    RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
+  return RD->hasAttr<T>();
+}
+} // namespace clang::sema
+
+namespace clang {
+bool Sema::isPointerLikeType(QualType QT) {
+  return sema::isRecordWithAttr<PointerAttr>(QT) || QT->isPointerType() ||
+         QT->isNullPtrType();
+}
+} // namespace clang
+
+namespace clang::sema {
 // Decl::isInStdNamespace will return false for iterators in some STL
 // implementations due to them being defined in a namespace outside of the std
 // namespace.
@@ -292,7 +311,7 @@ static bool isContainerOfOwner(const RecordDecl *Container) {
     return false;
   const auto &TAs = CTSD->getTemplateArgs();
   return TAs.size() > 0 && TAs[0].getKind() == TemplateArgument::Type &&
-         Sema::isRecordWithAttr<OwnerAttr>(TAs[0].getAsType());
+         isRecordWithAttr<OwnerAttr>(TAs[0].getAsType());
 }
 
 // Returns true if the given Record is `std::initializer_list<pointer>`.
@@ -310,14 +329,14 @@ static bool isStdInitializerListOfPointer(const RecordDecl *RD) {
 
 static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) {
   if (auto *Conv = dyn_cast_or_null<CXXConversionDecl>(Callee))
-    if (Sema::isRecordWithAttr<PointerAttr>(Conv->getConversionType()) &&
+    if (isRecordWithAttr<PointerAttr>(Conv->getConversionType()) &&
         Callee->getParent()->hasAttr<OwnerAttr>())
       return true;
   if (!isInStlNamespace(Callee->getParent()))
     return false;
-  if (!Sema::isRecordWithAttr<PointerAttr>(
+  if (!isRecordWithAttr<PointerAttr>(
           Callee->getFunctionObjectParameterType()) &&
-      !Sema::isRecordWithAttr<OwnerAttr>(
+      !isRecordWithAttr<OwnerAttr>(
           Callee->getFunctionObjectParameterType()))
     return false;
   if (Sema::isPointerLikeType(Callee->getReturnType())) {
@@ -353,7 +372,7 @@ static bool shouldTrackFirstArgument(const FunctionDecl *FD) {
   if (!RD->hasAttr<PointerAttr>() && !RD->hasAttr<OwnerAttr>())
     return false;
   if (FD->getReturnType()->isPointerType() ||
-      Sema::isRecordWithAttr<PointerAttr>(FD->getReturnType())) {
+      isRecordWithAttr<PointerAttr>(FD->getReturnType())) {
     return llvm::StringSwitch<bool>(FD->getName())
         .Cases("begin", "rbegin", "cbegin", "crbegin", true)
         .Cases("end", "rend", "cend", "crend", true)
@@ -425,7 +444,7 @@ shouldTrackFirstArgumentForConstructor(const CXXConstructExpr *Ctor) {
     return true;
 
   // RHS must be an owner.
-  if (!Sema::isRecordWithAttr<OwnerAttr>(RHSArgType))
+  if (!isRecordWithAttr<OwnerAttr>(RHSArgType))
     return false;
 
   // Bail out if the RHS is Owner<Pointer>.
@@ -552,7 +571,7 @@ static void visitFunctionCallArguments(IndirectLocalPath &Path, Expr *Call,
     // Once we initialized a value with a non gsl-owner reference, it can no
     // longer dangle.
     if (ReturnType->isReferenceType() &&
-        !Sema::isRecordWithAttr<OwnerAttr>(ReturnType->getPointeeType())) {
+        !isRecordWithAttr<OwnerAttr>(ReturnType->getPointeeType())) {
       for (const IndirectLocalPathEntry &PE : llvm::reverse(Path)) {
         if (PE.Kind == IndirectLocalPathEntry::GslReferenceInit ||
             PE.Kind == IndirectLocalPathEntry::LifetimeBoundCall)
@@ -1098,7 +1117,7 @@ static bool shouldRunGSLAssignmentAnalysis(const Sema &SemaRef,
   bool EnableGSLAssignmentWarnings = !SemaRef.getDiagnostics().isIgnored(
       diag::warn_dangling_lifetime_pointer_assignment, SourceLocation());
   return (EnableGSLAssignmentWarnings &&
-          (Sema::isRecordWithAttr<PointerAttr>(Entity.LHS->getType()) ||
+          (isRecordWithAttr<PointerAttr>(Entity.LHS->getType()) ||
            isAssignmentOperatorLifetimeBound(Entity.AssignmentOperator)));
 }
 
@@ -1133,12 +1152,12 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
         //   someContainer.add(std::move(localUniquePtr));
         //   return p;
         if (pathContainsInit(Path) ||
-            !Sema::isRecordWithAttr<OwnerAttr>(L->getType()))
+            !isRecordWithAttr<OwnerAttr>(L->getType()))
           return false;
       } else {
         IsGslPtrValueFromGslTempOwner =
             MTE && !MTE->getExtendingDecl() &&
-            Sema::isRecordWithAttr<OwnerAttr>(MTE->getType());
+            isRecordWithAttr<OwnerAttr>(MTE->getType());
         // Skipping a chain of initializing gsl::Pointer annotated objects.
         // We are looking only for the final source to find out if it was
         // a local or temporary owner or the address of a local variable/param.
@@ -1267,7 +1286,7 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
         auto *DRE = dyn_cast<DeclRefExpr>(L);
         // Suppress false positives for code like the one below:
         //   Ctor(unique_ptr<T> up) : pointer(up.get()), owner(move(up)) {}
-        if (DRE && Sema::isRecordWithAttr<OwnerAttr>(DRE->getType()))
+        if (DRE && isRecordWithAttr<OwnerAttr>(DRE->getType()))
           return false;
 
         auto *VD = DRE ? dyn_cast<VarDecl>(DRE->getDecl()) : nullptr;
@@ -1490,4 +1509,4 @@ void checkCaptureByLifetime(Sema &SemaRef, const CapturingEntity &Entity,
                                /*CapEntity=*/&Entity, Init);
 }
 
-} // namespace clang::sema
+} // namespace sema
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 53a7387ad69353..f568ed277b0e9e 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -11,7 +11,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "CheckExprLifetime.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/Attr.h"
 #include "clang/AST/Expr.h"
@@ -216,11 +215,6 @@ void Sema::inferGslOwnerPointerAttribute(CXXRecordDecl *Record) {
   inferGslPointerAttribute(Record, Record);
 }
 
-bool Sema::isPointerLikeType(QualType Type) {
-  return isRecordWithAttr<PointerAttr>(Type) || Type->isPointerType() ||
-         Type->isNullPtrType();
-}
-
 void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
   if (FD->getNumParams() == 0)
     return;

>From a847f8bf8d02edb0b9615856713ec122cee1e927 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Thu, 28 Nov 2024 10:46:49 +0000
Subject: [PATCH 5/8] fix namespace

---
 clang/lib/Sema/CheckExprLifetime.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp
index 7f069393a3a00f..f522c46c6c4388 100644
--- a/clang/lib/Sema/CheckExprLifetime.cpp
+++ b/clang/lib/Sema/CheckExprLifetime.cpp
@@ -1509,4 +1509,4 @@ void checkCaptureByLifetime(Sema &SemaRef, const CapturingEntity &Entity,
                                /*CapEntity=*/&Entity, Init);
 }
 
-} // namespace sema
+} // namespace clang::sema

>From 29db0128913d0e8f666ddce3c7ee57b1fb86060e Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Thu, 28 Nov 2024 11:21:19 +0000
Subject: [PATCH 6/8] format

---
 clang/lib/Sema/CheckExprLifetime.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp
index f522c46c6c4388..2970f1fa0c5692 100644
--- a/clang/lib/Sema/CheckExprLifetime.cpp
+++ b/clang/lib/Sema/CheckExprLifetime.cpp
@@ -336,8 +336,7 @@ static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) {
     return false;
   if (!isRecordWithAttr<PointerAttr>(
           Callee->getFunctionObjectParameterType()) &&
-      !isRecordWithAttr<OwnerAttr>(
-          Callee->getFunctionObjectParameterType()))
+      !isRecordWithAttr<OwnerAttr>(Callee->getFunctionObjectParameterType()))
     return false;
   if (Sema::isPointerLikeType(Callee->getReturnType())) {
     if (!Callee->getIdentifier())

>From 241a35c277263bc1890a4cf5131e652c8e564450 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Thu, 28 Nov 2024 11:31:49 +0000
Subject: [PATCH 7/8] docs

---
 clang/include/clang/Sema/Sema.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index c2182ddf7abff6..343d21738dad55 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1763,6 +1763,8 @@ class Sema final : public SemaBase {
   /// Add [[gsl::Pointer]] attributes for std:: types.
   void inferGslPointerAttribute(TypedefNameDecl *TD);
 
+  // Tells whether the type is annotated with [[gsl::Pointer]] or is a pointer
+  // type.
   static bool isPointerLikeType(QualType QT);
 
   LifetimeCaptureByAttr *ParseLifetimeCaptureByAttr(const ParsedAttr &AL,

>From 203a349ab94020dd14fd4d9a9739482a917e6eb5 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Thu, 28 Nov 2024 11:41:27 +0000
Subject: [PATCH 8/8] move to CheckExprLifetime.h

---
 clang/include/clang/Sema/Sema.h      |  4 ----
 clang/lib/Sema/CheckExprLifetime.cpp | 16 ++++++----------
 clang/lib/Sema/CheckExprLifetime.h   |  4 ++++
 clang/lib/Sema/SemaAttr.cpp          |  3 ++-
 4 files changed, 12 insertions(+), 15 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 343d21738dad55..b8684d11460eda 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1763,10 +1763,6 @@ class Sema final : public SemaBase {
   /// Add [[gsl::Pointer]] attributes for std:: types.
   void inferGslPointerAttribute(TypedefNameDecl *TD);
 
-  // Tells whether the type is annotated with [[gsl::Pointer]] or is a pointer
-  // type.
-  static bool isPointerLikeType(QualType QT);
-
   LifetimeCaptureByAttr *ParseLifetimeCaptureByAttr(const ParsedAttr &AL,
                                                     StringRef ParamName);
   // Processes the argument 'X' in [[clang::lifetime_capture_by(X)]]. Since 'X'
diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp
index 2970f1fa0c5692..069d85cc0bc8c0 100644
--- a/clang/lib/Sema/CheckExprLifetime.cpp
+++ b/clang/lib/Sema/CheckExprLifetime.cpp
@@ -261,16 +261,12 @@ template <typename T> static bool isRecordWithAttr(QualType Type) {
     RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
   return RD->hasAttr<T>();
 }
-} // namespace clang::sema
 
-namespace clang {
-bool Sema::isPointerLikeType(QualType QT) {
-  return sema::isRecordWithAttr<PointerAttr>(QT) || QT->isPointerType() ||
+bool isPointerLikeType(QualType QT) {
+  return isRecordWithAttr<PointerAttr>(QT) || QT->isPointerType() ||
          QT->isNullPtrType();
 }
-} // namespace clang
 
-namespace clang::sema {
 // Decl::isInStdNamespace will return false for iterators in some STL
 // implementations due to them being defined in a namespace outside of the std
 // namespace.
@@ -298,7 +294,7 @@ static bool isContainerOfPointer(const RecordDecl *Container) {
       return false;
     const auto &TAs = CTSD->getTemplateArgs();
     return TAs.size() > 0 && TAs[0].getKind() == TemplateArgument::Type &&
-           Sema::isPointerLikeType(TAs[0].getAsType());
+           isPointerLikeType(TAs[0].getAsType());
   }
   return false;
 }
@@ -322,7 +318,7 @@ static bool isStdInitializerListOfPointer(const RecordDecl *RD) {
     return isInStlNamespace(RD) && RD->getIdentifier() &&
            RD->getName() == "initializer_list" && TAs.size() > 0 &&
            TAs[0].getKind() == TemplateArgument::Type &&
-           Sema::isPointerLikeType(TAs[0].getAsType());
+           isPointerLikeType(TAs[0].getAsType());
   }
   return false;
 }
@@ -338,7 +334,7 @@ static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) {
           Callee->getFunctionObjectParameterType()) &&
       !isRecordWithAttr<OwnerAttr>(Callee->getFunctionObjectParameterType()))
     return false;
-  if (Sema::isPointerLikeType(Callee->getReturnType())) {
+  if (isPointerLikeType(Callee->getReturnType())) {
     if (!Callee->getIdentifier())
       return false;
     return llvm::StringSwitch<bool>(Callee->getName())
@@ -1446,7 +1442,7 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
     break;
   }
   case LK_LifetimeCapture: {
-    if (Sema::isPointerLikeType(Init->getType()))
+    if (isPointerLikeType(Init->getType()))
       Path.push_back({IndirectLocalPathEntry::GslPointerInit, Init});
     break;
   }
diff --git a/clang/lib/Sema/CheckExprLifetime.h b/clang/lib/Sema/CheckExprLifetime.h
index b10c84363527a7..95c249c6109774 100644
--- a/clang/lib/Sema/CheckExprLifetime.h
+++ b/clang/lib/Sema/CheckExprLifetime.h
@@ -18,6 +18,10 @@
 
 namespace clang::sema {
 
+// Tells whether the type is annotated with [[gsl::Pointer]] or is a pointer
+// type.
+bool isPointerLikeType(QualType QT);
+
 /// Describes an entity that is being assigned.
 struct AssignedEntity {
   // The left-hand side expression of the assignment.
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index f568ed277b0e9e..b0849c74e375ed 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -11,6 +11,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "CheckExprLifetime.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/Attr.h"
 #include "clang/AST/Expr.h"
@@ -286,7 +287,7 @@ void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) {
     if (PVD->hasAttr<LifetimeCaptureByAttr>())
       return;
   for (ParmVarDecl *PVD : MD->parameters()) {
-    if (isPointerLikeType(PVD->getType().getNonReferenceType())) {
+    if (sema::isPointerLikeType(PVD->getType().getNonReferenceType())) {
       int CaptureByThis[] = {LifetimeCaptureByAttr::THIS};
       PVD->addAttr(
           LifetimeCaptureByAttr::CreateImplicit(Context, CaptureByThis, 1));



More information about the cfe-commits mailing list