[clang] 3a03513 - Revert "[clang] Introduce [[clang::lifetime_capture_by(X)]] (#111499)"

Nikita Popov via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 11 11:57:36 PST 2024


Author: Nikita Popov
Date: 2024-11-11T20:57:26+01:00
New Revision: 3a03513fc6ef8f3272d33be19164243c9dbf0452

URL: https://github.com/llvm/llvm-project/commit/3a03513fc6ef8f3272d33be19164243c9dbf0452
DIFF: https://github.com/llvm/llvm-project/commit/3a03513fc6ef8f3272d33be19164243c9dbf0452.diff

LOG: Revert "[clang] Introduce [[clang::lifetime_capture_by(X)]] (#111499)"

This reverts commit 8c4331c1abeb33eabf3cdbefa7f2b6e0540e7f4f.

Causes a large compile-time regression, see:
https://llvm-compile-time-tracker.com/compare.php?from=4a68e4cbd2423dcacada8162ab7c4bb8d7f7e2cf&to=8c4331c1abeb33eabf3cdbefa7f2b6e0540e7f4f&stat=instructions:u

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/Attr.td
    clang/include/clang/Basic/AttrDocs.td
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Sema/Sema.h
    clang/lib/AST/TypePrinter.cpp
    clang/lib/Sema/SemaDecl.cpp
    clang/lib/Sema/SemaDeclAttr.cpp
    clang/lib/Sema/SemaType.cpp

Removed: 
    clang/test/AST/attr-lifetime-capture-by.cpp
    clang/test/SemaCXX/attr-lifetime-capture-by.cpp


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index e817b0ceb3fd06..e235a04f78112b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -449,9 +449,6 @@ Attribute Changes in Clang
 - Fix a bug where clang doesn't automatically apply the ``[[gsl::Owner]]`` or
   ``[[gsl::Pointer]]`` to STL explicit template specialization decls. (#GH109442)
 
-- Clang now supports ``[[clang::lifetime_capture_by(X)]]``. Similar to lifetimebound, this can be
-  used to specify when a reference to a function parameter is captured by another capturing entity ``X``.
-
 Improvements to Clang's diagnostics
 -----------------------------------
 

diff  --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 6a77967c32cbcb..a631e81d40aa68 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -1889,39 +1889,6 @@ def LifetimeBound : DeclOrTypeAttr {
   let SimpleHandler = 1;
 }
 
-def LifetimeCaptureBy : DeclOrTypeAttr {
-  let Spellings = [Clang<"lifetime_capture_by", 0>];
-  let Subjects = SubjectList<[ParmVar, ImplicitObjectParameter], ErrorDiag>;
-  let Args = [VariadicParamOrParamIdxArgument<"Params">];
-  let Documentation = [LifetimeCaptureByDocs];
-  let AdditionalMembers = [{
-private:
-  SmallVector<IdentifierInfo*, 1> ArgIdents;
-  SmallVector<SourceLocation, 1> ArgLocs;
-
-public:
-  static constexpr int THIS = 0;
-  static constexpr int INVALID = -1;
-  static constexpr int UNKNOWN = -2;
-  static constexpr int GLOBAL = -3;
-
-  void setArgs(SmallVector<IdentifierInfo*>&& Idents,
-               SmallVector<SourceLocation>&& Locs) { 
-    assert(Idents.size() == Locs.size());
-    assert(Idents.size() == params_Size);
-    ArgIdents = std::move(Idents);
-    ArgLocs = std::move(Locs);
-  }
-  
-  ArrayRef<IdentifierInfo*> getArgIdents() const { return ArgIdents; }
-  ArrayRef<SourceLocation> getArgLocs() const { return ArgLocs; }
-  void setParamIdx(size_t Idx, int Val) { 
-    assert(Idx < params_Size);
-    params_[Idx] = Val;
-  }
-}];
-}
-
 def TrivialABI : InheritableAttr {
   // This attribute does not have a C [[]] spelling because it requires the
   // CPlusPlus language option.

diff  --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 21fcd183e8969c..b64dbef6332e6a 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -3918,75 +3918,6 @@ have their lifetimes extended.
   }];
 }
 
