[clang] [LifetimeSafety] Warn on inapplicable `[[clang::lifetimebound]]` when return type can not carry a lifetime (PR #203767)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Jun 28 02:38:42 PDT 2026
https://github.com/NeKon69 updated https://github.com/llvm/llvm-project/pull/203767
>From a5b932706518c1513894400307801e359ac619fe Mon Sep 17 00:00:00 2001
From: NeKon69 <nobodqwe at gmail.com>
Date: Sun, 14 Jun 2026 16:11:12 +0300
Subject: [PATCH 1/2] [LifetimeSafety] Warn on inapplicable
[[clang::lifetimebound]] when return type can not carry a lifetime
---
.../Analyses/LifetimeSafety/LifetimeSafety.h | 5 +++-
.../clang/Basic/DiagnosticSemaKinds.td | 5 ++++
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 23 +++++++++++++---
clang/lib/Sema/SemaLifetimeSafety.h | 17 +++++++++---
.../LifetimeSafety/annotation-suggestions.cpp | 6 ++---
.../inapplicable-lifetimebound.cpp | 27 ++++++++++++++++++-
.../misplaced-lifetimebound-intra-tu.cpp | 2 +-
clang/test/Sema/LifetimeSafety/safety.cpp | 8 +++---
8 files changed, 76 insertions(+), 17 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 28886b826f72f..ce35a14641a15 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -142,7 +142,10 @@ class LifetimeSafetySemaHelper {
const ParmVarDecl *PVDDef,
const ParmVarDecl *PVDDecl) {}
- virtual void reportInapplicableLifetimebound(const ParmVarDecl *PVD) {}
+ virtual void reportInapplicableLifetimebound(const ParmVarDecl *PVD,
+ QualType Type,
+ bool IsReturnType) {}
+ virtual void reportInapplicableLifetimebound(const CXXMethodDecl *MD) {}
// Suggests lifetime bound annotations for implicit this.
virtual void suggestLifetimeboundToImplicitThis(WarningScope Scope,
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 8097800e6744a..30ab502c32000 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11048,6 +11048,11 @@ def warn_lifetime_safety_inapplicable_lifetimebound
InGroup<LifetimeSafetyInapplicableLifetimebound>,
DefaultIgnore;
+def warn_lifetime_safety_inapplicable_lifetimebound_return
+ : Warning<"'lifetimebound' attribute has no effect on this function because return type %0 cannot carry a lifetime. The attribute only applies when the return type is a reference type, pointer type, or non-owner record type">,
+ InGroup<LifetimeSafetyInapplicableLifetimebound>,
+ DefaultIgnore;
+
def note_lifetime_safety_used_here : Note<"later used here">;
def note_lifetime_safety_invalidated_here : Note<"invalidated here">;
def note_lifetime_safety_destroyed_here : Note<"destroyed here">;
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index d41d6f43f837b..41945607cf531 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -484,11 +484,26 @@ class LifetimeChecker {
FDef->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
return;
+ QualType ReturnType = FDef->getReturnType();
+ if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(FDef))
+ ReturnType = AST.getTypeDeclType(cast<TypeDecl>(Ctor->getParent()));
+
+ bool ReturnTypeHasOrigins =
+ FactMgr.getOriginMgr().hasOrigins(ReturnType,
+ /*IntrinsicOnly=*/true);
+ if (getImplicitObjectParamLifetimeBoundAttr(FDef) && !ReturnTypeHasOrigins)
+ SemaHelper->reportInapplicableLifetimebound(cast<CXXMethodDecl>(FDef));
+
for (const auto &PVD : FDef->parameters())
- if (PVD->hasAttr<LifetimeBoundAttr>() &&
- !FactMgr.getOriginMgr().hasOrigins(PVD->getType(),
- /*IntrinsicOnly=*/true))
- SemaHelper->reportInapplicableLifetimebound(PVD);
+ if (PVD->hasAttr<LifetimeBoundAttr>()) {
+ if (!FactMgr.getOriginMgr().hasOrigins(PVD->getType(),
+ /*IntrinsicOnly=*/true))
+ SemaHelper->reportInapplicableLifetimebound(PVD, PVD->getType(),
+ /*IsReturnType=*/false);
+ if (!ReturnTypeHasOrigins)
+ SemaHelper->reportInapplicableLifetimebound(PVD, ReturnType,
+ /*IsReturnType=*/true);
+ }
}
void inferAnnotations() {
diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h
index 91f1290f38723..20312d1787c87 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -353,13 +353,24 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
<< Attr->getRange();
}
- void reportInapplicableLifetimebound(const ParmVarDecl *PVD) override {
+ void reportInapplicableLifetimebound(const ParmVarDecl *PVD, QualType Type,
+ bool IsReturnType) override {
assert(PVD->hasAttr<LifetimeBoundAttr>() &&
"Expected parameter to have lifetimebound attribute");
const auto *Attr = PVD->getAttr<LifetimeBoundAttr>();
+ unsigned DiagID =
+ IsReturnType
+ ? diag::warn_lifetime_safety_inapplicable_lifetimebound_return
+ : diag::warn_lifetime_safety_inapplicable_lifetimebound;
+ S.Diag(Attr->getLocation(), DiagID) << Type << Attr->getRange();
+ }
+
+ void reportInapplicableLifetimebound(const CXXMethodDecl *MD) override {
+ const auto *Attr = getImplicitObjectParamLifetimeBoundAttr(MD);
+ assert(Attr && "Expected lifetimebound attribute");
S.Diag(Attr->getLocation(),
- diag::warn_lifetime_safety_inapplicable_lifetimebound)
- << PVD->getType() << Attr->getRange();
+ diag::warn_lifetime_safety_inapplicable_lifetimebound_return)
+ << MD->getReturnType() << Attr->getRange();
}
void suggestLifetimeboundToImplicitThis(WarningScope Scope,
diff --git a/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp b/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp
index cef3397b57a6f..754533b065836 100644
--- a/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp
+++ b/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp
@@ -1,7 +1,7 @@
// RUN: rm -rf %t
// RUN: split-file %s %t
// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wlifetime-safety -Wlifetime-safety-annotation-placement -Wno-dangling -I%t -I%S -verify %t/test_source.cpp
-// RUN: %clang_cc1 -fsyntax-only -std=c++23 -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wlifetime-safety -Wno-dangling -I%t -I%S -verify %t/test_source.cpp
+// RUN: %clang_cc1 -fsyntax-only -std=c++23 -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wlifetime-safety -Wlifetime-safety-annotation-placement -Wno-dangling -I%t -I%S -verify %t/test_source.cpp
// RUN: %clang_cc1 -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wlifetime-safety -Wno-dangling -I%t -I%S -fixit %t/test_source.cpp
// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wno-dangling -I%t -I%S -Werror=lifetime-safety-suggestions %t/test_source.cpp
@@ -615,7 +615,7 @@ namespace make_unique_suggestion {
struct LifetimeBoundCtor {
View v;
// FIXME: This test fails to propagate the lifetimebound in ctor if this is inferred (instead of the current explicit annotation).
- LifetimeBoundCtor(const MyObj& obj [[clang::lifetimebound]]): v(obj) {}
+ LifetimeBoundCtor(const MyObj& obj [[clang::lifetimebound]]): v(obj) {} // expected-warning {{'lifetimebound' attribute has no effect on this function because return type 'make_unique_suggestion::LifetimeBoundCtor' cannot carry a lifetime}}
};
std::unique_ptr<LifetimeBoundCtor> create_target(const MyObj& obj) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
@@ -649,7 +649,7 @@ void test_new_allocation() {
struct LifetimeBoundCtor {
View v;
LifetimeBoundCtor();
- LifetimeBoundCtor(const MyObj& obj [[clang::lifetimebound]]) : v(obj) {}
+ LifetimeBoundCtor(const MyObj& obj [[clang::lifetimebound]]) : v(obj) {} // expected-warning {{'lifetimebound' attribute has no effect on this function because return type 'new_allocation_suggestion::LifetimeBoundCtor' cannot carry a lifetime}}
};
struct HasCtorField {
diff --git a/clang/test/Sema/LifetimeSafety/inapplicable-lifetimebound.cpp b/clang/test/Sema/LifetimeSafety/inapplicable-lifetimebound.cpp
index 624a8e9bb00cc..0e8f3196df972 100644
--- a/clang/test/Sema/LifetimeSafety/inapplicable-lifetimebound.cpp
+++ b/clang/test/Sema/LifetimeSafety/inapplicable-lifetimebound.cpp
@@ -9,7 +9,14 @@ struct [[gsl::Pointer()]] View {
View(const Owner &o [[clang::lifetimebound]]);
};
-struct Plain {};
+struct Plain {
+ Plain() {}
+ Plain(const Plain &other [[clang::lifetimebound]]) {} // expected-warning {{'lifetimebound' attribute has no effect on this function because return type 'Plain' cannot carry a lifetime}}
+ Plain operator+(const Plain &other [[clang::lifetimebound]]) const { return {}; } // expected-warning {{'lifetimebound' attribute has no effect on this function because return type 'Plain' cannot carry a lifetime}}
+ Plain &operator=(const Plain &other [[clang::lifetimebound]]) { return *this; }
+ operator int() const [[clang::lifetimebound]] { return 0; } // expected-warning {{'lifetimebound' attribute has no effect on this function because return type 'int' cannot carry a lifetime}}
+ Plain(const Owner &o [[clang::lifetimebound]]) {} // expected-warning {{'lifetimebound' attribute has no effect on this function because return type 'Plain' cannot carry a lifetime}}
+};
enum Enum { Enumerator };
@@ -90,3 +97,21 @@ int *context_sensitive_origin_type(
lifetime_annotated_return(i);
return v[0];
}
+
+int getInt(const Owner &o [[clang::lifetimebound]]) { return 0; } // expected-warning {{'lifetimebound' attribute has no effect on this function because return type 'int' cannot carry a lifetime}}
+Owner getOwner(const Owner &o [[clang::lifetimebound]]) { return o; } // expected-warning {{'lifetimebound' attribute has no effect on this function because return type 'Owner' cannot carry a lifetime}}
+Plain getPlain(const Owner &o [[clang::lifetimebound]]) { return {}; } // expected-warning {{'lifetimebound' attribute has no effect on this function because return type 'Plain' cannot carry a lifetime}}
+
+View getView(const Owner &o [[clang::lifetimebound]]) { return View(); }
+Owner *getOwnerPtr(Owner &o [[clang::lifetimebound]]) { return &o; }
+
+auto getAuto(const Owner &o [[clang::lifetimebound]]) { return 0; } // expected-warning {{'lifetimebound' attribute has no effect on this function because return type 'int' cannot carry a lifetime}}
+
+int getIntMultiParam(const Owner &o [[clang::lifetimebound]], int i [[clang::lifetimebound]]) { return 0; } // expected-warning 2 {{'lifetimebound' attribute has no effect on this function because return type 'int' cannot carry a lifetime}} \
+ // expected-warning {{'lifetimebound' attribute has no effect on parameter of type 'int'}}
+
+void test_lambda() {
+ auto lambda = [](const Owner &o [[clang::lifetimebound]]) -> int { return 0; }; // expected-warning {{'lifetimebound' attribute has no effect on this function because return type 'int' cannot carry a lifetime}}
+ (void)lambda;
+}
+
diff --git a/clang/test/Sema/LifetimeSafety/misplaced-lifetimebound-intra-tu.cpp b/clang/test/Sema/LifetimeSafety/misplaced-lifetimebound-intra-tu.cpp
index 7fa4cae100509..b1cfb490446e0 100644
--- a/clang/test/Sema/LifetimeSafety/misplaced-lifetimebound-intra-tu.cpp
+++ b/clang/test/Sema/LifetimeSafety/misplaced-lifetimebound-intra-tu.cpp
@@ -119,7 +119,7 @@ IntraSuppressedObj &intra_suppressed(
return obj;
}
-struct View {
+struct [[gsl::Pointer()]] View {
friend View friend_redecl(MyObj & // expected-warning {{'lifetimebound' attribute on this definition is not visible to callers before the definition; add it to the declaration instead}}
obj // CHECK: fix-it:"{{.*}}":{[[@LINE]]:{{[0-9]+}}-[[@LINE]]:{{[0-9]+}}}:" {{\[\[clang::lifetimebound\]\]}}"
);
diff --git a/clang/test/Sema/LifetimeSafety/safety.cpp b/clang/test/Sema/LifetimeSafety/safety.cpp
index c838918eb556d..687aa4c962b6c 100644
--- a/clang/test/Sema/LifetimeSafety/safety.cpp
+++ b/clang/test/Sema/LifetimeSafety/safety.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wlifetime-safety-annotation-placement -Wno-dangling -verify=expected,function %s
// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety -Wno-dangling -verify=expected,tu %s
-// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wno-dangling -fcxx-exceptions -verify=expected,function %s
+// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wlifetime-safety-annotation-placement -Wno-dangling -fcxx-exceptions -verify=expected,function %s
#include "Inputs/lifetime-analysis.h"
@@ -2533,7 +2533,7 @@ S S::return_self_after_registration() const {
struct SWithUserDefinedCopyLikeOps {
SWithUserDefinedCopyLikeOps();
- SWithUserDefinedCopyLikeOps(const std::string &s [[clang::lifetimebound]]) : owned(s), data(s) {}
+ SWithUserDefinedCopyLikeOps(const std::string &s [[clang::lifetimebound]]) : owned(s), data(s) {} // function-warning {{'lifetimebound' attribute has no effect on this function because return type 'track_origins_for_lifetimebound_record_type::SWithUserDefinedCopyLikeOps' cannot carry a lifetime}}
SWithUserDefinedCopyLikeOps(const SWithUserDefinedCopyLikeOps &other) : owned("copy"), data(owned) {}
@@ -2586,7 +2586,7 @@ void from_typedef_return() {
struct SWithOriginPropagatingCopy {
SWithOriginPropagatingCopy();
- SWithOriginPropagatingCopy(const std::string &s [[clang::lifetimebound]]) : data(s) {}
+ SWithOriginPropagatingCopy(const std::string &s [[clang::lifetimebound]]) : data(s) {} // function-warning {{'lifetimebound' attribute has no effect on this function because return type 'track_origins_for_lifetimebound_record_type::SWithOriginPropagatingCopy' cannot carry a lifetime}}
SWithOriginPropagatingCopy(const SWithOriginPropagatingCopy &other) : data(other.data) {}
std::string_view data;
};
@@ -2603,7 +2603,7 @@ SWithOriginPropagatingCopy user_defined_copy_with_origin_propagation() {
struct DefaultedOuter {
DefaultedOuter();
- DefaultedOuter(const std::string &s [[clang::lifetimebound]]) : inner(s) {}
+ DefaultedOuter(const std::string &s [[clang::lifetimebound]]) : inner(s) {} // function-warning {{'lifetimebound' attribute has no effect on this function because return type 'track_origins_for_lifetimebound_record_type::DefaultedOuter' cannot carry a lifetime}}
SWithUserDefinedCopyLikeOps inner;
};
>From fb0f772f9820cf5b1e8a7bf3673d70d04046496a Mon Sep 17 00:00:00 2001
From: NeKon69 <nobodqwe at gmail.com>
Date: Sun, 28 Jun 2026 12:38:28 +0300
Subject: [PATCH 2/2] fixup
---
.../Analyses/LifetimeSafety/LifetimeSafety.h | 8 ++++--
clang/include/clang/Basic/DiagnosticGroups.td | 10 ++++++-
.../clang/Basic/DiagnosticSemaKinds.td | 2 +-
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 15 ++++------
clang/lib/Sema/SemaLifetimeSafety.h | 28 +++++++++++++------
.../LifetimeSafety/annotation-suggestions.cpp | 6 ++--
.../inapplicable-lifetimebound.cpp | 4 +--
clang/test/Sema/LifetimeSafety/safety.cpp | 8 +++---
8 files changed, 49 insertions(+), 32 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index ce35a14641a15..b55d3c1456f4b 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -143,9 +143,11 @@ class LifetimeSafetySemaHelper {
const ParmVarDecl *PVDDecl) {}
virtual void reportInapplicableLifetimebound(const ParmVarDecl *PVD,
- QualType Type,
- bool IsReturnType) {}
- virtual void reportInapplicableLifetimebound(const CXXMethodDecl *MD) {}
+ QualType Type) {}
+ virtual void reportInapplicableLifetimeboundReturnTy(const ParmVarDecl *PVD,
+ QualType Type) {}
+ virtual void
+ reportInapplicableLifetimeboundReturnTy(const CXXMethodDecl *MD) {}
// Suggests lifetime bound annotations for implicit this.
virtual void suggestLifetimeboundToImplicitThis(WarningScope Scope,
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 244cd3630bb11..35775f4fe57b5 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -631,8 +631,16 @@ This warning may produce false-positives diagnostics when it cannot fully model
}];
}
+def LifetimeSafetyInapplicableLifetimeboundReturn
+ : DiagGroup<"lifetime-safety-inapplicable-lifetimebound-return"> {
+ code Documentation = [{
+Detects uses of [[clang::lifetimebound]] that have no effect because the function return type cannot carry a lifetime.
+ }];
+}
+
def LifetimeSafetyInapplicableLifetimebound
- : DiagGroup<"lifetime-safety-inapplicable-lifetimebound"> {
+ : DiagGroup<"lifetime-safety-inapplicable-lifetimebound",
+ [LifetimeSafetyInapplicableLifetimeboundReturn]> {
code Documentation = [{
Detects uses of [[clang::lifetimebound]] that have no effect because the type of the annotated parameter cannot carry a lifetime.
}];
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 30ab502c32000..7c25f022eb080 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11050,7 +11050,7 @@ def warn_lifetime_safety_inapplicable_lifetimebound
def warn_lifetime_safety_inapplicable_lifetimebound_return
: Warning<"'lifetimebound' attribute has no effect on this function because return type %0 cannot carry a lifetime. The attribute only applies when the return type is a reference type, pointer type, or non-owner record type">,
- InGroup<LifetimeSafetyInapplicableLifetimebound>,
+ InGroup<LifetimeSafetyInapplicableLifetimeboundReturn>,
DefaultIgnore;
def note_lifetime_safety_used_here : Note<"later used here">;
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 41945607cf531..73b4f23e4a76d 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -488,21 +488,18 @@ class LifetimeChecker {
if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(FDef))
ReturnType = AST.getTypeDeclType(cast<TypeDecl>(Ctor->getParent()));
- bool ReturnTypeHasOrigins =
- FactMgr.getOriginMgr().hasOrigins(ReturnType,
- /*IntrinsicOnly=*/true);
+ bool ReturnTypeHasOrigins = FactMgr.getOriginMgr().hasOrigins(ReturnType);
if (getImplicitObjectParamLifetimeBoundAttr(FDef) && !ReturnTypeHasOrigins)
- SemaHelper->reportInapplicableLifetimebound(cast<CXXMethodDecl>(FDef));
+ SemaHelper->reportInapplicableLifetimeboundReturnTy(
+ cast<CXXMethodDecl>(FDef));
for (const auto &PVD : FDef->parameters())
if (PVD->hasAttr<LifetimeBoundAttr>()) {
if (!FactMgr.getOriginMgr().hasOrigins(PVD->getType(),
/*IntrinsicOnly=*/true))
- SemaHelper->reportInapplicableLifetimebound(PVD, PVD->getType(),
- /*IsReturnType=*/false);
- if (!ReturnTypeHasOrigins)
- SemaHelper->reportInapplicableLifetimebound(PVD, ReturnType,
- /*IsReturnType=*/true);
+ SemaHelper->reportInapplicableLifetimebound(PVD, PVD->getType());
+ if (!ReturnTypeHasOrigins && !isa<CXXConstructorDecl>(FDef))
+ SemaHelper->reportInapplicableLifetimeboundReturnTy(PVD, ReturnType);
}
}
diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h
index 20312d1787c87..28607636a0d75 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -49,7 +49,8 @@ inline bool IsLifetimeSafetyEnabled(Sema &S, const Decl *D) {
diag::warn_lifetime_safety_intra_tu_param_suggestion,
diag::warn_lifetime_safety_cross_tu_this_suggestion,
diag::warn_lifetime_safety_intra_tu_this_suggestion,
- diag::warn_lifetime_safety_inapplicable_lifetimebound};
+ diag::warn_lifetime_safety_inapplicable_lifetimebound,
+ diag::warn_lifetime_safety_inapplicable_lifetimebound_return};
for (unsigned DiagID : DiagIDs)
if (!Diags.isIgnored(DiagID, D->getBeginLoc()))
return true;
@@ -353,19 +354,28 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
<< Attr->getRange();
}
- void reportInapplicableLifetimebound(const ParmVarDecl *PVD, QualType Type,
- bool IsReturnType) override {
+ void reportInapplicableLifetimebound(const ParmVarDecl *PVD,
+ QualType Type) override {
assert(PVD->hasAttr<LifetimeBoundAttr>() &&
"Expected parameter to have lifetimebound attribute");
const auto *Attr = PVD->getAttr<LifetimeBoundAttr>();
- unsigned DiagID =
- IsReturnType
- ? diag::warn_lifetime_safety_inapplicable_lifetimebound_return
- : diag::warn_lifetime_safety_inapplicable_lifetimebound;
- S.Diag(Attr->getLocation(), DiagID) << Type << Attr->getRange();
+ S.Diag(Attr->getLocation(),
+ diag::warn_lifetime_safety_inapplicable_lifetimebound)
+ << Type << Attr->getRange();
+ }
+
+ void reportInapplicableLifetimeboundReturnTy(const ParmVarDecl *PVD,
+ QualType Type) override {
+ assert(PVD->hasAttr<LifetimeBoundAttr>() &&
+ "Expected parameter to have lifetimebound attribute");
+ const auto *Attr = PVD->getAttr<LifetimeBoundAttr>();
+ S.Diag(Attr->getLocation(),
+ diag::warn_lifetime_safety_inapplicable_lifetimebound_return)
+ << Type << Attr->getRange();
}
- void reportInapplicableLifetimebound(const CXXMethodDecl *MD) override {
+ void
+ reportInapplicableLifetimeboundReturnTy(const CXXMethodDecl *MD) override {
const auto *Attr = getImplicitObjectParamLifetimeBoundAttr(MD);
assert(Attr && "Expected lifetimebound attribute");
S.Diag(Attr->getLocation(),
diff --git a/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp b/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp
index 754533b065836..cef3397b57a6f 100644
--- a/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp
+++ b/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp
@@ -1,7 +1,7 @@
// RUN: rm -rf %t
// RUN: split-file %s %t
// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wlifetime-safety -Wlifetime-safety-annotation-placement -Wno-dangling -I%t -I%S -verify %t/test_source.cpp
-// RUN: %clang_cc1 -fsyntax-only -std=c++23 -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wlifetime-safety -Wlifetime-safety-annotation-placement -Wno-dangling -I%t -I%S -verify %t/test_source.cpp
+// RUN: %clang_cc1 -fsyntax-only -std=c++23 -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wlifetime-safety -Wno-dangling -I%t -I%S -verify %t/test_source.cpp
// RUN: %clang_cc1 -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wlifetime-safety -Wno-dangling -I%t -I%S -fixit %t/test_source.cpp
// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety-suggestions -Wno-dangling -I%t -I%S -Werror=lifetime-safety-suggestions %t/test_source.cpp
@@ -615,7 +615,7 @@ namespace make_unique_suggestion {
struct LifetimeBoundCtor {
View v;
// FIXME: This test fails to propagate the lifetimebound in ctor if this is inferred (instead of the current explicit annotation).
- LifetimeBoundCtor(const MyObj& obj [[clang::lifetimebound]]): v(obj) {} // expected-warning {{'lifetimebound' attribute has no effect on this function because return type 'make_unique_suggestion::LifetimeBoundCtor' cannot carry a lifetime}}
+ LifetimeBoundCtor(const MyObj& obj [[clang::lifetimebound]]): v(obj) {}
};
std::unique_ptr<LifetimeBoundCtor> create_target(const MyObj& obj) { // expected-warning {{parameter in intra-TU function should be marked [[clang::lifetimebound]]}}
@@ -649,7 +649,7 @@ void test_new_allocation() {
struct LifetimeBoundCtor {
View v;
LifetimeBoundCtor();
- LifetimeBoundCtor(const MyObj& obj [[clang::lifetimebound]]) : v(obj) {} // expected-warning {{'lifetimebound' attribute has no effect on this function because return type 'new_allocation_suggestion::LifetimeBoundCtor' cannot carry a lifetime}}
+ LifetimeBoundCtor(const MyObj& obj [[clang::lifetimebound]]) : v(obj) {}
};
struct HasCtorField {
diff --git a/clang/test/Sema/LifetimeSafety/inapplicable-lifetimebound.cpp b/clang/test/Sema/LifetimeSafety/inapplicable-lifetimebound.cpp
index 0e8f3196df972..8347aadc63deb 100644
--- a/clang/test/Sema/LifetimeSafety/inapplicable-lifetimebound.cpp
+++ b/clang/test/Sema/LifetimeSafety/inapplicable-lifetimebound.cpp
@@ -11,11 +11,11 @@ struct [[gsl::Pointer()]] View {
struct Plain {
Plain() {}
- Plain(const Plain &other [[clang::lifetimebound]]) {} // expected-warning {{'lifetimebound' attribute has no effect on this function because return type 'Plain' cannot carry a lifetime}}
+ Plain(const Plain &other [[clang::lifetimebound]]) {}
Plain operator+(const Plain &other [[clang::lifetimebound]]) const { return {}; } // expected-warning {{'lifetimebound' attribute has no effect on this function because return type 'Plain' cannot carry a lifetime}}
Plain &operator=(const Plain &other [[clang::lifetimebound]]) { return *this; }
operator int() const [[clang::lifetimebound]] { return 0; } // expected-warning {{'lifetimebound' attribute has no effect on this function because return type 'int' cannot carry a lifetime}}
- Plain(const Owner &o [[clang::lifetimebound]]) {} // expected-warning {{'lifetimebound' attribute has no effect on this function because return type 'Plain' cannot carry a lifetime}}
+ Plain(const Owner &o [[clang::lifetimebound]]) {}
};
enum Enum { Enumerator };
diff --git a/clang/test/Sema/LifetimeSafety/safety.cpp b/clang/test/Sema/LifetimeSafety/safety.cpp
index 687aa4c962b6c..c838918eb556d 100644
--- a/clang/test/Sema/LifetimeSafety/safety.cpp
+++ b/clang/test/Sema/LifetimeSafety/safety.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wlifetime-safety-annotation-placement -Wno-dangling -verify=expected,function %s
// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety -Wno-dangling -verify=expected,tu %s
-// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wlifetime-safety-annotation-placement -Wno-dangling -fcxx-exceptions -verify=expected,function %s
+// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wno-dangling -fcxx-exceptions -verify=expected,function %s
#include "Inputs/lifetime-analysis.h"
@@ -2533,7 +2533,7 @@ S S::return_self_after_registration() const {
struct SWithUserDefinedCopyLikeOps {
SWithUserDefinedCopyLikeOps();
- SWithUserDefinedCopyLikeOps(const std::string &s [[clang::lifetimebound]]) : owned(s), data(s) {} // function-warning {{'lifetimebound' attribute has no effect on this function because return type 'track_origins_for_lifetimebound_record_type::SWithUserDefinedCopyLikeOps' cannot carry a lifetime}}
+ SWithUserDefinedCopyLikeOps(const std::string &s [[clang::lifetimebound]]) : owned(s), data(s) {}
SWithUserDefinedCopyLikeOps(const SWithUserDefinedCopyLikeOps &other) : owned("copy"), data(owned) {}
@@ -2586,7 +2586,7 @@ void from_typedef_return() {
struct SWithOriginPropagatingCopy {
SWithOriginPropagatingCopy();
- SWithOriginPropagatingCopy(const std::string &s [[clang::lifetimebound]]) : data(s) {} // function-warning {{'lifetimebound' attribute has no effect on this function because return type 'track_origins_for_lifetimebound_record_type::SWithOriginPropagatingCopy' cannot carry a lifetime}}
+ SWithOriginPropagatingCopy(const std::string &s [[clang::lifetimebound]]) : data(s) {}
SWithOriginPropagatingCopy(const SWithOriginPropagatingCopy &other) : data(other.data) {}
std::string_view data;
};
@@ -2603,7 +2603,7 @@ SWithOriginPropagatingCopy user_defined_copy_with_origin_propagation() {
struct DefaultedOuter {
DefaultedOuter();
- DefaultedOuter(const std::string &s [[clang::lifetimebound]]) : inner(s) {} // function-warning {{'lifetimebound' attribute has no effect on this function because return type 'track_origins_for_lifetimebound_record_type::DefaultedOuter' cannot carry a lifetime}}
+ DefaultedOuter(const std::string &s [[clang::lifetimebound]]) : inner(s) {}
SWithUserDefinedCopyLikeOps inner;
};
More information about the cfe-commits
mailing list