https://github.com/NeKon69 updated https://github.com/llvm/llvm-project/pull/203767
>From a5b932706518c1513894400307801e359ac619fe Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> 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 <[email protected]> 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; }; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