-def LifetimeCaptureByDocs : Documentation {
-  let Category = DocCatFunction;
-  let Content = [{
-    Similar to `lifetimebound`_, the ``lifetime_capture_by(X)`` attribute on a function
-parameter or implicit object parameter indicates that that objects that are referred to
-by that parameter may also be referred to by the capturing entity ``X``.
-
-By default, a reference is considered to refer to its referenced object, a
-pointer is considered to refer to its pointee, a ``std::initializer_list<T>``
-is considered to refer to its underlying array, and aggregates (arrays and
-simple ``struct``\s) are considered to refer to all objects that their
-transitive subobjects refer to.
-
-The capturing entity ``X`` can be one of the following:
-- Another (named) function parameter. 
-  
-  .. code-block:: c++
-
-    void addToSet(std::string_view a [[clang::lifetime_capture_by(s)]], std::set<std::string_view>& s) {
-      s.insert(a);
-    }
-
-- ``this`` (in case of member functions).
-  
-  .. code-block:: c++
-
-    class S {
-      void addToSet(std::string_view a [[clang::lifetime_capture_by(this)]]) {
-        s.insert(a);
-      }
-      std::set<std::string_view> s;
-    };
-
-- 'global', 'unknown' (without quotes).
-  
-  .. code-block:: c++
-
-    std::set<std::string_view> s;
-    void addToSet(std::string_view a [[clang::lifetime_capture_by(global)]]) {
-      s.insert(a);
-    }
-    void addSomewhere(std::string_view a [[clang::lifetime_capture_by(unknown)]]);
-
-The attribute can be applied to the implicit ``this`` parameter of a member
-function by writing the attribute after the function type:
-
-.. code-block:: c++
-
-  struct S {
-    const char *data(std::set<S*>& s) [[clang::lifetime_capture_by(s)]] {
-      s.insert(this);
-    }
-  };
-
-The attribute supports specifying more than one capturing entities:
-
-.. code-block:: c++
-  
-  void addToSets(std::string_view a [[clang::lifetime_capture_by(s1, s2)]],
-                 std::set<std::string_view>& s1,
-                 std::set<std::string_view>& s2) {
-    s1.insert(a);
-    s2.insert(a);
-  }
-
-.. _`lifetimebound`: https://clang.llvm.org/docs/AttributeReference.html#lifetimebound
-  }];
-}
-
 def TrivialABIDocs : Documentation {
   let Category = DocCatDecl;
   let Content = [{

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f4452fbb57e736..a5d97d7e545ffd 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3383,20 +3383,6 @@ def err_callback_callee_is_variadic : Error<
   "'callback' attribute callee may not be variadic">;
 def err_callback_implicit_this_not_available : Error<
   "'callback' argument at position %0 references unavailable implicit 'this'">;
-
-def err_capture_by_attribute_multiple : Error<
-  "multiple 'lifetime_capture' attributes specified">;
-def err_capture_by_attribute_no_entity : Error<
-  "'lifetime_capture_by' attribute specifies no capturing entity">;
-def err_capture_by_implicit_this_not_available : Error<
-  "'lifetime_capture_by' argument references unavailable implicit 'this'">;
-def err_capture_by_attribute_argument_unknown : Error<
-  "'lifetime_capture_by' attribute argument %0 is not a known function parameter"
-  "; must be a function parameter, 'this', 'global' or 'unknown'">;
-def err_capture_by_references_itself : Error<"'lifetime_capture_by' argument references itself">;
-def err_capture_by_param_uses_reserved_name : Error<
-  "parameter cannot be named '%select{global|unknown}0' while using 'lifetime_capture_by(%select{global|unknown}0)'">;
-
 def err_init_method_bad_return_type : Error<
   "init methods must return an object pointer type, not %0">;
 def err_attribute_invalid_size : Error<

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index d6f3508a5243f3..fad446a05e782f 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1760,14 +1760,6 @@ class Sema final : public SemaBase {
   /// Add [[gsl::Pointer]] attributes for std:: types.
   void inferGslPointerAttribute(TypedefNameDecl *TD);
 
-  LifetimeCaptureByAttr *ParseLifetimeCaptureByAttr(const ParsedAttr &AL,
-                                                    StringRef ParamName);
-  // Processes the argument 'X' in [[clang::lifetime_capture_by(X)]]. Since 'X'
-  // can be the name of a function parameter, we need to parse the function
-  // declaration and rest of the parameters before processesing 'X'. Therefore
-  // do this lazily instead of processing while parsing the annotation itself.
-  void LazyProcessLifetimeCaptureByParams(FunctionDecl *FD);
-
   /// Add _Nullable attributes for std:: types.
   void inferNullableClassAttribute(CXXRecordDecl *CRD);
 

diff  --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index a073a6a4b7d454..6d8db5cf4ffd22 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -25,7 +25,6 @@
 #include "clang/AST/TextNodeDumper.h"
 #include "clang/AST/Type.h"
 #include "clang/Basic/AddressSpaces.h"
-#include "clang/Basic/AttrKinds.h"
 #include "clang/Basic/ExceptionSpecificationType.h"
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/LLVM.h"
@@ -1910,19 +1909,6 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
     OS << " [[clang::lifetimebound]]";
     return;
   }
-  if (T->getAttrKind() == attr::LifetimeCaptureBy) {
-    OS << " [[clang::lifetime_capture_by(";
-    if (auto *attr = dyn_cast_or_null<LifetimeCaptureByAttr>(T->getAttr())) {
-      auto Idents = attr->getArgIdents();
-      for (unsigned I = 0; I < Idents.size(); ++I) {
-        OS << Idents[I]->getName();
-        if (I != Idents.size() - 1)
-          OS << ", ";
-      }
-    }
-    OS << ")]]";
-    return;
-  }
 
   // The printing of the address_space attribute is handled by the qualifier
   // since it is still stored in the qualifier. Return early to prevent printing
@@ -1990,7 +1976,6 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
   case attr::SizedBy:
   case attr::SizedByOrNull:
   case attr::LifetimeBound:
-  case attr::LifetimeCaptureBy:
   case attr::TypeNonNull:
   case attr::TypeNullable:
   case attr::TypeNullableResult:

diff  --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index a3bc8e4191c819..61c29e320d5c73 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -16687,7 +16687,6 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
     }
   }
 
-  LazyProcessLifetimeCaptureByParams(FD);
   inferLifetimeBoundAttribute(FD);
   AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(FD);
 

diff  --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index b4aaa58c082002..d05d326178e1b8 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -14,7 +14,6 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTMutationListener.h"
 #include "clang/AST/CXXInheritance.h"
-#include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
@@ -3868,113 +3867,6 @@ static void handleCallbackAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
       S.Context, AL, EncodingIndices.data(), EncodingIndices.size()));
 }
 
