https://github.com/higher-performance updated 
https://github.com/llvm/llvm-project/pull/112047

>From 7422a13bbf2a4cd2a7994df77c5c89acb5ea84de Mon Sep 17 00:00:00 2001
From: higher-performance <higher.performance.git...@gmail.com>
Date: Fri, 11 Oct 2024 17:09:13 -0400
Subject: [PATCH] Make [[clang::lifetimebound]] work for expressions coming
 from default arguments

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  2 ++
 clang/lib/Sema/CheckExprLifetime.cpp          | 31 ++++++++++++++++---
 clang/test/SemaCXX/attr-lifetimebound.cpp     | 11 +++++++
 3 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ce08bd60f76449..f49c874207585f 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10107,6 +10107,8 @@ def note_lambda_capture_initializer : Note<
   " via initialization of lambda capture %0}1">;
 def note_init_with_default_member_initializer : Note<
   "initializing field %0 with default member initializer">;
+def note_init_with_default_argument : Note<
+  "initializing parameter %0 with default argument">;
 
 // Check for initializing a member variable with the address or a reference to
 // a constructor parameter.
diff --git a/clang/lib/Sema/CheckExprLifetime.cpp 
b/clang/lib/Sema/CheckExprLifetime.cpp
index f62e18543851c1..a094fbca0ef949 100644
--- a/clang/lib/Sema/CheckExprLifetime.cpp
+++ b/clang/lib/Sema/CheckExprLifetime.cpp
@@ -194,6 +194,7 @@ struct IndirectLocalPathEntry {
     GslReferenceInit,
     GslPointerInit,
     GslPointerAssignment,
+    DefaultArg,
   } Kind;
   Expr *E;
   union {
@@ -465,17 +466,27 @@ static void visitFunctionCallArguments(IndirectLocalPath 
&Path, Expr *Call,
   for (unsigned I = 0,
                 N = std::min<unsigned>(Callee->getNumParams(), Args.size());
        I != N; ++I) {
+    Expr *Arg = Args[I];
+    auto *DAE = dyn_cast<CXXDefaultArgExpr>(Arg);
+    if (DAE) {
+      Path.push_back(
+          {IndirectLocalPathEntry::DefaultArg, DAE, DAE->getParam()});
+      Arg = DAE->getExpr();
+    }
     if (CheckCoroCall || Callee->getParamDecl(I)->hasAttr<LifetimeBoundAttr>())
-      VisitLifetimeBoundArg(Callee->getParamDecl(I), Args[I]);
+      VisitLifetimeBoundArg(Callee->getParamDecl(I), Arg);
     else if (EnableGSLAnalysis && I == 0) {
       if (shouldTrackFirstArgument(Callee)) {
-        VisitGSLPointerArg(Callee, Args[0]);
+        VisitGSLPointerArg(Callee, Arg);
       } else if (auto *CCE = dyn_cast<CXXConstructExpr>(Call);
                  CCE &&
                  CCE->getConstructor()->getParent()->hasAttr<PointerAttr>()) {
-        VisitGSLPointerArg(CCE->getConstructor(), Args[0]);
+        VisitGSLPointerArg(CCE->getConstructor(), Arg);
       }
     }
+    if (DAE) {
+      Path.pop_back();
+    }
   }
 }
 
@@ -916,6 +927,9 @@ static SourceRange nextPathEntryRange(const 
IndirectLocalPath &Path, unsigned I,
       if (!Path[I].Capture->capturesVariable())
         continue;
       return Path[I].E->getSourceRange();
+
+    case IndirectLocalPathEntry::DefaultArg:
+      return cast<CXXDefaultArgExpr>(Path[I].E)->getUsedLocation();
     }
   }
   return E->getSourceRange();
@@ -1221,7 +1235,7 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
         break;
       }
 
-      case IndirectLocalPathEntry::LambdaCaptureInit:
+      case IndirectLocalPathEntry::LambdaCaptureInit: {
         if (!Elem.Capture->capturesVariable())
           break;
         // FIXME: We can't easily tell apart an init-capture from a nested
@@ -1234,6 +1248,15 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
             << nextPathEntryRange(Path, I + 1, L);
         break;
       }
