Author: Utkarsh Saxena
Date: 2026-01-19T13:02:59+01:00
New Revision: 41e231cae38028473dd327e8de5f65792b521ffe

URL: 
https://github.com/llvm/llvm-project/commit/41e231cae38028473dd327e8de5f65792b521ffe
DIFF: 
https://github.com/llvm/llvm-project/commit/41e231cae38028473dd327e8de5f65792b521ffe.diff

LOG: [LifetimeSafety] Read lifetimebound attribute on implicit 'this' from all 
redeclarations (#176188)

Fix handling of `lifetimebound` attributes on implicit `this` parameters across 
function redeclarations.

Previously, the lifetime analysis would miss `lifetimebound` attributes on 
implicit `this` parameters if they were only present on certain redeclarations 
of a method. This could lead to false negatives in the lifetime safety 
analysis. This change ensures that if any redeclaration of a method has the 
attribute, it will be properly detected and used in the analysis.

I can't seem to work around the crash in the earlier attempt 
https://github.com/llvm/llvm-project/pull/172146.

Reproducer of the original crash:

```cpp
struct a {
  a &b() [[_Clang::__lifetimebound__]];
};
a &a::b() {}
```
This only crashes with `-target i686-w64-mingw32`. `bin/clang++ -c a.cpp` works 
fine.
Problematic merging logic:
```cpp
 // If Old has lifetimebound but New doesn't, add it to New.
  if (OldLBAttr && !NewLBAttr) {
    QualType NewMethodType = New->getType();
    QualType AttributedType =
        S.Context.getAttributedType(OldLBAttr, NewMethodType, NewMethodType);
    TypeLocBuilder TLB;
    TLB.pushFullCopy(NewTSI->getTypeLoc());
    AttributedTypeLoc TyLoc = TLB.push<AttributedTypeLoc>(AttributedType); // 
Crashes.
    TyLoc.setAttr(OldLBAttr);
    New->setType(AttributedType);
    New->setTypeSourceInfo(TLB.getTypeSourceInfo(S.Context, AttributedType));
  }
```

<details>
<summary>Crash</summary>

```
clang++: /REDACTED//llvm-project/clang/lib/Sema/TypeLocBuilder.cpp:89: TypeLoc 
clang::TypeLocBuilder::pushImpl(QualType, size_t, unsigned int): Assertion 
`TLast == LastTy && "mismatch between last type and new type's inner type"' 
failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and 
include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.      Program arguments: bin/clang++ -target i686-w64-mingw32 -c 
/REDACTED//a.cpp
1.      /REDACTED//a.cpp:4:11: current parser token '{'
 #0 0x000055971cfcb838 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) 
/REDACTED//llvm-project/llvm/lib/Support/Unix/Signals.inc:842:13
 #1 0x000055971cfc9374 llvm::sys::RunSignalHandlers() 
/REDACTED//llvm-project/llvm/lib/Support/Signals.cpp:109:18
 #2 0x000055971cfcaf0c llvm::sys::CleanupOnSignal(unsigned long) 
/REDACTED//llvm-project/llvm/lib/Support/Unix/Signals.inc:0:3
 #3 0x000055971cf38116 (anonymous 
namespace)::CrashRecoveryContextImpl::HandleCrash(int, unsigned long) 
/REDACTED//llvm-project/llvm/lib/Support/CrashRecoveryContext.cpp:73:5
 #4 0x000055971cf38116 CrashRecoverySignalHandler(int) 
/REDACTED//llvm-project/llvm/lib/Support/CrashRecoveryContext.cpp:390:51
 #5 0x00007fe9ebe49df0 (/lib/x86_64-linux-gnu/libc.so.6+0x3fdf0)
 #6 0x00007fe9ebe9e95c __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
 #7 0x00007fe9ebe49cc2 raise ./signal/../sysdeps/posix/raise.c:27:6
 #8 0x00007fe9ebe324ac abort ./stdlib/abort.c:81:3
 #9 0x00007fe9ebe32420 __assert_perror_fail ./assert/assert-perr.c:31:1
