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

Utkarsh Saxena via cfe-commits cfe-commits at lists.llvm.org
Thu Nov 28 01:13:00 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/3] [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/3] 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/3] 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));



More information about the cfe-commits mailing list