llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-temporal-safety

Author: NeKon69

<details>
<summary>Changes</summary>

Extends `-Wlifetime-safety-inapplicable-lifetimebound` to also diagnose when 
the function's return type cannot carry a lifetime, making 
`[[clang::lifetimebound]]` on parameters/implicit this inapplicable.

The attribute is only meaningful when the return value can refer to another 
object. When the return type is `int`, `void`, `Owner`, or any other type that 
cannot carry a lifetime, the attribute has no effect.

For constructors, we use the class type as the effective return type instead of 
`void`, so `gsl::Pointer` constructors still work correctly. However, this 
means existing constructors with `clang::lifetimebound` on plain/mixed types 
now get diagnosed.

Closes #<!-- -->188655

Assisted-by: Kimi K2.6 for writing some of the tests.

---
Full diff: https://github.com/llvm/llvm-project/pull/203767.diff


8 Files Affected:

- (modified) 
clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h (+4-1) 
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+5) 
- (modified) clang/lib/Analysis/LifetimeSafety/Checker.cpp (+19-4) 
- (modified) clang/lib/Sema/SemaLifetimeSafety.h (+14-3) 
- (modified) clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp (+3-3) 
- (modified) clang/test/Sema/LifetimeSafety/inapplicable-lifetimebound.cpp 
(+26-1) 
- (modified) 
clang/test/Sema/LifetimeSafety/misplaced-lifetimebound-intra-tu.cpp (+1-1) 
- (modified) clang/test/Sema/LifetimeSafety/safety.cpp (+4-4) 


``````````diff
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;
 };
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/203767
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to