#10 0x000055971f969ade clang::TypeLocBuilder::pushImpl(clang::QualType, 
unsigned long, unsigned int) 
/REDACTED//llvm-project/clang/lib/Sema/TypeLocBuilder.cpp:93:3
#11 0x000055971f237255 clang::QualType::hasLocalQualifiers() const 
/REDACTED//llvm-project/clang/include/clang/AST/TypeBase.h:1065:37
#12 0x000055971f237255 clang::ConcreteTypeLoc<clang::UnqualTypeLoc, 
clang::AttributedTypeLoc, clang::AttributedType, 
clang::AttributedLocInfo>::isKind(clang::TypeLoc const&) 
/REDACTED//llvm-project/clang/include/clang/AST/TypeLoc.h:392:26
#13 0x000055971f237255 clang::AttributedTypeLoc 
clang::TypeLoc::castAs<clang::AttributedTypeLoc>() const 
/REDACTED//llvm-project/clang/include/clang/AST/TypeLoc.h:79:5
#14 0x000055971f237255 clang::AttributedTypeLoc 
clang::TypeLocBuilder::push<clang::AttributedTypeLoc>(clang::QualType) 
/REDACTED//llvm-project/clang/lib/Sema/TypeLocBuilder.h:106:47
#15 0x000055971f280cc8 clang::AttributedTypeLoc::setAttr(clang::Attr const*) 
/REDACTED//llvm-project/clang/include/clang/AST/TypeLoc.h:1035:30
#16 0x000055971f280cc8 mergeLifetimeBoundAttrOnMethod(clang::Sema&, 
clang::CXXMethodDecl*, clang::CXXMethodDecl const*) 
/REDACTED//llvm-project/clang/lib/Sema/SemaDecl.cpp:4497:11
#17 0x000055971f280cc8 
clang::Sema::MergeCompatibleFunctionDecls(clang::FunctionDecl*, 
clang::FunctionDecl*, clang::Scope*, bool) 
/REDACTED//llvm-project/clang/lib/Sema/SemaDecl.cpp:4528:5
#18 0x000055971f27eb1f clang::Sema::MergeFunctionDecl(clang::FunctionDecl*, 
clang::NamedDecl*&, clang::Scope*, bool, bool) 
/REDACTED//llvm-project/clang/lib/Sema/SemaDecl.cpp:0:0
#19 0x000055971f29c256 clang::Sema::CheckFunctionDeclaration(clang::Scope*, 
clang::FunctionDecl*, clang::LookupResult&, bool, bool) 
/REDACTED//llvm-project/clang/lib/Sema/SemaDecl.cpp:12371:9
#20 0x000055971f28dab0 clang::Declarator::setRedeclaration(bool) 
/REDACTED//llvm-project/clang/include/clang/Sema/DeclSpec.h:2738:51
#21 0x000055971f28dab0 clang::Sema::ActOnFunctionDeclarator(clang::Scope*, 
clang::Declarator&, clang::DeclContext*, clang::TypeSourceInfo*, 
clang::LookupResult&, llvm::MutableArrayRef<clang::TemplateParameterList*>, 
bool&) /REDACTED//llvm-project/clang/lib/Sema/SemaDecl.cpp:10877:9
#22 0x000055971f2890fc clang::Sema::HandleDeclarator(clang::Scope*, 
clang::Declarator&, llvm::MutableArrayRef<clang::TemplateParameterList*>) 
/REDACTED//llvm-project/clang/lib/Sema/SemaDecl.cpp:0:11
#23 0x000055971f2aab99 clang::Sema::ActOnStartOfFunctionDef(clang::Scope*, 
clang::Declarator&, llvm::MutableArrayRef<clang::TemplateParameterList*>, 
clang::SkipBodyInfo*, clang::Sema::FnBodyKind) 
/REDACTED//llvm-project/clang/lib/Sema/SemaDecl.cpp:15904:15
#24 0x000055971efab286 
clang::Parser::ParseFunctionDefinition(clang::ParsingDeclarator&, 
clang::Parser::ParsedTemplateInfo const&, clang::Parser::LateParsedAttrList*) 
/REDACTED//llvm-project/clang/lib/Parse/Parser.cpp:1364:23
#25 0x000055971f013b40 clang::Parser::ParseDeclGroup(clang::ParsingDeclSpec&, 
clang::DeclaratorContext, clang::ParsedAttributes&, 
clang::Parser::ParsedTemplateInfo&, clang::SourceLocation*, 
clang::Parser::ForRangeInit*) 
/REDACTED//llvm-project/clang/lib/Parse/ParseDecl.cpp:2268:18
#26 0x000055971efaa54f 
clang::Parser::ParseDeclOrFunctionDefInternal(clang::ParsedAttributes&, 
clang::ParsedAttributes&, clang::ParsingDeclSpec&, clang::AccessSpecifier) 
/REDACTED//llvm-project/clang/lib/Parse/Parser.cpp:0:10
#27 0x000055971efa9e36 
clang::Parser::ParseDeclarationOrFunctionDefinition(clang::ParsedAttributes&, 
clang::ParsedAttributes&, clang::ParsingDeclSpec*, clang::AccessSpecifier) 
/REDACTED//llvm-project/clang/lib/Parse/Parser.cpp:1202:12
#28 0x000055971efa8df8 
clang::Parser::ParseExternalDeclaration(clang::ParsedAttributes&, 
clang::ParsedAttributes&, clang::ParsingDeclSpec*) 
/REDACTED//llvm-project/clang/lib/Parse/Parser.cpp:0:14
#29 0x000055971efa7574 
clang::Parser::ParseTopLevelDecl(clang::OpaquePtr<clang::DeclGroupRef>&, 
clang::Sema::ModuleImportState&) 
/REDACTED//llvm-project/clang/lib/Parse/Parser.cpp:743:10
#30 0x000055971ef9c0ee clang::ParseAST(clang::Sema&, bool, bool) 
/REDACTED//llvm-project/clang/lib/Parse/ParseAST.cpp:169:5
#31 0x000055971dbcdad6 clang::FrontendAction::Execute() 
/REDACTED//llvm-project/clang/lib/Frontend/FrontendAction.cpp:1317:10
#32 0x000055971db3c5fd llvm::Error::getPtr() const 
/REDACTED//llvm-project/llvm/include/llvm/Support/Error.h:278:42
#33 0x000055971db3c5fd llvm::Error::operator bool() 
/REDACTED//llvm-project/llvm/include/llvm/Support/Error.h:241:16
#34 0x000055971db3c5fd 
clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) 
/REDACTED//llvm-project/clang/lib/Frontend/CompilerInstance.cpp:1006:23
#35 0x000055971dcb4f9c 
clang::ExecuteCompilerInvocation(clang::CompilerInstance*) 
/REDACTED//llvm-project/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp:310:25
#36 0x000055971a5e655e cc1_main(llvm::ArrayRef<char const*>, char const*, 
void*) /REDACTED//llvm-project/clang/tools/driver/cc1_main.cpp:304:15
#37 0x000055971a5e29cb ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, 
llvm::ToolContext const&, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>) 
/REDACTED//llvm-project/clang/tools/driver/driver.cpp:226:12
#38 0x000055971a5e4c1d clang_main(int, char**, llvm::ToolContext 
const&)::$_0::operator()(llvm::SmallVectorImpl<char const*>&) const 
/REDACTED//llvm-project/clang/tools/driver/driver.cpp:0:12
#39 0x000055971a5e4c1d int llvm::function_ref<int (llvm::SmallVectorImpl<char 
const*>&)>::callback_fn<clang_main(int, char**, llvm::ToolContext 
const&)::$_0>(long, llvm::SmallVectorImpl<char const*>&) 
/REDACTED//llvm-project/llvm/include/llvm/ADT/STLFunctionalExtras.h:46:12
#40 0x000055971d9bfe79 
clang::driver::CC1Command::Execute(llvm::ArrayRef<std::optional<llvm::StringRef>>,
 std::__cxx11::basic_string<char, std::char_traits<char>, 
std::allocator<char>>*, bool*) const::$_0::operator()() const 
/REDACTED//llvm-project/clang/lib/Driver/Job.cpp:442:30
#41 0x000055971d9bfe79 void llvm::function_ref<void 
()>::callback_fn<clang::driver::CC1Command::Execute(llvm::ArrayRef<std::optional<llvm::StringRef>>,
 std::__cxx11::basic_string<char, std::char_traits<char>, 
std::allocator<char>>*, bool*) const::$_0>(long) 
/REDACTED//llvm-project/llvm/include/llvm/ADT/STLFunctionalExtras.h:46:12
#42 0x000055971cf37dbe llvm::function_ref<void ()>::operator()() const 
/REDACTED//llvm-project/llvm/include/llvm/ADT/STLFunctionalExtras.h:0:12
#43 0x000055971cf37dbe 
llvm::CrashRecoveryContext::RunSafely(llvm::function_ref<void ()>) 
/REDACTED//llvm-project/llvm/lib/Support/CrashRecoveryContext.cpp:426:3
#44 0x000055971d9bf5ac 
clang::driver::CC1Command::Execute(llvm::ArrayRef<std::optional<llvm::StringRef>>,
 std::__cxx11::basic_string<char, std::char_traits<char>, 
std::allocator<char>>*, bool*) const 
/REDACTED//llvm-project/clang/lib/Driver/Job.cpp:442:7
#45 0x000055971d98422c 
clang::driver::Compilation::ExecuteCommand(clang::driver::Command const&, 
clang::driver::Command const*&, bool) const 
/REDACTED//llvm-project/clang/lib/Driver/Compilation.cpp:196:15
#46 0x000055971d984447 
clang::driver::Compilation::ExecuteJobs(clang::driver::JobList const&, 
llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*>>&, bool) 
const /REDACTED//llvm-project/clang/lib/Driver/Compilation.cpp:246:13
#47 0x000055971d99ee08 llvm::SmallVectorBase<unsigned int>::empty() const 
/REDACTED//llvm-project/llvm/include/llvm/ADT/SmallVector.h:83:46
#48 0x000055971d99ee08 
clang::driver::Driver::ExecuteCompilation(clang::driver::Compilation&, 
llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*>>&) 
/REDACTED//llvm-project/clang/lib/Driver/Driver.cpp:2265:23
#49 0x000055971a5e2303 clang_main(int, char**, llvm::ToolContext const&) 
/REDACTED//llvm-project/clang/tools/driver/driver.cpp:414:21
#50 0x000055971a5f2527 main 
/usr/local/google/home/usx/build/tools/clang/tools/driver/clang-driver.cpp:17:10
#51 0x00007fe9ebe33ca8 __libc_start_call_main 
./csu/../sysdeps/nptl/libc_start_call_main.h:74:3
#52 0x00007fe9ebe33d65 call_init ./csu/../csu/libc-start.c:128:20
#53 0x00007fe9ebe33d65 __libc_start_main ./csu/../csu/libc-start.c:347:5
#54 0x000055971a5e0361 _start (bin/clang+++0x6636361)
clang++: error: clang frontend command failed with exit code 134 (use -v to see 
invocation)
clang version 23.0.0git (https://github.com/llvm/llvm-project.git 
282a065c5bb36186c05b903980d1d3a37fce2175)
Target: i686-w64-windows-gnu
Thread model: posix
InstalledDir: /usr/local/google/home/usx/build/bin
Build config: +assertions
clang++: note: diagnostic msg: 
********************
```

</details>

Added: 
    

Modified: 
    clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h
    clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
    clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
    clang/test/Sema/warn-lifetime-safety.cpp
    clang/test/SemaCXX/attr-lifetimebound.cpp

Removed: 
    


################################################################################
diff  --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h
index f96d412aa63d2..760d34d33b15b 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h
@@ -10,6 +10,7 @@
 #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMEANNOTATIONS_H
 #define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMEANNOTATIONS_H
 
+#include "clang/AST/Attr.h"
 #include "clang/AST/DeclCXX.h"
 
 namespace clang ::lifetimes {

diff  --git a/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp 
b/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
index 2772fe20de19b..ced0ad537604a 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
@@ -52,22 +52,33 @@ bool isAssignmentOperatorLifetimeBound(const CXXMethodDecl 
*CMD) {
          CMD->getParamDecl(0)->hasAttr<clang::LifetimeBoundAttr>();
 }
 
+/// Check if a function has a lifetimebound attribute on its function type
+/// (which represents the implicit 'this' parameter for methods).
+/// Returns the attribute if found, nullptr otherwise.
+static const LifetimeBoundAttr *
+getLifetimeBoundAttrFromFunctionType(const TypeSourceInfo &TSI) {
+  // Walk through the type layers looking for a lifetimebound attribute.
+  TypeLoc TL = TSI.getTypeLoc();
+  while (true) {
+    auto ATL = TL.getAsAdjusted<AttributedTypeLoc>();
+    if (!ATL)
+      break;
+    if (auto *LBAttr = ATL.getAttrAs<LifetimeBoundAttr>())
+      return LBAttr;
+    TL = ATL.getModifiedLoc();
+  }
+  return nullptr;
+}
+
 bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD) {
   FD = getDeclWithMergedLifetimeBoundAttrs(FD);
-  const TypeSourceInfo *TSI = FD->getTypeSourceInfo();
-  if (!TSI)
-    return false;
-  // Don't declare this variable in the second operand of the for-statement;
-  // GCC miscompiles that by ending its lifetime before evaluating the
-  // third operand. See gcc.gnu.org/PR86769.
-  AttributedTypeLoc ATL;
-  for (TypeLoc TL = TSI->getTypeLoc();
-       (ATL = TL.getAsAdjusted<AttributedTypeLoc>());
-       TL = ATL.getModifiedLoc()) {
-    if (ATL.getAttrAs<clang::LifetimeBoundAttr>())
+  // Attribute merging doesn't work well with attributes on function types 
(like
+  // 'this' param). We need to check all redeclarations.
+  for (const FunctionDecl *Redecl : FD->redecls()) {
+    const TypeSourceInfo *TSI = Redecl->getTypeSourceInfo();
+    if (TSI && getLifetimeBoundAttrFromFunctionType(*TSI))
       return true;
   }
-
   return isNormalAssignmentOperator(FD);
 }
 

diff  --git a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp 
b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
index 7fdc493dbd17a..441f9fc602916 100644
--- a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
+++ b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
@@ -1039,3 +1039,141 @@ const char* foo() {
 }
 
 } // namespace GH127195
+
+// Lifetimebound on definition vs declaration on implicit this param.
+namespace GH175391 {
+// Version A: Attribute on declaration only
+class StringA {
+public:
+    const char* data() const [[clang::lifetimebound]];  // Declaration with 
attribute
+private:
+    char buffer[32] = "hello";
+};
+inline const char* StringA::data() const {  // Definition WITHOUT attribute
+    return buffer;
+}
+
+// Version B: Attribute on definition only
+class StringB {
+public:
+    const char* data() const;  // No attribute
+private:
+    char buffer[32] = "hello";
+};
+inline const char* StringB::data() const [[clang::lifetimebound]] {
+    return buffer;
+}
+
+// Version C: Attribute on BOTH declaration and definition
+class StringC {
+public:
+    const char* data() const [[clang::lifetimebound]];
+private:
+    char buffer[32] = "hello";
+};
+inline const char* StringC::data() const [[clang::lifetimebound]] {
+    return buffer;
+}
+
+// TEMPLATED VERSIONS
+
+// Template Version A: Attribute on declaration only
+template<typename T>
+class StringTemplateA {
+public:
+    const T* data() const [[clang::lifetimebound]];  // Declaration with 
attribute
+private:
+    T buffer[32];
+};
+template<typename T>
+inline const T* StringTemplateA<T>::data() const {  // Definition WITHOUT 
attribute
+    return buffer;
+}
+
+// Template Version B: Attribute on definition only
+template<typename T>
+class StringTemplateB {
+public:
+    const T* data() const;  // No attribute
+private:
+    T buffer[32];
+};
+template<typename T>
+inline const T* StringTemplateB<T>::data() const [[clang::lifetimebound]] {
+    return buffer;
+}
+
+// Template Version C: Attribute on BOTH declaration and definition
+template<typename T>
+class StringTemplateC {
+public:
+    const T* data() const [[clang::lifetimebound]];
+private:
+    T buffer[32];
+};
+template<typename T>
+inline const T* StringTemplateC<T>::data() const [[clang::lifetimebound]] {
+    return buffer;
+}
+
+// TEMPLATE SPECIALIZATION VERSIONS
+
+// Template predeclarations for specializations
+template<typename T> class StringTemplateSpecA;
+template<typename T> class StringTemplateSpecB;
+template<typename T> class StringTemplateSpecC;
+
+// Template Specialization Version A: Attribute on declaration only - <char> 
specialization
+template<>
+class StringTemplateSpecA<char> {
+public:
+    const char* data() const [[clang::lifetimebound]];  // Declaration with 
attribute
+private:
+    char buffer[32] = "hello";
+};
+inline const char* StringTemplateSpecA<char>::data() const {  // Definition 
WITHOUT attribute
+    return buffer;
+}
+
+// Template Specialization Version B: Attribute on definition only - <char> 
specialization
+template<>
+class StringTemplateSpecB<char> {
+public:
+    const char* data() const;  // No attribute
+private:
+    char buffer[32] = "hello";
+};
+inline const char* StringTemplateSpecB<char>::data() const 
[[clang::lifetimebound]] {
+    return buffer;
+}
+
+// Template Specialization Version C: Attribute on BOTH declaration and 
definition - <char> specialization
+template<>
+class StringTemplateSpecC<char> {
+public:
+    const char* data() const [[clang::lifetimebound]];
+private:
+    char buffer[32] = "hello";
+};
+inline const char* StringTemplateSpecC<char>::data() const 
[[clang::lifetimebound]] {
+    return buffer;
+}
+
+void test() {
+    // Non-templated tests
+    const auto ptrA = StringA().data();  // Declaration-only attribute  // 
expected-warning {{temporary whose address is used}}
+    const auto ptrB = StringB().data();  // Definition-only attribute   // 
expected-warning {{temporary whose address is used}}
+    const auto ptrC = StringC().data();  // Both have attribute         // 
expected-warning {{temporary whose address is used}}
+
+    // Templated tests (generic templates)
+    const auto ptrTA = StringTemplateA<char>().data();  // Declaration-only 
attribute // expected-warning {{temporary whose address is used}}
+    // FIXME: Definition is not instantiated until the end of TU. The 
attribute is not merged when this call is processed.
+    const auto ptrTB = StringTemplateB<char>().data();  // Definition-only 
attribute
+    const auto ptrTC = StringTemplateC<char>().data();  // Both have attribute 
       // expected-warning {{temporary whose address is used}}
+
+    // Template specialization tests
+    const auto ptrTSA = StringTemplateSpecA<char>().data();  // 
Declaration-only attribute  // expected-warning {{temporary whose address is 
used}}
+    const auto ptrTSB = StringTemplateSpecB<char>().data();  // 
Definition-only attribute   // expected-warning {{temporary whose address is 
used}}
+    const auto ptrTSC = StringTemplateSpecC<char>().data();  // Both have 
attribute         // expected-warning {{temporary whose address is used}}
+}
+} // namespace GH175391

diff  --git a/clang/test/Sema/warn-lifetime-safety.cpp 
b/clang/test/Sema/warn-lifetime-safety.cpp
index 0b1962b7cb651..24ac72e7aad4d 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -1431,3 +1431,25 @@ void not_silenced_via_conditional(bool cond) {
   (void)v;  // expected-note 2 {{later used here}}
 }
 } // namespace do_not_warn_on_std_move
+
+// Implicit this annotations with redecls.
+namespace GH172013 {
+// https://github.com/llvm/llvm-project/issues/62072
+// https://github.com/llvm/llvm-project/issues/172013
+struct S {
+    View x() const [[clang::lifetimebound]];
+    MyObj i;
+};
+
+View S::x() const { return i; }
+
+void bar() {
+    View x;
+    {
+        S s;
+        x = s.x(); // expected-warning {{object whose reference is captured 
does not live long enough}}
+        View y = S().x(); // FIXME: Handle temporaries.
+    } // expected-note {{destroyed here}}
+    (void)x; // expected-note {{used here}}
+}
+}

diff  --git a/clang/test/SemaCXX/attr-lifetimebound.cpp 
b/clang/test/SemaCXX/attr-lifetimebound.cpp
index 111bad65f7e1b..9e2aaff6559c4 100644
--- a/clang/test/SemaCXX/attr-lifetimebound.cpp
+++ b/clang/test/SemaCXX/attr-lifetimebound.cpp
@@ -75,6 +75,27 @@ namespace usage_ok {
     r = A(1); // expected-warning {{object backing the pointer 'r' will be 
destroyed at the end of the full-expression}}
   }
 
+  // Test that lifetimebound on implicit 'this' is propagated across 
redeclarations
+  struct B {
+    int *method() [[clang::lifetimebound]];
+    int i;
+  };
+  int *B::method() { return &i; }
+
+  // Test that lifetimebound on implicit 'this' is propagated across 
redeclarations
+  struct C {
+    int *method();
+    int i;
+  };
+  int *C::method() [[clang::lifetimebound]] { return &i; }
+
+  void test_lifetimebound_on_implicit_this() {
+    int *t = B().method();  // expected-warning {{temporary whose address is 
used as value of local variable 't' will be destroyed at the end of the 
full-expression}}
+    t = {B().method()};     // expected-warning {{object backing the pointer 
't' will be destroyed at the end of the full-expression}}
+    t = C().method();       // expected-warning {{object backing the pointer 
't' will be destroyed at the end of the full-expression}}
+    t = {C().method()};     // expected-warning {{object backing the pointer 
't' will be destroyed at the end of the full-expression}}
+  }
+
   struct FieldCheck {
     struct Set {
       int a;


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

Reply via email to