https://github.com/kashika0112 updated https://github.com/llvm/llvm-project/pull/171081
>From d9e30d12154c68a956bbf8eabb1a56a572e8e118 Mon Sep 17 00:00:00 2001 From: Kashika Akhouri <[email protected]> Date: Mon, 8 Dec 2025 06:14:28 +0000 Subject: [PATCH 1/2] Add annotation inference --- clang/lib/Analysis/LifetimeSafety/Checker.cpp | 17 ++++++++++++++++- .../Sema/warn-lifetime-safety-suggestions.cpp | 12 ++++++++++++ clang/test/Sema/warn-lifetime-safety.cpp | 16 +++++++++++++++- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp index 74792768e2c57..f5236f63da34a 100644 --- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp +++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp @@ -55,13 +55,14 @@ class LifetimeChecker { const LiveOriginsAnalysis &LiveOrigins; const FactManager &FactMgr; LifetimeSafetyReporter *Reporter; + AnalysisDeclContext &AC; public: LifetimeChecker(const LoanPropagationAnalysis &LoanPropagation, const LiveOriginsAnalysis &LiveOrigins, const FactManager &FM, AnalysisDeclContext &ADC, LifetimeSafetyReporter *Reporter) : LoanPropagation(LoanPropagation), LiveOrigins(LiveOrigins), FactMgr(FM), - Reporter(Reporter) { + Reporter(Reporter), AC(ADC) { for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>()) for (const Fact *F : FactMgr.getFacts(B)) if (const auto *EF = F->getAs<ExpireFact>()) @@ -70,6 +71,7 @@ class LifetimeChecker { checkAnnotations(OEF); issuePendingWarnings(); suggestAnnotations(); + inferAnnotations(); } /// Checks if an escaping origin holds a placeholder loan, indicating a @@ -160,6 +162,19 @@ class LifetimeChecker { for (const auto &[PVD, EscapeExpr] : AnnotationWarningsMap) Reporter->suggestAnnotation(PVD, EscapeExpr); } + + void inferAnnotations() { + /// NOTE: This currently only adds the attribute to the function definition + /// being analyzed. For full inter-procedural inference to work reliably + /// (e.g., with out-of-order definitions), this attribute would also need to + /// be added to all other redeclarations of the function. + for (const auto &[ConstPVD, EscapeExpr] : AnnotationWarningsMap) { + ParmVarDecl *PVD = const_cast<ParmVarDecl *>(ConstPVD); + ASTContext &Ctx = AC.getASTContext(); + auto *Attr = LifetimeBoundAttr::CreateImplicit(Ctx, SourceLocation()); + PVD->addAttr(Attr); + } + } }; } // namespace diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp index c0f675a301d14..087899b9f5d3f 100644 --- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp +++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp @@ -89,6 +89,18 @@ void test_getView_on_temporary() { (void)sv; } +//===----------------------------------------------------------------------===// +// Annotation Inference Test Cases +//===----------------------------------------------------------------------===// + +View return_view_by_func (View a) { // expected-warning {{param should be marked [[clang::lifetimebound]]}}. + return return_view_directly(a); // expected-note {{param returned here}} +} + +MyObj* return_pointer_by_func (MyObj* a) { // expected-warning {{param should be marked [[clang::lifetimebound]]}}. + return return_pointer_object(a); // expected-note {{param returned here}} +} + //===----------------------------------------------------------------------===// // Negative Test Cases //===----------------------------------------------------------------------===// diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp index 1191469e23df1..251324f968acd 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -fexperimental-lifetime-safety -Wexperimental-lifetime-safety -Wno-dangling -verify %s +// RUN: %clang_cc1 -fsyntax-only -fexperimental-lifetime-safety -Wexperimental-lifetime-safety -Wno-dangling -Wno-experimental-lifetime-safety-suggestions -verify %s struct MyObj { int id; @@ -552,6 +552,20 @@ const int& get_ref_to_local() { // expected-note@-1 {{returned here}} } +View inference_callee_return_identity(View a) { + return a; +} + +View inference_caller_forwards_callee(View a) { + return inference_callee_return_identity(a); +} + +View inference_top_level_return_stack_view() { + MyObj local_stack; + return inference_caller_forwards_callee(local_stack); // expected-warning {{address of stack memory is returned later}} + // expected-note@-1 {{returned here}} +} + //===----------------------------------------------------------------------===// // Use-After-Scope & Use-After-Return (Return-Stack-Address) Combined // These are cases where the diagnostic kind is determined by location >From cd528bbe55c053500d8055d3ce0d9b336ca1287d Mon Sep 17 00:00:00 2001 From: Kashika Akhouri <[email protected]> Date: Mon, 8 Dec 2025 12:54:29 +0000 Subject: [PATCH 2/2] Add more unit tests --- clang/lib/Analysis/LifetimeSafety/Checker.cpp | 18 ++++----- .../Sema/warn-lifetime-safety-suggestions.cpp | 28 ++++++++++++++ clang/test/Sema/warn-lifetime-safety.cpp | 38 +++++++++++++++++++ 3 files changed, 75 insertions(+), 9 deletions(-) diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp index f5236f63da34a..c8592a623dd2f 100644 --- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp +++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp @@ -55,14 +55,14 @@ class LifetimeChecker { const LiveOriginsAnalysis &LiveOrigins; const FactManager &FactMgr; LifetimeSafetyReporter *Reporter; - AnalysisDeclContext &AC; + ASTContext &AC; public: LifetimeChecker(const LoanPropagationAnalysis &LoanPropagation, const LiveOriginsAnalysis &LiveOrigins, const FactManager &FM, AnalysisDeclContext &ADC, LifetimeSafetyReporter *Reporter) : LoanPropagation(LoanPropagation), LiveOrigins(LiveOrigins), FactMgr(FM), - Reporter(Reporter), AC(ADC) { + Reporter(Reporter), AC(ADC.getASTContext()) { for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>()) for (const Fact *F : FactMgr.getFacts(B)) if (const auto *EF = F->getAs<ExpireFact>()) @@ -164,15 +164,15 @@ class LifetimeChecker { } void inferAnnotations() { - /// NOTE: This currently only adds the attribute to the function definition - /// being analyzed. For full inter-procedural inference to work reliably - /// (e.g., with out-of-order definitions), this attribute would also need to - /// be added to all other redeclarations of the function. + // FIXME: To maximise inference propagation, functions should be analyzed in + // post-order of the call graph, allowing inferred annotations to propagate + // through the call chain + // FIXME: Add the inferred attribute to all redeclarations of the function, + // not just the definition being analyzed. for (const auto &[ConstPVD, EscapeExpr] : AnnotationWarningsMap) { ParmVarDecl *PVD = const_cast<ParmVarDecl *>(ConstPVD); - ASTContext &Ctx = AC.getASTContext(); - auto *Attr = LifetimeBoundAttr::CreateImplicit(Ctx, SourceLocation()); - PVD->addAttr(Attr); + if (!PVD->hasAttr<LifetimeBoundAttr>()) + PVD->addAttr(LifetimeBoundAttr::CreateImplicit(AC, PVD->getLocation())); } } }; diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp index 087899b9f5d3f..248179e8ba7b6 100644 --- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp +++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp @@ -93,6 +93,7 @@ void test_getView_on_temporary() { // Annotation Inference Test Cases //===----------------------------------------------------------------------===// +namespace correct_order_inference { View return_view_by_func (View a) { // expected-warning {{param should be marked [[clang::lifetimebound]]}}. return return_view_directly(a); // expected-note {{param returned here}} } @@ -100,6 +101,33 @@ View return_view_by_func (View a) { // expected-warning {{param should be mar MyObj* return_pointer_by_func (MyObj* a) { // expected-warning {{param should be marked [[clang::lifetimebound]]}}. return return_pointer_object(a); // expected-note {{param returned here}} } +} // correct_order_inference + +namespace incorrect_order_inference_view { +View return_view_callee(View a); + +// FIXME: No lifetime annotation suggestion when functions are not present in the callee-before-caller pattern +View return_view_caller(View a) { + return return_view_callee(a); +} + +View return_view_callee(View a) { // expected-warning {{param should be marked [[clang::lifetimebound]]}}. + return a; // expected-note {{param returned here}} +} +} // incorrect_order_inference_view + +namespace incorrect_order_inference_object { +View return_object_callee(View a); + +// FIXME: No lifetime annotation suggestion warning when functions are not present in the callee-before-caller pattern +View return_object_caller(View a) { + return return_object_callee(a); +} + +View return_object_callee(View a) { // expected-warning {{param should be marked [[clang::lifetimebound]]}}. + return a; // expected-note {{param returned here}} +} +} // incorrect_order_inference_object //===----------------------------------------------------------------------===// // Negative Test Cases diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp index 251324f968acd..8cd1bd8bcc54c 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -552,6 +552,7 @@ const int& get_ref_to_local() { // expected-note@-1 {{returned here}} } +namespace simple_annotation_inference { View inference_callee_return_identity(View a) { return a; } @@ -565,6 +566,43 @@ View inference_top_level_return_stack_view() { return inference_caller_forwards_callee(local_stack); // expected-warning {{address of stack memory is returned later}} // expected-note@-1 {{returned here}} } +} // simple_annotation_inference + +namespace inference_in_order_with_redecls { +View inference_callee_return_identity(View a); +View inference_callee_return_identity(View a) { + return a; +} + +View inference_caller_forwards_callee(View a); +View inference_caller_forwards_callee(View a) { + return inference_callee_return_identity(a); +} + +View inference_top_level_return_stack_view() { + MyObj local_stack; + return inference_caller_forwards_callee(local_stack); // expected-warning {{address of stack memory is returned later}} + // expected-note@-1 {{returned here}} +} +} // namespace inference_in_order_with_redecls + +namespace inference_with_templates { +template<typename T> +T* template_identity(T* a) { + return a; +} + +template<typename T> +T* template_caller(T* a) { + return template_identity(a); +} + +// FIXME: Fails to detect UAR as template instantiations are deferred to the end of the Translation Unit. +MyObj* test_template_inference_with_stack() { + MyObj local_stack; + return template_caller(&local_stack); +} +} // inference_with_templates //===----------------------------------------------------------------------===// // Use-After-Scope & Use-After-Return (Return-Stack-Address) Combined _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
