[clang] Revert "[clang][Sema] Deprecate `global`/`unknown` in `lifetime_capture_by`" (PR #208691)
Hans Wennborg via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 10 03:50:58 PDT 2026
https://github.com/zmodem created https://github.com/llvm/llvm-project/pull/208691
Let's revert this until there's a plan in place for how code is supposed to transition to the new spelling.
Reverts llvm/llvm-project#196635
>From 987f8a22ff8e0ae7bd92de335a373e53c2938fdc Mon Sep 17 00:00:00 2001
From: Hans Wennborg <hans at hanshq.net>
Date: Fri, 10 Jul 2026 12:50:05 +0200
Subject: [PATCH] =?UTF-8?q?Revert=20"[clang][Sema]=20Deprecate=20`global`/?=
=?UTF-8?q?`unknown`=20in=20`lifetime=5Fcapture=5Fby`=20(=E2=80=A6"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This reverts commit a627e7e9c3cc9adab27b1e6ebfd70f40dccacf5c.
---
clang/docs/ReleaseNotes.md | 9 --
clang/include/clang/Basic/Attr.td | 12 +--
clang/include/clang/Basic/AttrDocs.td | 34 ++----
.../clang/Basic/DiagnosticSemaKinds.td | 11 +-
clang/lib/Sema/CheckExprLifetime.cpp | 14 ++-
clang/lib/Sema/SemaChecking.cpp | 5 +-
clang/lib/Sema/SemaDeclAttr.cpp | 101 +++---------------
clang/test/Sema/LifetimeSafety/capture-by.cpp | 34 ++----
clang/test/Sema/LifetimeSafety/safety.cpp | 4 +-
.../test/SemaCXX/attr-lifetime-capture-by.cpp | 52 ++-------
10 files changed, 62 insertions(+), 214 deletions(-)
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 449a3792eb4ba..7676699a9b54d 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -554,15 +554,6 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
- The `modular_format` attribute now supports the `fixed` aspect for C
ISO 18037 fixed-point `printf` specifiers.
-- The `lifetime_capture_by` attribute now accepts three new spelling forms:
- `lifetime_capture_by_this`, `lifetime_capture_by_global`, and
- `lifetime_capture_by_unknown`. These replace passing `this`, `global`, and
- `unknown` as arguments to `lifetime_capture_by`; that argument form is now
- deprecated because those names can conflict with user-defined parameters.
- They will be removed in the next release. Distinct `lifetime_capture_by`
- spellings may also be combined on the same declaration, but each spelling may
- appear at most once.
-
- The `const` and `pure` attributes only apply to functions; they are now
diagnosed and ignored when applied to anything else.
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 1a5bd2301dfc8..de3e0f7b563a7 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -2137,19 +2137,9 @@ def LifetimeBound : DeclOrTypeAttr {
}
def LifetimeCaptureBy : DeclOrTypeAttr {
- let Spellings = [Clang<"lifetime_capture_by">,
- Clang<"lifetime_capture_by_this">,
- Clang<"lifetime_capture_by_global">,
- Clang<"lifetime_capture_by_unknown">];
+ let Spellings = [Clang<"lifetime_capture_by", 1>];
let Subjects = SubjectList<[ParmVar, ImplicitObjectParameter], ErrorDiag>;
let Args = [VariadicParamOrParamIdxArgument<"Params">];
- let Accessors = [Accessor<"isThis", [Clang<"lifetime_capture_by_this">]>,
- Accessor<"isGlobal", [Clang<"lifetime_capture_by_global">]>,
- Accessor<"isUnknown", [Clang<"lifetime_capture_by_unknown">]>,
- Accessor<"isStandaloneSpecial",
- [Clang<"lifetime_capture_by_this">,
- Clang<"lifetime_capture_by_global">,
- Clang<"lifetime_capture_by_unknown">]>];
let Documentation = [LifetimeCaptureByDocs];
let AdditionalMembers = [{
private:
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 05e4cb0870652..ba19e61168575 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -4701,13 +4701,10 @@ have their lifetimes extended.
def LifetimeCaptureByDocs : Documentation {
let Category = DocCatFunction;
- let Heading = "lifetime_capture_by, lifetime_capture_by_this, lifetime_capture_by_global, lifetime_capture_by_unknown";
let Content = [{
-Similar to `lifetimebound`_, the ``lifetime_capture_by`` attribute family on a
-function parameter or implicit object parameter indicates that a capturing
-entity may refer to the object referred to by that parameter. The capturing
-entity can be named in ``lifetime_capture_by(X)`` or selected by one of the
-standalone special forms listed below.
+Similar to `lifetimebound`_, the ``lifetime_capture_by(X)`` attribute on a
+function parameter or implicit object parameter indicates that the capturing
+entity ``X`` may refer to the object referred by that parameter.
Below is a list of types of the parameters and what they're considered to refer to:
@@ -4739,7 +4736,7 @@ temporary object.
addToSet(local, s); // Ok.
}
-The capturing entity can be one of the following:
+The capturing entity ``X`` can be one of the following:
- Another (named) function parameter.
@@ -4749,30 +4746,28 @@ The capturing entity can be one of the following:
s.insert(a);
}
-- ``this`` (in case of member functions), written as
- ``lifetime_capture_by_this``.
+- ``this`` (in case of member functions).
.. code-block:: c++
class S {
- void addToSet(std::string_view a [[clang::lifetime_capture_by_this]]) {
+ void addToSet(std::string_view a [[clang::lifetime_capture_by(this)]]) {
s.insert(a);
}
std::set<std::string_view> s;
};
- Note: When applied to a constructor parameter, `[[clang::lifetime_capture_by_this]]` is just an alias of `[[clang::lifetimebound]]`.
+ Note: When applied to a constructor parameter, `[[clang::lifetime_capture_by(this)]]` is just an alias of `[[clang::lifetimebound]]`.
-- ``global`` and ``unknown``, written as ``lifetime_capture_by_global`` and
- ``lifetime_capture_by_unknown`` respectively.
+- `global`, `unknown`.
.. code-block:: c++
std::set<std::string_view> s;
- void addToSet(std::string_view a [[clang::lifetime_capture_by_global]]) {
+ 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]]);
+ 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:
@@ -4785,7 +4780,7 @@ function by writing the attribute after the function type:
}
};
-The parameter-list form supports specifying more than one capturing entity:
+The attribute supports specifying more than one capturing entities:
.. code-block:: c++
@@ -4796,13 +4791,6 @@ The parameter-list form supports specifying more than one capturing entity:
s2.insert(a);
}
-Distinct ``lifetime_capture_by`` forms can also be combined on the same
-declaration, but each form can appear at most once. For example,
-``[[clang::lifetime_capture_by(s), clang::lifetime_capture_by_this]]`` is
-allowed, but two ``[[clang::lifetime_capture_by(...)]]`` attributes or two
-``[[clang::lifetime_capture_by_this]]`` attributes on the same declaration are
-rejected.
-
Limitation: The capturing entity ``X`` is not used by the analysis and is
used for documentation purposes only. This is because the analysis is
statement-local and only detects use of a temporary as an argument to the
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 09951730e1570..e57f3e0e14168 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3566,23 +3566,18 @@ def err_callback_callee_is_variadic : Error<
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_this_attr_without_implicit_this : Error<
- "'lifetime_capture_by_this' attribute requires an implicit object parameter">;
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 '%0' while using 'lifetime_capture_by(%0)'">;
-def err_capture_by_attribute_multiple : Error<
- "multiple '%0' attributes specified">;
-def warn_deprecated_capture_by_special_entity : Warning<
- "'lifetime_capture_by(%0)' is deprecated; use '%1' instead">,
- InGroup<DeprecatedAttributes>;
+ "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">;
diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp
index fafee76ec18c3..d15b2c6518cec 100644
--- a/clang/lib/Sema/CheckExprLifetime.cpp
+++ b/clang/lib/Sema/CheckExprLifetime.cpp
@@ -502,14 +502,12 @@ static void visitFunctionCallArguments(IndirectLocalPath &Path, Expr *Call,
if (CheckCoroCall ||
CanonCallee->getParamDecl(I)->hasAttr<LifetimeBoundAttr>())
VisitLifetimeBoundArg(CanonCallee->getParamDecl(I), Arg);
- else if (isa<CXXConstructorDecl>(CanonCallee) &&
- llvm::any_of(CanonCallee->getParamDecl(I)
- ->specific_attrs<LifetimeCaptureByAttr>(),
- [](const LifetimeCaptureByAttr *CaptureAttr) {
- return llvm::is_contained(
- CaptureAttr->params(),
- LifetimeCaptureByAttr::This);
- }))
+ else if (const auto *CaptureAttr =
+ CanonCallee->getParamDecl(I)->getAttr<LifetimeCaptureByAttr>();
+ CaptureAttr && isa<CXXConstructorDecl>(CanonCallee) &&
+ llvm::any_of(CaptureAttr->params(), [](int ArgIdx) {
+ return ArgIdx == LifetimeCaptureByAttr::This;
+ }))
// `lifetime_capture_by(this)` in a class constructor has the same
// semantics as `lifetimebound`:
//
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 2a8395e26d0bd..79fec78f88c69 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -4405,9 +4405,8 @@ void Sema::checkLifetimeCaptureBy(FunctionDecl *FD, bool IsMemberFunction,
}
};
for (unsigned I = 0; I < FD->getNumParams(); ++I)
- for (const auto *A :
- FD->getParamDecl(I)->specific_attrs<LifetimeCaptureByAttr>())
- HandleCaptureByAttr(A, I + IsMemberFunction);
+ HandleCaptureByAttr(FD->getParamDecl(I)->getAttr<LifetimeCaptureByAttr>(),
+ I + IsMemberFunction);
// Check when the implicit object param is captured.
if (IsMemberFunction) {
TypeSourceInfo *TSI = FD->getTypeSourceInfo();
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 1b272b5416860..1300635921d5e 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -4411,41 +4411,17 @@ static void handleCallbackAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
LifetimeCaptureByAttr *Sema::ParseLifetimeCaptureByAttr(const ParsedAttr &AL,
StringRef ParamName) {
- StringRef AttrName = AL.getAttrName()->getName();
- StringRef SpecialEntity;
- if (AttrName == "lifetime_capture_by_this")
- SpecialEntity = "this";
- else if (AttrName == "lifetime_capture_by_global")
- SpecialEntity = "global";
- else if (AttrName == "lifetime_capture_by_unknown")
- SpecialEntity = "unknown";
-
- if (!SpecialEntity.empty() && AL.getNumArgs() != 0) {
- Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 0;
- return nullptr;
- }
-
// Atleast one capture by is required.
- if (SpecialEntity.empty() && AL.getNumArgs() == 0) {
+ if (AL.getNumArgs() == 0) {
Diag(AL.getLoc(), diag::err_capture_by_attribute_no_entity)
<< AL.getRange();
return nullptr;
}
- unsigned N = SpecialEntity.empty() ? AL.getNumArgs() : 1;
+ unsigned N = AL.getNumArgs();
auto ParamIdents =
MutableArrayRef<IdentifierInfo *>(new (Context) IdentifierInfo *[N], N);
auto ParamLocs =
MutableArrayRef<SourceLocation>(new (Context) SourceLocation[N], N);
- if (!SpecialEntity.empty()) {
- ParamIdents[0] = &Context.Idents.get(SpecialEntity);
- ParamLocs[0] = AL.getRange().getEnd();
- int FakeParamIndices[] = {LifetimeCaptureByAttr::Invalid};
- auto *CapturedBy =
- LifetimeCaptureByAttr::Create(Context, FakeParamIndices, 1, AL);
- CapturedBy->setArgs(ParamIdents, ParamLocs);
- return CapturedBy;
- }
-
bool IsValid = true;
for (unsigned I = 0; I < N; ++I) {
if (AL.isArgExpr(I)) {
@@ -4457,17 +4433,6 @@ LifetimeCaptureByAttr *Sema::ParseLifetimeCaptureByAttr(const ParsedAttr &AL,
}
assert(AL.isArgIdent(I));
IdentifierLoc *IdLoc = AL.getArgAsIdent(I);
- StringRef Name = IdLoc->getIdentifierInfo()->getName();
- StringRef Replacement;
- if (Name == "this")
- Replacement = "lifetime_capture_by_this";
- else if (Name == "global")
- Replacement = "lifetime_capture_by_global";
- else if (Name == "unknown")
- Replacement = "lifetime_capture_by_unknown";
- if (!Replacement.empty())
- Diag(IdLoc->getLoc(), diag::warn_deprecated_capture_by_special_entity)
- << Name << Replacement << IdLoc->getLoc();
if (IdLoc->getIdentifierInfo()->getName() == ParamName) {
Diag(IdLoc->getLoc(), diag::err_capture_by_references_itself)
<< IdLoc->getLoc();
@@ -4488,53 +4453,24 @@ LifetimeCaptureByAttr *Sema::ParseLifetimeCaptureByAttr(const ParsedAttr &AL,
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)
- return;
-
- enum class SpellingKind { ParameterList, This, Global, Unknown };
- auto GetSpellingKind = [](const LifetimeCaptureByAttr *A) {
- if (A->isThis())
- return SpellingKind::This;
- if (A->isGlobal())
- return SpellingKind::Global;
- if (A->isUnknown())
- return SpellingKind::Unknown;
- return SpellingKind::ParameterList;
- };
- auto GetSpellingName = [](SpellingKind Kind) -> StringRef {
- switch (Kind) {
- case SpellingKind::ParameterList:
- return "lifetime_capture_by";
- case SpellingKind::This:
- return "lifetime_capture_by_this";
- case SpellingKind::Global:
- return "lifetime_capture_by_global";
- case SpellingKind::Unknown:
- return "lifetime_capture_by_unknown";
- }
- llvm_unreachable("unknown lifetime_capture_by spelling kind");
- };
-
- SpellingKind NewKind = GetSpellingKind(CaptureByAttr);
- for (const auto *Existing : D->specific_attrs<LifetimeCaptureByAttr>()) {
- if (GetSpellingKind(Existing) == NewKind) {
- S.Diag(AL.getLoc(), diag::err_capture_by_attribute_multiple)
- << GetSpellingName(NewKind) << AL.getRange();
- return;
- }
- }
-
- D->addAttr(CaptureByAttr);
+ if (CaptureByAttr)
+ D->addAttr(CaptureByAttr);
}
void Sema::LazyProcessLifetimeCaptureByParams(FunctionDecl *FD) {
bool HasImplicitThisParam = hasImplicitObjectParameter(FD);
SmallVector<LifetimeCaptureByAttr *, 1> Attrs;
for (ParmVarDecl *PVD : FD->parameters())
- for (auto *A : PVD->specific_attrs<LifetimeCaptureByAttr>())
+ if (auto *A = PVD->getAttr<LifetimeCaptureByAttr>())
Attrs.push_back(A);
if (HasImplicitThisParam) {
TypeSourceInfo *TSI = FD->getTypeSourceInfo();
@@ -4564,7 +4500,7 @@ void Sema::LazyProcessLifetimeCaptureByParams(FunctionDecl *FD) {
for (const ParmVarDecl *PVD : FD->parameters())
if (PVD->getName() == Reserved)
Diag(PVD->getLocation(), diag::err_capture_by_param_uses_reserved_name)
- << PVD->getName();
+ << (PVD->getName() == "unknown");
};
for (auto *CapturedBy : Attrs) {
const auto &Entities = CapturedBy->getArgIdents();
@@ -4573,19 +4509,14 @@ void Sema::LazyProcessLifetimeCaptureByParams(FunctionDecl *FD) {
auto It = NameIdxMapping.find(Name);
if (It == NameIdxMapping.end()) {
auto Loc = CapturedBy->getArgLocs()[I];
- if (!HasImplicitThisParam && Name == "this") {
- unsigned DiagID =
- CapturedBy->isStandaloneSpecial()
- ? diag::err_capture_by_this_attr_without_implicit_this
- : diag::err_capture_by_implicit_this_not_available;
- Diag(Loc, DiagID) << Loc;
- } else
+ 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") &&
- !CapturedBy->isStandaloneSpecial())
+ if (Name == "unknown" || Name == "global")
DisallowReservedParams(Name);
CapturedBy->setParamIdx(I, It->second);
}
diff --git a/clang/test/Sema/LifetimeSafety/capture-by.cpp b/clang/test/Sema/LifetimeSafety/capture-by.cpp
index e81669fe30782..2877d8d6cd5f9 100644
--- a/clang/test/Sema/LifetimeSafety/capture-by.cpp
+++ b/clang/test/Sema/LifetimeSafety/capture-by.cpp
@@ -85,18 +85,6 @@ void use() {
}
} // namespace capture_string_view
-namespace multiple_capture_by_attrs {
-struct X {} x1;
-void capture(std::string_view s [[clang::lifetime_capture_by(x1),
- clang::lifetime_capture_by_global]],
- X &x1);
-
-void use() {
- capture(std::string(), // expected-warning {{object whose reference is captured by 'x1' will be destroyed at the end of the full-expression}} expected-warning {{object whose reference is captured will be destroyed at the end of the full-expression}}
- x1);
-}
-} // namespace multiple_capture_by_attrs
-
// ****************************************************************************
// Capture pointer (eg: std::string*)
// ****************************************************************************
@@ -157,7 +145,7 @@ void use() {
namespace temporary_capturing_object {
struct S {
- void add(const int& x [[clang::lifetime_capture_by_this]]);
+ void add(const int& x [[clang::lifetime_capture_by(this)]]);
};
void test() {
@@ -173,8 +161,8 @@ void test() {
// Capture by Global and Unknown.
// ****************************************************************************
namespace capture_by_global_unknown {
-void captureByGlobal(std::string_view s [[clang::lifetime_capture_by_global]]);
-void captureByUnknown(std::string_view s [[clang::lifetime_capture_by_unknown]]);
+void captureByGlobal(std::string_view s [[clang::lifetime_capture_by(global)]]);
+void captureByUnknown(std::string_view s [[clang::lifetime_capture_by(unknown)]]);
std::string_view getLifetimeBoundView(const std::string& s [[clang::lifetimebound]]);
@@ -200,8 +188,8 @@ void use() {
// ****************************************************************************
namespace capture_by_this {
struct S {
- void captureInt(const int& x [[clang::lifetime_capture_by_this]]);
- void captureView(std::string_view sv [[clang::lifetime_capture_by_this]]);
+ void captureInt(const int& x [[clang::lifetime_capture_by(this)]]);
+ void captureView(std::string_view sv [[clang::lifetime_capture_by(this)]]);
};
std::string_view getLifetimeBoundView(const std::string& s [[clang::lifetimebound]]);
std::string_view getNotLifetimeBoundView(const std::string& s);
@@ -260,8 +248,8 @@ void useCaptureDefaultArg() {
namespace containers_no_distinction {
template<class T>
struct MySet {
- void insert(T&& t [[clang::lifetime_capture_by_this]]);
- void insert(const T& t [[clang::lifetime_capture_by_this]]);
+ void insert(T&& t [[clang::lifetime_capture_by(this)]]);
+ void insert(const T& t [[clang::lifetime_capture_by(this)]]);
};
void user_defined_containers() {
MySet<int> set_of_int;
@@ -281,8 +269,8 @@ template<> struct IsPointerLikeTypeImpl<std::string_view> : std::true_type {};
template<typename T> concept IsPointerLikeType = std::is_pointer<T>::value || IsPointerLikeTypeImpl<T>::value;
template<class T> struct MyVector {
- void push_back(T&& t [[clang::lifetime_capture_by_this]]) requires IsPointerLikeType<T>;
- void push_back(const T& t [[clang::lifetime_capture_by_this]]) requires IsPointerLikeType<T>;
+ void push_back(T&& t [[clang::lifetime_capture_by(this)]]) requires IsPointerLikeType<T>;
+ void push_back(const T& t [[clang::lifetime_capture_by(this)]]) requires IsPointerLikeType<T>;
void push_back(T&& t) requires (!IsPointerLikeType<T>);
void push_back(const T& t) requires (!IsPointerLikeType<T>);
@@ -440,13 +428,13 @@ void use() {
namespace on_constructor {
struct T {
- T(const int& t [[clang::lifetime_capture_by_this]]);
+ T(const int& t [[clang::lifetime_capture_by(this)]]);
};
struct T2 {
T2(const int& t [[clang::lifetime_capture_by(x)]], int& x);
};
struct T3 {
- T3(const T& t [[clang::lifetime_capture_by_this]]);
+ T3(const T& t [[clang::lifetime_capture_by(this)]]);
};
int foo(const T& t);
diff --git a/clang/test/Sema/LifetimeSafety/safety.cpp b/clang/test/Sema/LifetimeSafety/safety.cpp
index 0776fcdf05773..3c9b58c4e4957 100644
--- a/clang/test/Sema/LifetimeSafety/safety.cpp
+++ b/clang/test/Sema/LifetimeSafety/safety.cpp
@@ -3978,7 +3978,7 @@ void test_reference_to_pointer() {
struct [[gsl::Pointer]] MyContainer {
View stored;
- void set(View s [[clang::lifetime_capture_by_this]]);
+ void set(View s [[clang::lifetime_capture_by(this)]]);
};
void member_capture() {
@@ -3993,7 +3993,7 @@ void member_capture() {
// FIXME: Add support for simple containers without annotations.
struct SimpleContainer {
View stored;
- void set(View s [[clang::lifetime_capture_by_this]]);
+ void set(View s [[clang::lifetime_capture_by(this)]]);
};
void member_capture_simple_container() {
diff --git a/clang/test/SemaCXX/attr-lifetime-capture-by.cpp b/clang/test/SemaCXX/attr-lifetime-capture-by.cpp
index 0848cf98c160b..6b3726a88c8b5 100644
--- a/clang/test/SemaCXX/attr-lifetime-capture-by.cpp
+++ b/clang/test/SemaCXX/attr-lifetime-capture-by.cpp
@@ -2,7 +2,7 @@
struct S {
const int *x;
- void captureInt(const int&x [[clang::lifetime_capture_by_this]]) { this->x = &x; }
+ void captureInt(const int&x [[clang::lifetime_capture_by(this)]]) { this->x = &x; }
};
///////////////////////////
@@ -16,14 +16,12 @@ void nonMember(
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_this' attribute requires an implicit object parameter}}
+ 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)]], // expected-warning {{'lifetime_capture_by(global)' is deprecated; use 'lifetime_capture_by_global' instead}}
- const int &x9 [[clang::lifetime_capture_by(unknown)]], // expected-warning {{'lifetime_capture_by(unknown)' is deprecated; use 'lifetime_capture_by_unknown' instead}}
- const int &x10 [[clang::lifetime_capture_by_global(s)]], // expected-error {{'clang::lifetime_capture_by_global' attribute takes no arguments}}
- const int &x11 [[clang::lifetime_capture_by(this)]], // expected-error {{'lifetime_capture_by' argument references unavailable implicit 'this'}} // expected-warning {{'lifetime_capture_by(this)' is deprecated; use 'lifetime_capture_by_this' instead}}
+ 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 int &test_memory_leak[[clang::lifetime_capture_by(x1,x2, x3, x4, x5, x6, x7, x8, x9)]],
const S& u
)
@@ -32,9 +30,9 @@ void nonMember(
}
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)]]); // expected-warning {{'lifetime_capture_by(unknown)' is deprecated; use 'lifetime_capture_by_unknown' instead}}
+ 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)]]); // expected-warning {{'lifetime_capture_by(global)' is deprecated; use 'lifetime_capture_by_global' instead}}
+ const int& s [[clang::lifetime_capture_by(global)]]);
void no_such_param(int i [[clang::lifetime_capture_by(no_such_param)]]); // expected-error {{'lifetime_capture_by' attribute argument 'no_such_param' is not a known function parameter; must be a function parameter, 'this', 'global' or 'unknown'}}
void use_no_such_param() { no_such_param(0); }
struct T {
@@ -43,42 +41,12 @@ struct T {
S &s,
S &t,
const int &y [[clang::lifetime_capture_by(s)]],
- const int &z [[clang::lifetime_capture_by(x, y), clang::lifetime_capture_by_this]],
- const int &u [[clang::lifetime_capture_by(global, unknown, x, s)]]) // expected-warning 2 {{deprecated}}
+ const int &z [[clang::lifetime_capture_by(this, x, y)]],
+ const int &u [[clang::lifetime_capture_by(global, unknown, x, s)]])
{
s.captureInt(x);
}
void explicit_this1(this T& self, const int &x [[clang::lifetime_capture_by(self)]]);
- void explicit_this2(this T& self, const int &x [[clang::lifetime_capture_by(this)]]); // expected-warning {{'lifetime_capture_by(this)' is deprecated; use 'lifetime_capture_by_this' instead}} expected-error {{argument references unavailable implicit 'this'}}
-};
-
-void duplicate_parameter_list(
- const int &x [[clang::lifetime_capture_by(s),
- clang::lifetime_capture_by(t)]], // expected-error {{multiple 'lifetime_capture_by' attributes specified}}
- S &s, S &t);
-
-void duplicate_global(
- const int &x [[clang::lifetime_capture_by_global,
- clang::lifetime_capture_by_global]]); // expected-error {{multiple 'lifetime_capture_by_global' attributes specified}}
-
-void duplicate_unknown(
- const int &x [[clang::lifetime_capture_by_unknown,
- clang::lifetime_capture_by_unknown]]); // expected-error {{multiple 'lifetime_capture_by_unknown' attributes specified}}
-
-struct U {
- void duplicate_this(
- const int &x [[clang::lifetime_capture_by_this,
- clang::lifetime_capture_by_this]]); // expected-error {{multiple 'lifetime_capture_by_this' attributes specified}}
-
- void different_spellings(
- const int &x [[clang::lifetime_capture_by(s),
- clang::lifetime_capture_by_this,
- clang::lifetime_capture_by_global,
- clang::lifetime_capture_by_unknown]],
- S &s);
-
- void deprecated_this_spelling_is_distinct(
- const int &x [[clang::lifetime_capture_by(this), // expected-warning {{'lifetime_capture_by(this)' is deprecated; use 'lifetime_capture_by_this' instead}}
- clang::lifetime_capture_by_this]]);
+ void explicit_this2(this T& self, const int &x [[clang::lifetime_capture_by(this)]]); // expected-error {{argument references unavailable implicit 'this'}}
};
More information about the cfe-commits
mailing list