-LifetimeCaptureByAttr *Sema::ParseLifetimeCaptureByAttr(const ParsedAttr &AL,
-                                                        StringRef ParamName) {
-  // Atleast one capture by is required.
-  if (AL.getNumArgs() == 0) {
-    Diag(AL.getLoc(), diag::err_capture_by_attribute_no_entity)
-        << AL.getRange();
-    return nullptr;
-  }
-  SmallVector<IdentifierInfo *, 1> ParamIdents;
-  SmallVector<SourceLocation, 1> ParamLocs;
-  for (unsigned I = 0; I < AL.getNumArgs(); ++I) {
-    if (AL.isArgExpr(I)) {
-      Expr *E = AL.getArgAsExpr(I);
-      Diag(E->getExprLoc(), diag::err_capture_by_attribute_argument_unknown)
-          << E << E->getExprLoc();
-      continue;
-    }
-    assert(AL.isArgIdent(I));
-    IdentifierLoc *IdLoc = AL.getArgAsIdent(I);
-    if (IdLoc->Ident->getName() == ParamName) {
-      Diag(IdLoc->Loc, diag::err_capture_by_references_itself) << IdLoc->Loc;
-      continue;
-    }
-    ParamIdents.push_back(IdLoc->Ident);
-    ParamLocs.push_back(IdLoc->Loc);
-  }
-  SmallVector<int, 1> FakeParamIndices(ParamIdents.size(),
-                                       LifetimeCaptureByAttr::INVALID);
-  LifetimeCaptureByAttr *CapturedBy = ::new (Context) LifetimeCaptureByAttr(
-      Context, AL, FakeParamIndices.data(), FakeParamIndices.size());
-  CapturedBy->setArgs(std::move(ParamIdents), std::move(ParamLocs));
-  return CapturedBy;
-}
-
-static void HandleLifetimeCaptureByAttr(Sema &S, Decl *D,
-                                        const ParsedAttr &AL) {
-  // Do not allow multiple attributes.
-  if (D->hasAttr<LifetimeCaptureByAttr>()) {
-    S.Diag(AL.getLoc(), diag::err_capture_by_attribute_multiple)
-        << AL.getRange();
-    return;
-  }
-  auto *PVD = dyn_cast<ParmVarDecl>(D);
-  assert(PVD);
-  auto *CaptureByAttr = S.ParseLifetimeCaptureByAttr(AL, PVD->getName());
-  if (CaptureByAttr)
-    D->addAttr(CaptureByAttr);
-}
-
-void Sema::LazyProcessLifetimeCaptureByParams(FunctionDecl *FD) {
-  bool HasImplicitThisParam = isInstanceMethod(FD);
-
-  llvm::StringMap<int> NameIdxMapping;
-  NameIdxMapping["global"] = LifetimeCaptureByAttr::GLOBAL;
-  NameIdxMapping["unknown"] = LifetimeCaptureByAttr::UNKNOWN;
-  int Idx = 0;
-  if (HasImplicitThisParam) {
-    NameIdxMapping["this"] = 0;
-    Idx++;
-  }
-  for (const ParmVarDecl *PVD : FD->parameters())
-    NameIdxMapping[PVD->getName()] = Idx++;
-  auto DisallowReservedParams = [&](StringRef Reserved) {
-    for (const ParmVarDecl *PVD : FD->parameters())
-      if (PVD->getName() == Reserved)
-        Diag(PVD->getLocation(), diag::err_capture_by_param_uses_reserved_name)
-            << (PVD->getName() == "unknown");
-  };
-  auto HandleCaptureBy = [&](LifetimeCaptureByAttr *CapturedBy) {
-    if (!CapturedBy)
-      return;
-    const auto &Entities = CapturedBy->getArgIdents();
-    for (size_t I = 0; I < Entities.size(); ++I) {
-      StringRef Name = Entities[I]->getName();
-      auto It = NameIdxMapping.find(Name);
-      if (It == NameIdxMapping.end()) {
-        auto Loc = CapturedBy->getArgLocs()[I];
-        if (!HasImplicitThisParam && Name == "this")
-          Diag(Loc, diag::err_capture_by_implicit_this_not_available) << Loc;
-        else
-          Diag(Loc, diag::err_capture_by_attribute_argument_unknown)
-              << Entities[I] << Loc;
-        continue;
-      }
-      if (Name == "unknown" || Name == "global")
-        DisallowReservedParams(Name);
-      CapturedBy->setParamIdx(I, It->second);
-    }
-  };
-  for (ParmVarDecl *PVD : FD->parameters())
-    HandleCaptureBy(PVD->getAttr<LifetimeCaptureByAttr>());
-  if (!HasImplicitThisParam)
-    return;
-  TypeSourceInfo *TSI = FD->getTypeSourceInfo();
-  if (!TSI)
-    return;
-  AttributedTypeLoc ATL;
-  for (TypeLoc TL = TSI->getTypeLoc();
-       (ATL = TL.getAsAdjusted<AttributedTypeLoc>());
-       TL = ATL.getModifiedLoc()) {
-    auto *A = ATL.getAttrAs<LifetimeCaptureByAttr>();
-    if (!A)
-      continue;
-    HandleCaptureBy(const_cast<LifetimeCaptureByAttr *>(A));
-  }
-}
-
 static bool isFunctionLike(const Type &T) {
   // Check for explicit function types.
   // 'called_once' is only supported in Objective-C and it has
@@ -6752,9 +6644,6 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
   case ParsedAttr::AT_Callback:
     handleCallbackAttr(S, D, AL);
     break;
-  case ParsedAttr::AT_LifetimeCaptureBy:
-    HandleLifetimeCaptureByAttr(S, D, AL);
-    break;
   case ParsedAttr::AT_CalledOnce:
     handleCalledOnceAttr(S, D, AL);
     break;

diff  --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index eb7516b3ef1ece..515b9f689a248a 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -8609,15 +8609,6 @@ static void HandleLifetimeBoundAttr(TypeProcessingState &State,
   }
 }
 