+
+      case IndirectLocalPathEntry::DefaultArg: {
+        const auto *DAE = cast<CXXDefaultArgExpr>(Elem.E);
+        SemaRef.Diag(DAE->getParam()->getDefaultArgRange().getBegin(),
+                     diag::note_init_with_default_argument)
+            << DAE->getParam() << nextPathEntryRange(Path, I + 1, L);
+        break;
+      }
+      }
     }
 
     // We didn't lifetime-extend, so don't go any further; we don't need more
diff --git a/clang/test/SemaCXX/attr-lifetimebound.cpp 
b/clang/test/SemaCXX/attr-lifetimebound.cpp
index 0fb997a5671085..a1dba5c6a2473e 100644
--- a/clang/test/SemaCXX/attr-lifetimebound.cpp
+++ b/clang/test/SemaCXX/attr-lifetimebound.cpp
@@ -18,9 +18,13 @@ namespace usage_invalid {
 
 namespace usage_ok {
   struct IntRef { int *target; };
+  using IntArray = int[];
 
+  const int *defaultparam(const int &def1 [[clang::lifetimebound]] = 0); // 
#def1
   int &refparam(int &param [[clang::lifetimebound]]);
   int &classparam(IntRef param [[clang::lifetimebound]]);
+  const int *c = defaultparam(); // expected-warning {{temporary whose address 
is used as value of local variable 'c' will be destroyed at the end of the 
full-expression}} expected-note@#def1 {{initializing parameter 'def1' with 
default argument}}
+  const int &defaultparam_array([[clang::lifetimebound]] const int *p = 
IntArray{1, 2, 3}); // #def2
 
   // Do not diagnose non-void return types; they can still be lifetime-bound.
   long long ptrintcast(int &param [[clang::lifetimebound]]) {
@@ -34,13 +38,20 @@ namespace usage_ok {
   struct A {
     A();
     A(int);
+    A(const char*, const int& def3 [[clang::lifetimebound]] = 0); // #def3
     int *class_member() [[clang::lifetimebound]];
     operator int*() [[clang::lifetimebound]];
+    static const int &defaulted_param(const int &def4 [[clang::lifetimebound]] 
= 0); // #def4
+    static const int &defaulted_param2(const int &def5 
[[clang::lifetimebound]] = defaulted_param()); // #def5
   };
 
   int *p = A().class_member(); // expected-warning {{temporary whose address 
is used as value of local variable 'p' will be destroyed at the end of the 
full-expression}}
   int *q = A(); // expected-warning {{temporary whose address is used as value 
of local variable 'q' will be destroyed at the end of the full-expression}}
   int *r = A(1); // expected-warning {{temporary whose address is used as 
value of local variable 'r' will be destroyed at the end of the 
full-expression}}
+  A a = A(""); // expected-warning {{temporary whose address is used as value 
of local variable 'a' will be destroyed at the end of the full-expression}} 
expected-note@#def3 {{initializing parameter 'def3' with default argument}}
+  const int &s = A::defaulted_param(); // expected-warning {{temporary bound 
to local reference 's' will be destroyed at the end of the full-expression}} 
expected-note@#def4 {{initializing parameter 'def4' with default argument}}
+  const int &t = A::defaulted_param2(); // expected-warning {{temporary bound 
to local reference 't' will be destroyed at the end of the full-expression}} 
expected-note@#def4 {{initializing parameter 'def4' with default argument}} 
expected-note@#def5 {{initializing parameter 'def5' with default argument}}
+  const int &u = defaultparam_array(); // expected-warning {{temporary bound 
to local reference 'u' will be destroyed at the end of the full-expression}} 
expected-note@#def2 {{initializing parameter 'p' with default argument}}
 
   void test_assignment() {
     p = A().class_member(); // expected-warning {{object backing the pointer p 
will be destroyed at the end of the full-expression}}

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to