-static void HandleLifetimeCaptureByAttr(TypeProcessingState &State,
-                                        QualType &CurType, ParsedAttr &PA) {
-  if (State.getDeclarator().isDeclarationOfFunction()) {
-    auto *Attr = State.getSema().ParseLifetimeCaptureByAttr(PA, "this");
-    if (Attr)
-      CurType = State.getAttributedType(Attr, CurType, CurType);
-  }
-}
-
 static void HandleHLSLParamModifierAttr(TypeProcessingState &State,
                                         QualType &CurType,
                                         const ParsedAttr &Attr, Sema &S) {
@@ -8779,10 +8770,6 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
       if (TAL == TAL_DeclChunk)
         HandleLifetimeBoundAttr(state, type, attr);
       break;
-    case ParsedAttr::AT_LifetimeCaptureBy:
-      if (TAL == TAL_DeclChunk)
-        HandleLifetimeCaptureByAttr(state, type, attr);
-      break;
 
     case ParsedAttr::AT_NoDeref: {
       // FIXME: `noderef` currently doesn't work correctly in [[]] syntax.

diff  --git a/clang/test/AST/attr-lifetime-capture-by.cpp b/clang/test/AST/attr-lifetime-capture-by.cpp
deleted file mode 100644
index da2eb0cf3d592e..00000000000000
--- a/clang/test/AST/attr-lifetime-capture-by.cpp
+++ /dev/null
@@ -1,9 +0,0 @@
-// RUN: %clang_cc1 %s -ast-dump | FileCheck %s
-
-// Verify that we print the [[clang::lifetime_capture_by(X)]] attribute.
-
-struct S {
-    void foo(int &a, int &b) [[clang::lifetime_capture_by(a, b, global)]];
-};
-
-// CHECK: CXXMethodDecl {{.*}}clang::lifetime_capture_by(a, b, global)

diff  --git a/clang/test/SemaCXX/attr-lifetime-capture-by.cpp b/clang/test/SemaCXX/attr-lifetime-capture-by.cpp
deleted file mode 100644
index 3115dc8d6150c9..00000000000000
--- a/clang/test/SemaCXX/attr-lifetime-capture-by.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-// RUN: %clang_cc1 -std=c++23 -verify %s
-
-struct S {
-  const int *x;
-  void captureInt(const int&x [[clang::lifetime_capture_by(this)]]) { this->x = &x; }
-};
-
-///////////////////////////
-// Test for valid usages.
-///////////////////////////
-[[clang::lifetime_capture_by(unknown)]] // expected-error {{'lifetime_capture_by' attribute only applies to parameters and implicit object parameters}}
-void nonMember(
-    const int &x1 [[clang::lifetime_capture_by(s, t)]],
-    S &s,
-    S &t,
-    const int &x2 [[clang::lifetime_capture_by(12345 + 12)]], // expected-error {{'lifetime_capture_by' attribute argument 12345 + 12 is not a known function parameter; must be a function parameter, 'this', 'global' or 'unknown'}}
-    const int &x3 [[clang::lifetime_capture_by(abcdefgh)]],   // expected-error {{'lifetime_capture_by' attribute argument 'abcdefgh' is not a known function parameter; must be a function parameter, 'this', 'global' or 'unknown'}}
-    const int &x4 [[clang::lifetime_capture_by("abcdefgh")]], // expected-error {{'lifetime_capture_by' attribute argument "abcdefgh" is not a known function parameter; must be a function parameter, 'this', 'global' or 'unknown'}}
-    const int &x5 [[clang::lifetime_capture_by(this)]], // expected-error {{'lifetime_capture_by' argument references unavailable implicit 'this'}}
-    const int &x6 [[clang::lifetime_capture_by()]], // expected-error {{'lifetime_capture_by' attribute specifies no capturing entity}}
-    const int& x7 [[clang::lifetime_capture_by(u, 
-                                               x7)]], // expected-error {{'lifetime_capture_by' argument references itself}}
-    const int &x8 [[clang::lifetime_capture_by(global)]],
-    const int &x9 [[clang::lifetime_capture_by(unknown)]],
-    const S& u
-  )
-{
-  s.captureInt(x1);
-}
-
-void unknown_param_name(const int& unknown, // expected-error {{parameter cannot be named 'unknown' while using 'lifetime_capture_by(unknown)'}}
-                        const int& s [[clang::lifetime_capture_by(unknown)]]);
-void global_param_name(const int& global, // expected-error {{parameter cannot be named 'global' while using 'lifetime_capture_by(global)'}}
-                       const int& s [[clang::lifetime_capture_by(global)]]);
-struct T {
-  void member(
-    const int &x [[clang::lifetime_capture_by(s)]], 
-    S &s,
-    S &t,            
-    const int &y [[clang::lifetime_capture_by(s)]],
-    const int &z [[clang::lifetime_capture_by(this, x, y)]],
-    const int &u [[clang::lifetime_capture_by(global, unknown, x, s)]])
-  {
-    s.captureInt(x);
-  }
-};


        


More information about the cfe-commits mailing list