https://github.com/suoyuan666 updated https://github.com/llvm/llvm-project/pull/212083
>From fc0f25bc4769204d0fdfad065bc35708d31300c4 Mon Sep 17 00:00:00 2001 From: Yuan Suo <[email protected]> Date: Sat, 18 Jul 2026 15:06:23 +0800 Subject: [PATCH 1/5] Use buildOriginFlowChain for remaining diagnostics in issuePendingWarnings Signed-off-by: Yuan Suo <[email protected]> --- .../Analyses/LifetimeSafety/LifetimeSafety.h | 18 ++++-- .../Analyses/LifetimeSafety/LoanPropagation.h | 2 +- clang/lib/Analysis/LifetimeSafety/Checker.cpp | 34 +++++----- .../LifetimeSafety/LoanPropagation.cpp | 9 ++- clang/lib/Sema/SemaLifetimeSafety.h | 34 +++++++--- .../LifetimeSafety/annotation-suggestions.cpp | 18 ++++-- .../Sema/LifetimeSafety/dangling-field.cpp | 27 +++++--- .../Sema/LifetimeSafety/dangling-global.cpp | 2 +- .../Sema/LifetimeSafety/invalidations.cpp | 19 ++++-- clang/test/Sema/LifetimeSafety/nocfg.cpp | 14 +++-- clang/test/Sema/LifetimeSafety/safety-c.c | 6 +- clang/test/Sema/LifetimeSafety/safety.cpp | 63 +++++++++++++------ 12 files changed, 164 insertions(+), 82 deletions(-) diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h index f8b7d2008bd789..84fbfde19dbb80 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h @@ -86,12 +86,14 @@ class LifetimeSafetySemaHelper { const FieldDecl *Field, const Expr *MovedExpr, bool IsCapturedByLambda, - SourceLocation ExpiryLoc) {} + SourceLocation ExpiryLoc, + llvm::ArrayRef<const Expr *> ExprChain) {} virtual void reportDanglingGlobal(const Expr *IssueExpr, const VarDecl *DanglingGlobal, const Expr *MovedExpr, SourceLocation ExpiryLoc, + llvm::ArrayRef<const Expr *> ExprChain, bool IsMain = false) {} // Reports when a reference/iterator is used after the container operation @@ -106,16 +108,22 @@ class LifetimeSafetySemaHelper { llvm::ArrayRef<const Expr *> ExprChain) {} virtual void reportInvalidatedField(const Expr *IssueExpr, const FieldDecl *Field, - const Expr *InvalidationExpr) {} + const Expr *InvalidationExpr, + llvm::ArrayRef<const Expr *> ExprChain) {} virtual void reportInvalidatedField(const ParmVarDecl *PVD, const FieldDecl *Field, - const Expr *InvalidationExpr) {} + const Expr *InvalidationExpr, + llvm::ArrayRef<const Expr *> ExprChain) {} virtual void reportInvalidatedGlobal(const Expr *IssueExpr, const VarDecl *Global, - const Expr *InvalidationExpr) {} + const Expr *InvalidationExpr, + llvm::ArrayRef<const Expr *> ExprChain) { + } virtual void reportInvalidatedGlobal(const ParmVarDecl *PVD, const VarDecl *Global, - const Expr *InvalidationExpr) {} + const Expr *InvalidationExpr, + llvm::ArrayRef<const Expr *> ExprChain) { + } using EscapingTarget = llvm::PointerUnion<const Expr *, const FieldDecl *, const VarDecl *>; diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h index de7eca39228ca3..d8dffb4fc1a268 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h @@ -53,7 +53,7 @@ class LoanPropagationAnalysis { /// Like the above, starting from the used origin holding \p TargetLoan. The /// casts that load the used variable itself are left out. - llvm::SmallVector<OriginID> buildOriginFlowChain(const UseFact *UF, + llvm::SmallVector<OriginID> buildOriginFlowChain(const Fact *F, const LoanID TargetLoan, const CFG *Cfg) const; diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp index 3d2cab92b384bf..a5fdcf677484cd 100644 --- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp +++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp @@ -322,33 +322,35 @@ class LifetimeChecker { } else if (const auto *OEF = dyn_cast<const OriginEscapesFact *>(CausingFact)) { + llvm::SmallVector<const Expr *> ExprChain = + getExprChain(LoanPropagation.buildOriginFlowChain(OEF, LID, Cfg)); if (Warning.InvalidatedByExpr) { if (const auto *FieldEscape = dyn_cast<FieldEscapeFact>(OEF)) { // Invalidated object escapes to a field. if (IssueExpr) // Invalidated object on stack escapes to a field. - SemaHelper->reportInvalidatedField(IssueExpr, - FieldEscape->getFieldDecl(), - Warning.InvalidatedByExpr); + SemaHelper->reportInvalidatedField( + IssueExpr, FieldEscape->getFieldDecl(), + Warning.InvalidatedByExpr, ExprChain); else if (InvalidatedPVD) // Invalidated parameter escapes to a field. - SemaHelper->reportInvalidatedField(InvalidatedPVD, - FieldEscape->getFieldDecl(), - Warning.InvalidatedByExpr); + SemaHelper->reportInvalidatedField( + InvalidatedPVD, FieldEscape->getFieldDecl(), + Warning.InvalidatedByExpr, ExprChain); } else if (const auto *GlobalEscape = dyn_cast<GlobalEscapeFact>(OEF)) { // Invalidated object escapes to global or static storage. if (IssueExpr) // Invalidated object on stack escapes to global or static // storage. - SemaHelper->reportInvalidatedGlobal(IssueExpr, - GlobalEscape->getGlobal(), - Warning.InvalidatedByExpr); + SemaHelper->reportInvalidatedGlobal( + IssueExpr, GlobalEscape->getGlobal(), + Warning.InvalidatedByExpr, ExprChain); else if (InvalidatedPVD) // Invalidated parameter escapes to global or static storage. - SemaHelper->reportInvalidatedGlobal(InvalidatedPVD, - GlobalEscape->getGlobal(), - Warning.InvalidatedByExpr); + SemaHelper->reportInvalidatedGlobal( + InvalidatedPVD, GlobalEscape->getGlobal(), + Warning.InvalidatedByExpr, ExprChain); } else if (isa<ReturnEscapeFact>(OEF)) { // FIXME: Diagnose invalidated return escapes separately. } else @@ -356,23 +358,21 @@ class LifetimeChecker { } else if (const auto *RetEscape = dyn_cast<ReturnEscapeFact>(OEF)) { // Return stack address. SemaHelper->reportUseAfterReturn( - IssueExpr, RetEscape->getReturnExpr(), MovedExpr, - getExprChain( - LoanPropagation.buildOriginFlowChain(OEF, LID, Cfg))); + IssueExpr, RetEscape->getReturnExpr(), MovedExpr, ExprChain); } else if (const auto *FieldEscape = dyn_cast<FieldEscapeFact>(OEF)) { // Dangling field. bool IsCapturedByLambda = FactMgr.isFieldCapturedByLambda(FieldEscape->getFieldDecl()); SemaHelper->reportDanglingField( IssueExpr, FieldEscape->getFieldDecl(), MovedExpr, - IsCapturedByLambda, ExpiryLoc); + IsCapturedByLambda, ExpiryLoc, ExprChain); } else if (const auto *GlobalEscape = dyn_cast<GlobalEscapeFact>(OEF)) { // Global escape. bool IsMain = false; if (const auto *Func = dyn_cast_if_present<FunctionDecl>(FD)) IsMain = Func->isMain(); SemaHelper->reportDanglingGlobal(IssueExpr, GlobalEscape->getGlobal(), - MovedExpr, ExpiryLoc, IsMain); + MovedExpr, ExpiryLoc, ExprChain, IsMain); } else llvm_unreachable("Unhandled OriginEscapesFact type"); } else diff --git a/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp b/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp index df66f029a5400d..7db184a09a41e0 100644 --- a/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp +++ b/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp @@ -352,8 +352,13 @@ llvm::SmallVector<OriginID> LoanPropagationAnalysis::buildOriginFlowChain( } llvm::SmallVector<OriginID> LoanPropagationAnalysis::buildOriginFlowChain( - const UseFact *UF, const LoanID TargetLoan, const CFG *Cfg) const { - return PImpl->buildOriginFlowChain(UF, TargetLoan, Cfg); + const Fact *F, const LoanID TargetLoan, const CFG *Cfg) const { + if (const auto *UF = llvm::dyn_cast<UseFact>(F)) + return PImpl->buildOriginFlowChain(UF, TargetLoan, Cfg); + if (const auto *OEF = llvm::dyn_cast<OriginEscapesFact>(F)) + return PImpl->buildOriginFlowChain(OEF, OEF->getEscapedOriginID(), + TargetLoan, Cfg); + llvm_unreachable("Unhandled Fact type"); } llvm::SmallVector<OriginID> LoanPropagationAnalysis::buildOriginFlowChain(const OriginEscapesFact *OEF, diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h index 3db298b6fec85c..57570043610a0d 100644 --- a/clang/lib/Sema/SemaLifetimeSafety.h +++ b/clang/lib/Sema/SemaLifetimeSafety.h @@ -187,7 +187,8 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper { void reportDanglingField(const Expr *IssueExpr, const FieldDecl *DanglingField, const Expr *MovedExpr, bool IsCapturedByLambda, - SourceLocation ExpiryLoc) override { + SourceLocation ExpiryLoc, + llvm::ArrayRef<const Expr *> ExprChain) override { unsigned DiagID = IsCapturedByLambda ? diag::warn_lifetime_safety_dangling_field_lambda_capture @@ -201,6 +202,9 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper { if (MovedExpr) S.Diag(MovedExpr->getExprLoc(), diag::note_lifetime_safety_moved_here) << MovedExpr->getSourceRange(); + + reportAliasingChain(ExprChain); + S.Diag(DanglingField->getLocation(), diag::note_lifetime_safety_dangling_field_here) << DanglingField->getEndLoc(); @@ -209,6 +213,7 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper { void reportDanglingGlobal(const Expr *IssueExpr, const VarDecl *DanglingGlobal, const Expr *MovedExpr, SourceLocation ExpiryLoc, + llvm::ArrayRef<const Expr *> ExprChain, bool IsMain = false) override { unsigned DiagID; if (IsMain) { @@ -226,6 +231,9 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper { if (MovedExpr) S.Diag(MovedExpr->getExprLoc(), diag::note_lifetime_safety_moved_here) << MovedExpr->getSourceRange(); + + reportAliasingChain(ExprChain); + if (DanglingGlobal->isStaticLocal() || DanglingGlobal->isStaticDataMember()) S.Diag(DanglingGlobal->getLocation(), diag::note_lifetime_safety_dangling_static_here) @@ -271,13 +279,15 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper { void reportInvalidatedField(const Expr *IssueExpr, const FieldDecl *DanglingField, - const Expr *InvalidationExpr) override { + const Expr *InvalidationExpr, + llvm::ArrayRef<const Expr *> ExprChain) override { std::string InvalidatedSubject = getDiagSubjectDescription(IssueExpr); S.Diag(IssueExpr->getExprLoc(), diag::warn_lifetime_safety_invalidated_field) << InvalidatedSubject << getDiagSubjectDescription(DanglingField) << IssueExpr->getSourceRange(); reportInvalidationSite(InvalidationExpr, InvalidatedSubject); + reportAliasingChain(ExprChain); S.Diag(DanglingField->getLocation(), diag::note_lifetime_safety_dangling_field_here) << DanglingField->getEndLoc(); @@ -285,27 +295,31 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper { void reportInvalidatedField(const ParmVarDecl *PVD, const FieldDecl *DanglingField, - const Expr *InvalidationExpr) override { + const Expr *InvalidationExpr, + llvm::ArrayRef<const Expr *> ExprChain) override { std::string InvalidatedSubject = getDiagSubjectDescription(PVD); S.Diag(PVD->getSourceRange().getBegin(), diag::warn_lifetime_safety_invalidated_field) << InvalidatedSubject << getDiagSubjectDescription(DanglingField) << PVD->getSourceRange(); reportInvalidationSite(InvalidationExpr, InvalidatedSubject); + reportAliasingChain(ExprChain); S.Diag(DanglingField->getLocation(), diag::note_lifetime_safety_dangling_field_here) << DanglingField->getEndLoc(); } - void reportInvalidatedGlobal(const Expr *IssueExpr, - const VarDecl *DanglingGlobal, - const Expr *InvalidationExpr) override { + void + reportInvalidatedGlobal(const Expr *IssueExpr, const VarDecl *DanglingGlobal, + const Expr *InvalidationExpr, + llvm::ArrayRef<const Expr *> ExprChain) override { std::string InvalidatedSubject = getDiagSubjectDescription(IssueExpr); S.Diag(IssueExpr->getExprLoc(), diag::warn_lifetime_safety_invalidated_global) << InvalidatedSubject << getDiagSubjectDescription(DanglingGlobal) << IssueExpr->getSourceRange(); reportInvalidationSite(InvalidationExpr, InvalidatedSubject); + reportAliasingChain(ExprChain); if (DanglingGlobal->isStaticLocal() || DanglingGlobal->isStaticDataMember()) S.Diag(DanglingGlobal->getLocation(), diag::note_lifetime_safety_dangling_static_here) @@ -316,15 +330,17 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper { << DanglingGlobal->getEndLoc(); } - void reportInvalidatedGlobal(const ParmVarDecl *PVD, - const VarDecl *DanglingGlobal, - const Expr *InvalidationExpr) override { + void + reportInvalidatedGlobal(const ParmVarDecl *PVD, const VarDecl *DanglingGlobal, + const Expr *InvalidationExpr, + llvm::ArrayRef<const Expr *> ExprChain) override { std::string InvalidatedSubject = getDiagSubjectDescription(PVD); S.Diag(PVD->getSourceRange().getBegin(), diag::warn_lifetime_safety_invalidated_global) << InvalidatedSubject << getDiagSubjectDescription(DanglingGlobal) << PVD->getSourceRange(); reportInvalidationSite(InvalidationExpr, InvalidatedSubject); + reportAliasingChain(ExprChain); if (DanglingGlobal->isStaticLocal() || DanglingGlobal->isStaticDataMember()) S.Diag(DanglingGlobal->getLocation(), diag::note_lifetime_safety_dangling_static_here) diff --git a/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp b/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp index 34f3ad4f45de1a..3769710c489886 100644 --- a/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp +++ b/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp @@ -528,7 +528,8 @@ struct CaptureRefToView { CaptureRefToView test_ref_to_view() { MyObj obj; CaptureRefToView x(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} - return x; // expected-note {{returned here}} + return x; // expected-note {{returned here}} \ + // expected-note {{local variable 'x' aliases the storage of local variable 'obj'}} } struct CaptureRefToPtr { @@ -539,7 +540,8 @@ struct CaptureRefToPtr { CaptureRefToPtr test_ref_to_ptr() { MyObj obj; CaptureRefToPtr x(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} - return x; // expected-note {{returned here}} + return x; // expected-note {{returned here}} \ + // expected-note {{local variable 'x' aliases the storage of local variable 'obj'}} } struct CaptureViewToView { @@ -562,7 +564,8 @@ struct CapturePtrToPtr { CapturePtrToPtr test_ptr_to_ptr() { MyObj obj; CapturePtrToPtr x(&obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} - return x; // expected-note {{returned here}} + return x; // expected-note {{returned here}} \ + // expected-note {{local variable 'x' aliases the storage of local variable 'obj'}} } struct CaptureRefToRef { @@ -573,7 +576,8 @@ struct CaptureRefToRef { CaptureRefToRef test_ref_to_ref() { MyObj obj; CaptureRefToRef x(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} - return x; // expected-note {{returned here}} + return x; // expected-note {{returned here}} \ + // expected-note {{local variable 'x' aliases the storage of local variable 'obj'}} } struct BaseWithView { @@ -588,7 +592,8 @@ struct CaptureRefToBaseView : BaseWithView { CaptureRefToBaseView test_ref_to_base_view() { MyObj obj; CaptureRefToBaseView x(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} - return x; // expected-note {{returned here}} + return x; // expected-note {{returned here}} \ + // expected-note {{local variable 'x' aliases the storage of local variable 'obj'}} } } // namespace capturing_constructor @@ -660,7 +665,8 @@ struct HasCtorField { HasCtorField test_dangling_field_ctor() { MyObj obj; HasCtorField x(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} - return x; // expected-note {{returned here}} + return x; // expected-note {{returned here}} \ + // expected-note {{local variable 'x' aliases the storage of local variable 'obj'}} } struct HasSetterField { diff --git a/clang/test/Sema/LifetimeSafety/dangling-field.cpp b/clang/test/Sema/LifetimeSafety/dangling-field.cpp index 68ed47687b29ae..06db94d81f02c5 100644 --- a/clang/test/Sema/LifetimeSafety/dangling-field.cpp +++ b/clang/test/Sema/LifetimeSafety/dangling-field.cpp @@ -40,7 +40,8 @@ struct CtorSetInLoop { struct CtorInitLifetimeBound { std::string_view view; // expected-note {{this field dangles}} - CtorInitLifetimeBound(std::string s) : view(construct_view(s)) {} // expected-warning {{stack memory associated with parameter 's' escapes to the field 'view' which will dangle}} + CtorInitLifetimeBound(std::string s) : view(construct_view(s)) {} // expected-warning {{stack memory associated with parameter 's' escapes to the field 'view' which will dangle}} \ + // expected-note {{result of call to 'construct_view' aliases the storage of parameter 's'}} }; struct CtorInitButMoved { @@ -90,7 +91,8 @@ struct CtorRefField { struct CtorPointerField { const char* ptr; // expected-note {{this field dangles}} - CtorPointerField(std::string s) : ptr(s.data()) {} // expected-warning {{stack memory associated with parameter 's' escapes to the field 'ptr' which will dangle}} + CtorPointerField(std::string s) : ptr(s.data()) {} // expected-warning {{stack memory associated with parameter 's' escapes to the field 'ptr' which will dangle}} \ + // expected-note {{result of call to 'data' aliases the storage of parameter 's'}} CtorPointerField(Dummy<1> ok, const std::string& s) : ptr(s.data()) {} CtorPointerField(Dummy<2> ok, std::string_view view) : ptr(view.data()) {} }; @@ -101,12 +103,14 @@ struct MemberSetters { void setWithParam(std::string s) { view = s; // expected-warning {{stack memory associated with parameter 's' escapes to the field 'view' which will dangle}} - p = s.data(); // expected-warning {{stack memory associated with parameter 's' escapes to the field 'p' which will dangle}} + p = s.data(); // expected-warning {{stack memory associated with parameter 's' escapes to the field 'p' which will dangle}} \ + // expected-note {{result of call to 'data' aliases the storage of parameter 's'}} } void setWithParamAndReturn(std::string s) { view = s; // expected-warning {{stack memory associated with parameter 's' escapes to the field 'view' which will dangle}} - p = s.data(); // expected-warning {{stack memory associated with parameter 's' escapes to the field 'p' which will dangle}} + p = s.data(); // expected-warning {{stack memory associated with parameter 's' escapes to the field 'p' which will dangle}} \ + // expected-note {{result of call to 'data' aliases the storage of parameter 's'}} return; } @@ -124,13 +128,15 @@ struct MemberSetters { void setWithLocal() { std::string s; view = s; // expected-warning {{stack memory associated with local variable 's' escapes to the field 'view' which will dangle}} - p = s.data(); // expected-warning {{stack memory associated with local variable 's' escapes to the field 'p' which will dangle}} + p = s.data(); // expected-warning {{stack memory associated with local variable 's' escapes to the field 'p' which will dangle}} \ + // expected-note {{result of call to 'data' aliases the storage of local variable 's'}} } void setWithLocalButMoved() { std::string s; view = s; // expected-warning-re {{stack memory associated with local variable 's' may escape to the field 'view' which will dangle. {{.*}} may have been moved}} - p = s.data(); // expected-warning-re {{stack memory associated with local variable 's' may escape to the field 'p' which will dangle. {{.*}} may have been moved}} + p = s.data(); // expected-warning-re {{stack memory associated with local variable 's' may escape to the field 'p' which will dangle. {{.*}} may have been moved}} \ + // expected-note {{result of call to 'data' aliases the storage of local variable 's'}} takeString(std::move(s)); // expected-note 2 {{potentially moved here}} } @@ -154,14 +160,16 @@ struct MemberSetters { std::string local; view = local; // expected-warning {{stack memory associated with local variable 'local' escapes to the field 'view' which will dangle}} - p = local.data(); // expected-warning {{stack memory associated with local variable 'local' escapes to the field 'p' which will dangle}} + p = local.data(); // expected-warning {{stack memory associated with local variable 'local' escapes to the field 'p' which will dangle}} \ + // expected-note {{result of call to 'data' aliases the storage of local variable 'local'}} } void escape_to_field() { { std::string local; view = local; // expected-warning {{stack memory associated with local variable 'local' escapes to the field 'view' which will dangle}} - p = local.data(); // expected-warning {{stack memory associated with local variable 'local' escapes to the field 'p' which will dangle}} + p = local.data(); // expected-warning {{stack memory associated with local variable 'local' escapes to the field 'p' which will dangle}} \ + // expected-note {{result of call to 'data' aliases the storage of local variable 'local'}} } (void)view; // Discarding the value is not a use. (void)p; @@ -256,7 +264,8 @@ struct HasUniquePtrField { std::unique_ptr<LifetimeBoundCtor> field; // tu-note {{this field dangles}} void setWithParam(MyObj obj) { - field = std::make_unique<LifetimeBoundCtor>(obj); // tu-warning {{stack memory associated with parameter 'obj' escapes to the field 'field' which will dangle}} + field = std::make_unique<LifetimeBoundCtor>(obj); // tu-warning {{stack memory associated with parameter 'obj' escapes to the field 'field' which will dangle}} \ + // tu-note {{result of call to 'make_unique<MakeUnique::LifetimeBoundCtor, MakeUnique::MyObj &>' aliases the storage of parameter 'obj'}} } }; } // namespace MakeUnique diff --git a/clang/test/Sema/LifetimeSafety/dangling-global.cpp b/clang/test/Sema/LifetimeSafety/dangling-global.cpp index ef00582fb9c122..7a0e03594fff64 100644 --- a/clang/test/Sema/LifetimeSafety/dangling-global.cpp +++ b/clang/test/Sema/LifetimeSafety/dangling-global.cpp @@ -27,7 +27,7 @@ void invoke_function_with_side_effects() { void inlined() { int local; global = &local; // expected-warning {{stack memory associated with local variable 'local' escapes to the global variable 'global_backup' which will dangle}} - global_backup = global; + global_backup = global; // expected-note {{global variable 'global' aliases the storage of local variable 'local'}} global = nullptr; } diff --git a/clang/test/Sema/LifetimeSafety/invalidations.cpp b/clang/test/Sema/LifetimeSafety/invalidations.cpp index a7c62852c69892..95d33ad0a9c64e 100644 --- a/clang/test/Sema/LifetimeSafety/invalidations.cpp +++ b/clang/test/Sema/LifetimeSafety/invalidations.cpp @@ -578,7 +578,8 @@ struct SinkOwnerBorrow { struct SinkInteriorBorrow { const char *dest_; // expected-note {{this field dangles}} - SinkInteriorBorrow(std::string *dest, int n) : dest_(dest->data()) { // expected-warning {{parameter 'dest' escapes to the field 'dest_' and is later invalidated}} + SinkInteriorBorrow(std::string *dest, int n) : dest_(dest->data()) { // expected-warning {{parameter 'dest' escapes to the field 'dest_' and is later invalidated}} \ + // expected-note {{result of call to 'data' aliases the storage of parameter 'dest'}} if (n > 0) dest->clear(); // expected-note {{parameter 'dest' is invalidated here}} } @@ -596,12 +597,16 @@ struct S { void InvalidatedFieldLocalVector() { std::vector<std::string> strings; - FieldFromLocalVector = *strings.begin(); // expected-warning {{local variable 'strings' escapes to the field 'FieldFromLocalVector' and is later invalidated}} + FieldFromLocalVector = *strings.begin(); // expected-warning {{local variable 'strings' escapes to the field 'FieldFromLocalVector' and is later invalidated}} \ + // expected-note {{result of call to 'begin' aliases the storage of local variable 'strings'}} \ + // expected-note {{expression aliases the storage of local variable 'strings'}} strings.push_back("1"); // expected-note {{local variable 'strings' is invalidated here}} } void InvalidatedFieldByValueParamVector(std::vector<std::string> strings) { - FieldFromByValueParamVector = *strings.begin(); // expected-warning {{parameter 'strings' escapes to the field 'FieldFromByValueParamVector' and is later invalidated}} + FieldFromByValueParamVector = *strings.begin(); // expected-warning {{parameter 'strings' escapes to the field 'FieldFromByValueParamVector' and is later invalidated}} \ + // expected-note {{result of call to 'begin' aliases the storage of parameter 'strings'}} \ + // expected-note {{expression aliases the storage of parameter 'strings'}} strings.push_back("1"); // expected-note {{parameter 'strings' is invalidated here}} } @@ -623,7 +628,7 @@ struct S { void InvalidatedFieldDelete() { int *p = new int; // expected-warning {{allocated object escapes to the field 'FieldFromNew' and is later invalidated}} - FieldFromNew = p; + FieldFromNew = p; // expected-note {{local variable 'p' aliases the storage of allocated object}} delete p; // expected-note {{allocated object is freed here}} } @@ -656,7 +661,9 @@ struct S { void InvalidatedGlobalLocalVector() { std::vector<std::string> strings; - GlobalFromLocalVector = *strings.begin(); // expected-warning {{local variable 'strings' escapes to the global variable 'GlobalFromLocalVector' and is later invalidated}} + GlobalFromLocalVector = *strings.begin(); // expected-warning {{local variable 'strings' escapes to the global variable 'GlobalFromLocalVector' and is later invalidated}} \ + // expected-note {{result of call to 'begin' aliases the storage of local variable 'strings'}} \ + // expected-note {{expression aliases the storage of local variable 'strings'}} strings.push_back("1"); // expected-note {{local variable 'strings' is invalidated here}} } @@ -672,7 +679,7 @@ void InvalidatedGlobalRefParamString(std::string &s) { // expected-warning {{par void InvalidatedGlobalDelete() { int *p = new int; // expected-warning {{allocated object escapes to the global variable 'GlobalFromNew' and is later invalidated}} - GlobalFromNew = p; + GlobalFromNew = p; // expected-note {{local variable 'p' aliases the storage of allocated object}} delete p; // expected-note {{allocated object is freed here}} } diff --git a/clang/test/Sema/LifetimeSafety/nocfg.cpp b/clang/test/Sema/LifetimeSafety/nocfg.cpp index addbe9213a0ac2..405312b35eff45 100644 --- a/clang/test/Sema/LifetimeSafety/nocfg.cpp +++ b/clang/test/Sema/LifetimeSafety/nocfg.cpp @@ -374,8 +374,10 @@ const char *trackThroughMultiplePointer() { struct X { X(std::unique_ptr<int> up) : - pointee(*up), // cfg-warning {{may have been moved.}} - pointee2(up.get()), // cfg-warning {{may have been moved.}} + pointee(*up), // cfg-warning {{may have been moved.}} \ + // cfg-note {{expression aliases the storage of parameter 'up'}} + pointee2(up.get()), // cfg-warning {{may have been moved.}} \ + // cfg-note {{result of call to 'get' aliases the storage of parameter 'up'}} pointer(std::move(up)) {} // cfg-note 2 {{potentially moved here}} int &pointee; // cfg-note {{this field dangles}} int *pointee2; // cfg-note {{this field dangles}} @@ -389,7 +391,8 @@ struct X2 { // A common usage that moves the passing owner to the class. // verify a strict warning on this case. X2(XOwner owner) : - pointee(owner.get()), // cfg-warning {{may have been moved.}} + pointee(owner.get()), // cfg-warning {{may have been moved.}} \ + // cfg-note {{result of call to 'get' aliases the storage of parameter 'owner'}} owner(std::move(owner)) {} // cfg-note {{potentially moved here}} int* pointee; // cfg-note {{this field dangles}} XOwner owner; @@ -610,10 +613,12 @@ FooView test3(int i, std::optional<Foo> a) { return *a; // expected-warning {{address of stack memory}} \ // cfg-note {{result of call to 'operator*' aliases the storage of parameter 'a' because the implicit object parameter is inferred as lifetimebound}} \ // cfg-warning {{stack memory associated with parameter 'a' is returned}} \ + // cfg-note {{expression aliases the storage of parameter 'a'}} \ // cfg-note {{returned here}} return a.value(); // expected-warning {{address of stack memory}} \ // cfg-note {{result of call to 'value' aliases the storage of parameter 'a' because the implicit object parameter is inferred as lifetimebound}} \ // cfg-warning {{stack memory associated with parameter 'a' is returned}} \ + // cfg-note {{result of call to 'value' aliases the storage of parameter 'a'}} \ // cfg-note {{returned here}} } } // namespace GH93386 @@ -1197,7 +1202,8 @@ struct Foo2 { }; struct Test { - Test(Foo2 foo) : bar(foo.bar.get()), // cfg-warning-re {{stack memory associated with parameter 'foo' may escape to the field 'bar' which will dangle. {{.*}} may have been moved}} + Test(Foo2 foo) : bar(foo.bar.get()), // cfg-warning-re {{stack memory associated with parameter 'foo' may escape to the field 'bar' which will dangle. {{.*}} may have been moved}} \ + // cfg-note {{result of call to 'get' aliases the storage of parameter 'foo'}} storage(std::move(foo.bar)) {}; // cfg-note {{potentially moved here}} Bar* bar; // cfg-note {{this field dangles}} diff --git a/clang/test/Sema/LifetimeSafety/safety-c.c b/clang/test/Sema/LifetimeSafety/safety-c.c index 8e6ca521c18046..ed0b9e21eb53ee 100644 --- a/clang/test/Sema/LifetimeSafety/safety-c.c +++ b/clang/test/Sema/LifetimeSafety/safety-c.c @@ -181,7 +181,8 @@ void *void_pointer_dereference(void) { int *atomic_pointer_declref(void) { int value; _Atomic(int *) p = &value; // expected-warning {{stack memory associated with local variable 'value' is returned}} - return p; // expected-note {{returned here}} + return p; // expected-note {{returned here}} \ + // expected-note {{local variable 'p' aliases the storage of local variable 'value'}} } int *atomic_pointer_static(void) { @@ -193,7 +194,8 @@ int *atomic_pointer_static(void) { int **atomic_pointer_multilevel(void) { int *inner; _Atomic(int **) p = &inner; // expected-warning {{stack memory associated with local variable 'inner' is returned}} - return p; // expected-note {{returned here}} + return p; // expected-note {{returned here}} \ + // expected-note {{local variable 'p' aliases the storage of local variable 'inner'}} } // In C, a pointer compound assignment is a prvalue; its result still carries diff --git a/clang/test/Sema/LifetimeSafety/safety.cpp b/clang/test/Sema/LifetimeSafety/safety.cpp index 18800830cb59f4..9ded44f6a720f6 100644 --- a/clang/test/Sema/LifetimeSafety/safety.cpp +++ b/clang/test/Sema/LifetimeSafety/safety.cpp @@ -530,7 +530,8 @@ View conditional_assign_both_branches(const MyObj& safe, bool c) { else { p = safe; } - return p; // expected-note {{returned here}} + return p; // expected-note {{returned here}} \ + // expected-note {{local variable 'p' aliases the storage of local variable 's'}} } @@ -538,7 +539,8 @@ View reassign_safe_to_local(const MyObj& safe) { MyObj local; View p = safe; p = local; // expected-warning {{stack memory associated with local variable 'local' is returned}} - return p; // expected-note {{returned here}} + return p; // expected-note {{returned here}} \ + // expected-note {{local variable 'p' aliases the storage of local variable 'local'}} } View pointer_chain_to_local() { @@ -554,11 +556,13 @@ View multiple_assign_multiple_return(const MyObj& safe, bool c1, bool c2) { View p; if (c1) { p = local1; // expected-warning {{stack memory associated with local variable 'local1' is returned}} - return p; // expected-note {{returned here}} + return p; // expected-note {{returned here}} \ + // expected-note {{local variable 'p' aliases the storage of local variable 'local1'}} } else if (c2) { p = local2; // expected-warning {{stack memory associated with local variable 'local2' is returned}} - return p; // expected-note {{returned here}} + return p; // expected-note {{returned here}} \ + // expected-note {{local variable 'p' aliases the storage of local variable 'local2'}} } p = safe; return p; @@ -577,7 +581,9 @@ View multiple_assign_single_return(const MyObj& safe, bool c1, bool c2) { else { p = safe; } - return p; // expected-note 2 {{returned here}} + return p; // expected-note 2 {{returned here}} \ + // expected-note {{local variable 'p' aliases the storage of local variable 'local1'}} \ + // expected-note {{local variable 'p' aliases the storage of local variable 'local2'}} } View direct_return_of_local() { @@ -645,7 +651,8 @@ const int* return_pointer_to_parameter_via_reference(int a, int b, bool cond) { const int& return_pointer_to_parameter_via_reference_1(int a) { const int* d = &a; // expected-warning {{stack memory associated with parameter 'a' is returned}} - return *d; // expected-note {{returned here}} + return *d; // expected-note {{returned here}} \ + // expected-note {{local variable 'd' aliases the storage of parameter 'a'}} } const int& get_ref_to_local() { @@ -743,7 +750,8 @@ View uar_before_uaf(const MyObj& safe, bool c) { MyObj local_obj; p = local_obj; // expected-warning {{stack memory associated with local variable 'local_obj' is returned}} if (c) { - return p; // expected-note {{returned here}} + return p; // expected-note {{returned here}} \ + // expected-note {{local variable 'p' aliases the storage of local variable 'local_obj'}} } } p.use(); @@ -1973,7 +1981,8 @@ void bar() { namespace DereferenceViews { const MyObj& testDeref(MyObj obj) { View v = obj; // expected-warning {{stack memory associated with parameter 'obj' is returned}} - return *v; // expected-note {{returned here}} + return *v; // expected-note {{returned here}} \ + // expected-note {{local variable 'v' aliases the storage of parameter 'obj'}} } const MyObj* testDerefAddr(MyObj obj) { View v = obj; // expected-warning {{stack memory associated with parameter 'obj' is returned}} @@ -1982,7 +1991,8 @@ const MyObj* testDerefAddr(MyObj obj) { } const MyObj* testData(MyObj obj) { View v = obj; // expected-warning {{stack memory associated with parameter 'obj' is returned}} - return v.data(); // expected-note {{returned here}} + return v.data(); // expected-note {{returned here}} \ + // expected-note {{local variable 'v' aliases the storage of parameter 'obj'}} } const int* testLifetimeboundAccessorOfMyObj(MyObj obj) { View v = obj; // expected-warning {{stack memory associated with parameter 'obj' is returned}} @@ -2293,7 +2303,8 @@ View test1(std::string a) { View test2(std::string a) { View b = View(a); // expected-warning {{stack memory associated with parameter 'a' is returned}} - return b; // expected-note {{returned here}} + return b; // expected-note {{returned here}} \ + // expected-note {{local variable 'b' aliases the storage of parameter 'a'}} } View test3(std::string a) { @@ -2350,7 +2361,8 @@ namespace lambda_captures { auto return_ref_capture() { int local = 1; auto lambda = [&local]() { return local; }; // expected-warning {{stack memory associated with local variable 'local' is returned}} - return lambda; // expected-note {{returned here}} + return lambda; // expected-note {{returned here}} \ + // expected-note {{local variable 'lambda' aliases the storage of local variable 'local'}} } void safe_ref_capture() { @@ -2383,7 +2395,8 @@ auto capture_pointer_by_ref() { MyObj obj; MyObj* p = &obj; auto lambda = [&p]() { return p; }; // expected-warning {{stack memory associated with local variable 'p' is returned}} - return lambda; // expected-note {{returned here}} + return lambda; // expected-note {{returned here}} \ + // expected-note {{local variable 'lambda' aliases the storage of local variable 'p'}} } auto capture_multiple() { @@ -2392,7 +2405,9 @@ auto capture_multiple() { &a, // expected-warning {{stack memory associated with local variable 'a' is returned}} &b // expected-warning {{stack memory associated with local variable 'b' is returned}} ]() { return a + b; }; - return lambda; // expected-note 2 {{returned here}} + return lambda; // expected-note 2 {{returned here}} \ + // expected-note {{local variable 'lambda' aliases the storage of local variable 'a'}} \ + // expected-note {{local variable 'lambda' aliases the storage of local variable 'b'}} } auto capture_raw_pointer_by_value() { @@ -2433,7 +2448,8 @@ auto return_copied_lambda() { auto implicit_ref_capture() { int local = 1; auto lambda = [&]() { return local; }; // expected-warning {{stack memory associated with local variable 'local' is returned}} - return lambda; // expected-note {{returned here}} + return lambda; // expected-note {{returned here}} \ + // expected-note {{local variable 'lambda' aliases the storage of local variable 'local'}} } // TODO: Include the name of the variable in the diagnostic to improve @@ -2442,7 +2458,9 @@ auto implicit_ref_capture() { auto implicit_ref_capture_multiple() { int local = 1, local2 = 2; auto lambda = [&]() { return local + local2; }; // expected-warning {{stack memory associated with local variable 'local2' is returned}} expected-warning {{stack memory associated with local variable 'local' is returned}} - return lambda; // expected-note 2 {{returned here}} + return lambda; // expected-note 2 {{returned here}} \ + // expected-note {{local variable 'lambda' aliases the storage of local variable 'local2'}} \ + // expected-note {{local variable 'lambda' aliases the storage of local variable 'local'}} } auto implicit_value_capture() { @@ -2480,7 +2498,8 @@ auto capture_static_address_by_ref() { static int local = 1; int* p = &local; auto lambda = [&p]() { return p; }; // expected-warning {{stack memory associated with local variable 'p' is returned}} - return lambda; // expected-note {{returned here}} + return lambda; // expected-note {{returned here}} \ + // expected-note {{local variable 'lambda' aliases the storage of local variable 'p'}} } auto capture_multilevel_pointer() { @@ -2885,7 +2904,8 @@ void from_template_instantiation() { struct FieldInitFromLifetimebound { S value; // expected-note {{this field dangles}} - FieldInitFromLifetimebound() : value(getS(std::string("temp"))) {} // expected-warning {{stack memory associated with temporary object escapes to the field 'value' which will dangle}} + FieldInitFromLifetimebound() : value(getS(std::string("temp"))) {} // expected-warning {{stack memory associated with temporary object escapes to the field 'value' which will dangle}} \ + // expected-note {{result of call to 'getS' aliases the storage of temporary object}} }; S S::return_self_after_registration() const { @@ -3117,7 +3137,8 @@ void binary_conditional_throw_void(int *in) { int *binary_conditional_throw_dangling() { int x; int *p = &x; // expected-warning {{stack memory associated with local variable 'x' is returned}} - return p ?: throw 1; // expected-note {{returned here}} + return p ?: throw 1; // expected-note {{returned here}} \ + // expected-note {{local variable 'p' aliases the storage of local variable 'x'}} } #endif @@ -3800,7 +3821,8 @@ std::function<void()> reassign_safe_then_unsafe() { int local = 2; std::function<void()> f = []() { (void)safe; }; f = [&local]() { (void)local; }; // expected-warning {{stack memory associated with local variable 'local' is returned}} - return f; // expected-note {{returned here}} + return f; // expected-note {{returned here}} \ + // expected-note {{local variable 'f' aliases the storage of local variable 'local'}} } std::function<void()> reassign_unsafe_then_safe() { @@ -3973,7 +3995,8 @@ View use_after_return_capture_by() { MyObj a; View res; setCaptureBy(res, a); // expected-warning {{stack memory associated with local variable 'a' is returned}} - return res; // expected-note {{returned here}} + return res; // expected-note {{returned here}} \ + // expected-note {{local variable 'res' aliases the storage of local variable 'a'}} } >From 9ab795024831150873d8fe9c1aac2aa327fc1b43 Mon Sep 17 00:00:00 2001 From: Yuan Suo <[email protected]> Date: Sat, 1 Aug 2026 16:35:44 +0800 Subject: [PATCH 2/5] Align continuation comments Signed-off-by: Yuan Suo <[email protected]> Assisted-by: deepseek-v4-flash --- clang/test/Sema/LifetimeSafety/dangling-global.cpp | 2 +- clang/test/Sema/LifetimeSafety/invalidations.cpp | 2 +- clang/test/Sema/LifetimeSafety/safety.cpp | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/test/Sema/LifetimeSafety/dangling-global.cpp b/clang/test/Sema/LifetimeSafety/dangling-global.cpp index 7a0e03594fff64..3681ae9fcab669 100644 --- a/clang/test/Sema/LifetimeSafety/dangling-global.cpp +++ b/clang/test/Sema/LifetimeSafety/dangling-global.cpp @@ -26,7 +26,7 @@ void invoke_function_with_side_effects() { // We can however catch the inlined one of course! void inlined() { int local; - global = &local; // expected-warning {{stack memory associated with local variable 'local' escapes to the global variable 'global_backup' which will dangle}} + global = &local; // expected-warning {{stack memory associated with local variable 'local' escapes to the global variable 'global_backup' which will dangle}} global_backup = global; // expected-note {{global variable 'global' aliases the storage of local variable 'local'}} global = nullptr; } diff --git a/clang/test/Sema/LifetimeSafety/invalidations.cpp b/clang/test/Sema/LifetimeSafety/invalidations.cpp index 95d33ad0a9c64e..6affbed1958322 100644 --- a/clang/test/Sema/LifetimeSafety/invalidations.cpp +++ b/clang/test/Sema/LifetimeSafety/invalidations.cpp @@ -678,7 +678,7 @@ void InvalidatedGlobalRefParamString(std::string &s) { // expected-warning {{par } void InvalidatedGlobalDelete() { - int *p = new int; // expected-warning {{allocated object escapes to the global variable 'GlobalFromNew' and is later invalidated}} + int *p = new int; // expected-warning {{allocated object escapes to the global variable 'GlobalFromNew' and is later invalidated}} GlobalFromNew = p; // expected-note {{local variable 'p' aliases the storage of allocated object}} delete p; // expected-note {{allocated object is freed here}} } diff --git a/clang/test/Sema/LifetimeSafety/safety.cpp b/clang/test/Sema/LifetimeSafety/safety.cpp index 9ded44f6a720f6..bfbe1e66f61190 100644 --- a/clang/test/Sema/LifetimeSafety/safety.cpp +++ b/clang/test/Sema/LifetimeSafety/safety.cpp @@ -651,8 +651,8 @@ const int* return_pointer_to_parameter_via_reference(int a, int b, bool cond) { const int& return_pointer_to_parameter_via_reference_1(int a) { const int* d = &a; // expected-warning {{stack memory associated with parameter 'a' is returned}} - return *d; // expected-note {{returned here}} \ - // expected-note {{local variable 'd' aliases the storage of parameter 'a'}} + return *d; // expected-note {{returned here}} \ + // expected-note {{local variable 'd' aliases the storage of parameter 'a'}} } const int& get_ref_to_local() { @@ -3942,7 +3942,7 @@ void deref_use_after_scope() { namespace GH191954 { int* return_moved_pointer() { int x; - int* f = &x; // expected-warning {{stack memory associated with local variable 'x' is returned}} + int* f = &x; // expected-warning {{stack memory associated with local variable 'x' is returned}} int* a; a = std::move(f); // expected-note {{result of call to 'move<int *&>' aliases the storage of local variable 'x'}} return a; // expected-note {{returned here}} >From 312b2f5b135b860ee9795eddeba282bd252072a8 Mon Sep 17 00:00:00 2001 From: Yuan Suo <[email protected]> Date: Sat, 22 Aug 2026 16:34:54 +0800 Subject: [PATCH 3/5] Rebase and resolve some conflicts Signed-off-by: Yuan Suo <[email protected]> --- clang/test/Sema/LifetimeSafety/capture-by.cpp | 2 +- .../Sema/LifetimeSafety/explicit-object-param-no-crash.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/clang/test/Sema/LifetimeSafety/capture-by.cpp b/clang/test/Sema/LifetimeSafety/capture-by.cpp index 99924bed821457..8331c6a5437d4a 100644 --- a/clang/test/Sema/LifetimeSafety/capture-by.cpp +++ b/clang/test/Sema/LifetimeSafety/capture-by.cpp @@ -196,7 +196,7 @@ void temporary_pointer_lifetimebound_capture() { } void temporary_nested_lifetimebound_capture() { - capturePointer(getLifetimeBoundPointer(*getLifetimeBoundPointer( + capturePointer(getLifetimeBoundPointer(*getLifetimeBoundPointer( // cfg-note 2 {{result of call to 'getLifetimeBoundPointer' aliases the storage of temporary object because parameter 's' is lifetimebound}} std::string())), x); // expected-warning {{object whose reference is captured by 'x' will be destroyed at the end of the full-expression}} \ // cfg-warning {{stack memory associated with temporary object escapes to the global variable 'x' which will dangle}} } diff --git a/clang/test/Sema/LifetimeSafety/explicit-object-param-no-crash.cpp b/clang/test/Sema/LifetimeSafety/explicit-object-param-no-crash.cpp index 31c07d9d7f1028..4437ba773ffffc 100644 --- a/clang/test/Sema/LifetimeSafety/explicit-object-param-no-crash.cpp +++ b/clang/test/Sema/LifetimeSafety/explicit-object-param-no-crash.cpp @@ -78,14 +78,16 @@ const int *t1(Holder h) { const int *ptr = h.borrow(); // expected-warning {{stack memory associated with parameter 'h' is returned}} \ // expected-note {{result of call to 'borrow' aliases the storage of parameter 'h' because the implicit object parameter is marked as lifetimebound}} static_cast<Holder &&>(h).consume(); - return ptr; // expected-note {{returned here}} + return ptr; // expected-note {{returned here}} \ + // expected-note {{local variable 'ptr' aliases the storage of parameter 'h'}} } const int *t2(Holder h) { const int *ptr = h.borrow(); // expected-warning {{stack memory associated with parameter 'h' is returned}} \ // expected-note {{result of call to 'borrow' aliases the storage of parameter 'h' because the implicit object parameter is marked as lifetimebound}} std::move(h).consume(); - return ptr; // expected-note {{returned here}} + return ptr; // expected-note {{returned here}} \ + // expected-note {{local variable 'ptr' aliases the storage of parameter 'h'}} } struct Set { >From 54a3e2e7317cf56e6aae9254dea33ff6c8086893 Mon Sep 17 00:00:00 2001 From: Yuan Suo <[email protected]> Date: Sun, 30 Aug 2026 10:55:18 +0800 Subject: [PATCH 4/5] Align something Signed-off-by: Yuan Suo <[email protected]> --- .../LifetimeSafety/annotation-suggestions.cpp | 22 +++---- .../Sema/LifetimeSafety/invalidations.cpp | 10 ++-- clang/test/Sema/LifetimeSafety/safety.cpp | 60 +++++++++---------- 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp b/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp index 3769710c489886..2ca3a94f41b7ac 100644 --- a/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp +++ b/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp @@ -528,8 +528,8 @@ struct CaptureRefToView { CaptureRefToView test_ref_to_view() { MyObj obj; CaptureRefToView x(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} - return x; // expected-note {{returned here}} \ - // expected-note {{local variable 'x' aliases the storage of local variable 'obj'}} + return x; // expected-note {{returned here}} \ + // expected-note {{local variable 'x' aliases the storage of local variable 'obj'}} } struct CaptureRefToPtr { @@ -540,8 +540,8 @@ struct CaptureRefToPtr { CaptureRefToPtr test_ref_to_ptr() { MyObj obj; CaptureRefToPtr x(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} - return x; // expected-note {{returned here}} \ - // expected-note {{local variable 'x' aliases the storage of local variable 'obj'}} + return x; // expected-note {{returned here}} \ + // expected-note {{local variable 'x' aliases the storage of local variable 'obj'}} } struct CaptureViewToView { @@ -551,7 +551,7 @@ struct CaptureViewToView { CaptureViewToView test_view_to_view() { MyObj obj; - View v(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} + View v(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} CaptureViewToView x(v); // expected-note {{local variable 'v' aliases the storage of local variable 'obj'}} return x; // expected-note {{returned here}} } @@ -564,8 +564,8 @@ struct CapturePtrToPtr { CapturePtrToPtr test_ptr_to_ptr() { MyObj obj; CapturePtrToPtr x(&obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} - return x; // expected-note {{returned here}} \ - // expected-note {{local variable 'x' aliases the storage of local variable 'obj'}} + return x; // expected-note {{returned here}} \ + // expected-note {{local variable 'x' aliases the storage of local variable 'obj'}} } struct CaptureRefToRef { @@ -576,8 +576,8 @@ struct CaptureRefToRef { CaptureRefToRef test_ref_to_ref() { MyObj obj; CaptureRefToRef x(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} - return x; // expected-note {{returned here}} \ - // expected-note {{local variable 'x' aliases the storage of local variable 'obj'}} + return x; // expected-note {{returned here}} \ + // expected-note {{local variable 'x' aliases the storage of local variable 'obj'}} } struct BaseWithView { @@ -592,8 +592,8 @@ struct CaptureRefToBaseView : BaseWithView { CaptureRefToBaseView test_ref_to_base_view() { MyObj obj; CaptureRefToBaseView x(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} - return x; // expected-note {{returned here}} \ - // expected-note {{local variable 'x' aliases the storage of local variable 'obj'}} + return x; // expected-note {{returned here}} \ + // expected-note {{local variable 'x' aliases the storage of local variable 'obj'}} } } // namespace capturing_constructor diff --git a/clang/test/Sema/LifetimeSafety/invalidations.cpp b/clang/test/Sema/LifetimeSafety/invalidations.cpp index 6affbed1958322..af09676981d0db 100644 --- a/clang/test/Sema/LifetimeSafety/invalidations.cpp +++ b/clang/test/Sema/LifetimeSafety/invalidations.cpp @@ -600,14 +600,14 @@ struct S { FieldFromLocalVector = *strings.begin(); // expected-warning {{local variable 'strings' escapes to the field 'FieldFromLocalVector' and is later invalidated}} \ // expected-note {{result of call to 'begin' aliases the storage of local variable 'strings'}} \ // expected-note {{expression aliases the storage of local variable 'strings'}} - strings.push_back("1"); // expected-note {{local variable 'strings' is invalidated here}} + strings.push_back("1"); // expected-note {{local variable 'strings' is invalidated here}} } void InvalidatedFieldByValueParamVector(std::vector<std::string> strings) { FieldFromByValueParamVector = *strings.begin(); // expected-warning {{parameter 'strings' escapes to the field 'FieldFromByValueParamVector' and is later invalidated}} \ // expected-note {{result of call to 'begin' aliases the storage of parameter 'strings'}} \ // expected-note {{expression aliases the storage of parameter 'strings'}} - strings.push_back("1"); // expected-note {{parameter 'strings' is invalidated here}} + strings.push_back("1"); // expected-note {{parameter 'strings' is invalidated here}} } void InvalidatedFieldLocalString() { @@ -629,7 +629,7 @@ struct S { void InvalidatedFieldDelete() { int *p = new int; // expected-warning {{allocated object escapes to the field 'FieldFromNew' and is later invalidated}} FieldFromNew = p; // expected-note {{local variable 'p' aliases the storage of allocated object}} - delete p; // expected-note {{allocated object is freed here}} + delete p; // expected-note {{allocated object is freed here}} } void InvalidatedFieldDeleteParam(int *p) { // expected-warning {{parameter 'p' escapes to the field 'FieldFromPointerParam' and is later invalidated}} @@ -664,7 +664,7 @@ void InvalidatedGlobalLocalVector() { GlobalFromLocalVector = *strings.begin(); // expected-warning {{local variable 'strings' escapes to the global variable 'GlobalFromLocalVector' and is later invalidated}} \ // expected-note {{result of call to 'begin' aliases the storage of local variable 'strings'}} \ // expected-note {{expression aliases the storage of local variable 'strings'}} - strings.push_back("1"); // expected-note {{local variable 'strings' is invalidated here}} + strings.push_back("1"); // expected-note {{local variable 'strings' is invalidated here}} } void InvalidatedGlobalByValueParamString(std::string s) { @@ -680,7 +680,7 @@ void InvalidatedGlobalRefParamString(std::string &s) { // expected-warning {{par void InvalidatedGlobalDelete() { int *p = new int; // expected-warning {{allocated object escapes to the global variable 'GlobalFromNew' and is later invalidated}} GlobalFromNew = p; // expected-note {{local variable 'p' aliases the storage of allocated object}} - delete p; // expected-note {{allocated object is freed here}} + delete p; // expected-note {{allocated object is freed here}} } void InvalidatedGlobalDeleteParam(int *p) { // expected-warning {{parameter 'p' escapes to the global variable 'GlobalFromPointerParam' and is later invalidated}} diff --git a/clang/test/Sema/LifetimeSafety/safety.cpp b/clang/test/Sema/LifetimeSafety/safety.cpp index bfbe1e66f61190..2abd81eb2b0bc8 100644 --- a/clang/test/Sema/LifetimeSafety/safety.cpp +++ b/clang/test/Sema/LifetimeSafety/safety.cpp @@ -1642,7 +1642,7 @@ View range_based_for_use_after_return() { MyObjStorage s; for (const MyObj &o : s) { // expected-warning {{stack memory associated with local variable 's' is returned}} \ // expected-note {{local variable '__range1' aliases the storage of local variable 's'}} - return o; // expected-note {{returned here}} + return o; // expected-note {{returned here}} } return *s.begin(); // expected-warning {{stack memory associated with local variable 's' is returned}} \ // expected-note {{result of call to 'begin' aliases the storage of local variable 's' because the implicit object parameter is marked as lifetimebound}} \ @@ -1995,7 +1995,7 @@ const MyObj* testData(MyObj obj) { // expected-note {{local variable 'v' aliases the storage of parameter 'obj'}} } const int* testLifetimeboundAccessorOfMyObj(MyObj obj) { - View v = obj; // expected-warning {{stack memory associated with parameter 'obj' is returned}} + View v = obj; // expected-warning {{stack memory associated with parameter 'obj' is returned}} const MyObj* ptr = v.data(); // expected-note {{local variable 'v' aliases the storage of parameter 'obj'}} \ // expected-note {{result of call to 'data' aliases the storage of parameter 'obj' because the implicit object parameter is inferred as lifetimebound}} return ptr->getData(); // expected-note {{returned here}} @@ -2361,8 +2361,8 @@ namespace lambda_captures { auto return_ref_capture() { int local = 1; auto lambda = [&local]() { return local; }; // expected-warning {{stack memory associated with local variable 'local' is returned}} - return lambda; // expected-note {{returned here}} \ - // expected-note {{local variable 'lambda' aliases the storage of local variable 'local'}} + return lambda; // expected-note {{returned here}} \ + // expected-note {{local variable 'lambda' aliases the storage of local variable 'local'}} } void safe_ref_capture() { @@ -2379,7 +2379,7 @@ auto capture_int_by_value() { auto capture_view_by_value() { MyObj obj; - View v(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} + View v(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} auto lambda = [v]() { return v; }; // expected-note {{local variable 'v' aliases the storage of local variable 'obj'}} return lambda; // expected-note {{returned here}} } @@ -2395,8 +2395,8 @@ auto capture_pointer_by_ref() { MyObj obj; MyObj* p = &obj; auto lambda = [&p]() { return p; }; // expected-warning {{stack memory associated with local variable 'p' is returned}} - return lambda; // expected-note {{returned here}} \ - // expected-note {{local variable 'lambda' aliases the storage of local variable 'p'}} + return lambda; // expected-note {{returned here}} \ + // expected-note {{local variable 'lambda' aliases the storage of local variable 'p'}} } auto capture_multiple() { @@ -2412,28 +2412,28 @@ auto capture_multiple() { auto capture_raw_pointer_by_value() { int x; - int* p = &x; // expected-warning {{stack memory associated with local variable 'x' is returned}} + int* p = &x; // expected-warning {{stack memory associated with local variable 'x' is returned}} auto lambda = [p]() { return p; }; // expected-note {{local variable 'p' aliases the storage of local variable 'x'}} return lambda; // expected-note {{returned here}} } auto capture_raw_pointer_init_capture() { int x; - int* p = &x; // expected-warning {{stack memory associated with local variable 'x' is returned}} + int* p = &x; // expected-warning {{stack memory associated with local variable 'x' is returned}} auto lambda = [q = p]() { return q; }; // expected-note {{local variable 'p' aliases the storage of local variable 'x'}} return lambda; // expected-note {{returned here}} } auto capture_view_init_capture() { MyObj obj; - View v(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} + View v(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} auto lambda = [w = v]() { return w; }; // expected-note {{local variable 'v' aliases the storage of local variable 'obj'}} return lambda; // expected-note {{returned here}} } auto capture_lambda() { int x; - auto inner = [&x]() { return x; }; // expected-warning {{stack memory associated with local variable 'x' is returned}} + auto inner = [&x]() { return x; }; // expected-warning {{stack memory associated with local variable 'x' is returned}} auto outer = [inner]() { return inner(); }; // expected-note {{local variable 'inner' aliases the storage of local variable 'x'}} return outer; // expected-note {{returned here}} } @@ -2448,8 +2448,8 @@ auto return_copied_lambda() { auto implicit_ref_capture() { int local = 1; auto lambda = [&]() { return local; }; // expected-warning {{stack memory associated with local variable 'local' is returned}} - return lambda; // expected-note {{returned here}} \ - // expected-note {{local variable 'lambda' aliases the storage of local variable 'local'}} + return lambda; // expected-note {{returned here}} \ + // expected-note {{local variable 'lambda' aliases the storage of local variable 'local'}} } // TODO: Include the name of the variable in the diagnostic to improve @@ -2458,14 +2458,14 @@ auto implicit_ref_capture() { auto implicit_ref_capture_multiple() { int local = 1, local2 = 2; auto lambda = [&]() { return local + local2; }; // expected-warning {{stack memory associated with local variable 'local2' is returned}} expected-warning {{stack memory associated with local variable 'local' is returned}} - return lambda; // expected-note 2 {{returned here}} \ - // expected-note {{local variable 'lambda' aliases the storage of local variable 'local2'}} \ - // expected-note {{local variable 'lambda' aliases the storage of local variable 'local'}} + return lambda; // expected-note 2 {{returned here}} \ + // expected-note {{local variable 'lambda' aliases the storage of local variable 'local2'}} \ + // expected-note {{local variable 'lambda' aliases the storage of local variable 'local'}} } auto implicit_value_capture() { MyObj obj; - View v(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} + View v(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} auto lambda = [=]() { return v; }; // expected-note {{local variable 'v' aliases the storage of local variable 'obj'}} return lambda; // expected-note {{returned here}} } @@ -2498,15 +2498,15 @@ auto capture_static_address_by_ref() { static int local = 1; int* p = &local; auto lambda = [&p]() { return p; }; // expected-warning {{stack memory associated with local variable 'p' is returned}} - return lambda; // expected-note {{returned here}} \ - // expected-note {{local variable 'lambda' aliases the storage of local variable 'p'}} + return lambda; // expected-note {{returned here}} \ + // expected-note {{local variable 'lambda' aliases the storage of local variable 'p'}} } auto capture_multilevel_pointer() { int x; - int *p = &x; // expected-warning {{stack memory associated with local variable 'x' is returned}} - int **q = &p; // expected-warning {{stack memory associated with local variable 'p' is returned}} - int ***r = &q; // expected-warning {{stack memory associated with local variable 'q' is returned}} + int *p = &x; // expected-warning {{stack memory associated with local variable 'x' is returned}} + int **q = &p; // expected-warning {{stack memory associated with local variable 'p' is returned}} + int ***r = &q; // expected-warning {{stack memory associated with local variable 'q' is returned}} auto lambda = [=]() { return *p + **q + ***r; }; // expected-note {{local variable 'p' aliases the storage of local variable 'x'}} \ // expected-note {{local variable 'r' aliases the storage of local variable 'q'}} \ // expected-note {{local variable 'q' aliases the storage of local variable 'p'}} @@ -3136,7 +3136,7 @@ void binary_conditional_throw_void(int *in) { int *binary_conditional_throw_dangling() { int x; - int *p = &x; // expected-warning {{stack memory associated with local variable 'x' is returned}} + int *p = &x; // expected-warning {{stack memory associated with local variable 'x' is returned}} return p ?: throw 1; // expected-note {{returned here}} \ // expected-note {{local variable 'p' aliases the storage of local variable 'x'}} } @@ -3821,8 +3821,8 @@ std::function<void()> reassign_safe_then_unsafe() { int local = 2; std::function<void()> f = []() { (void)safe; }; f = [&local]() { (void)local; }; // expected-warning {{stack memory associated with local variable 'local' is returned}} - return f; // expected-note {{returned here}} \ - // expected-note {{local variable 'f' aliases the storage of local variable 'local'}} + return f; // expected-note {{returned here}} \ + // expected-note {{local variable 'f' aliases the storage of local variable 'local'}} } std::function<void()> reassign_unsafe_then_safe() { @@ -3942,10 +3942,10 @@ void deref_use_after_scope() { namespace GH191954 { int* return_moved_pointer() { int x; - int* f = &x; // expected-warning {{stack memory associated with local variable 'x' is returned}} + int* f = &x; // expected-warning {{stack memory associated with local variable 'x' is returned}} int* a; a = std::move(f); // expected-note {{result of call to 'move<int *&>' aliases the storage of local variable 'x'}} - return a; // expected-note {{returned here}} + return a; // expected-note {{returned here}} } int* return_moved_pointer2() { @@ -3957,7 +3957,7 @@ namespace GH191954 { View return_moved_view() { MyObj o; - View v(o); // expected-warning {{stack memory associated with local variable 'o' is returned}} + View v(o); // expected-warning {{stack memory associated with local variable 'o' is returned}} View v2 = std::move(v); // expected-note {{result of call to 'move<View &>' aliases the storage of local variable 'o'}} return v2; // expected-note {{returned here}} } @@ -3995,8 +3995,8 @@ View use_after_return_capture_by() { MyObj a; View res; setCaptureBy(res, a); // expected-warning {{stack memory associated with local variable 'a' is returned}} - return res; // expected-note {{returned here}} \ - // expected-note {{local variable 'res' aliases the storage of local variable 'a'}} + return res; // expected-note {{returned here}} \ + // expected-note {{local variable 'res' aliases the storage of local variable 'a'}} } >From 84f66d030285c2301eece2217f02119cfee52638 Mon Sep 17 00:00:00 2001 From: Yuan Suo <[email protected]> Date: Sun, 18 Oct 2026 09:35:54 +0800 Subject: [PATCH 5/5] Rebase and resolve some conflicts Signed-off-by: Yuan Suo <[email protected]> --- .../Analyses/LifetimeSafety/LoanPropagation.h | 6 -- .../LifetimeSafety/LoanPropagation.cpp | 9 +-- .../LifetimeSafety/annotation-suggestions.cpp | 18 ++---- clang/test/Sema/LifetimeSafety/capture-by.cpp | 2 +- .../Sema/LifetimeSafety/dangling-global.cpp | 2 +- .../explicit-object-param-no-crash.cpp | 6 +- .../Sema/LifetimeSafety/invalidations.cpp | 13 ++-- clang/test/Sema/LifetimeSafety/nocfg.cpp | 4 +- clang/test/Sema/LifetimeSafety/safety-c.c | 6 +- clang/test/Sema/LifetimeSafety/safety.cpp | 60 ++++++------------- 10 files changed, 39 insertions(+), 87 deletions(-) diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h index d8dffb4fc1a268..d410adb1caef03 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h @@ -57,12 +57,6 @@ class LoanPropagationAnalysis { const LoanID TargetLoan, const CFG *Cfg) const; - /// Like the above, starting from the origin \p OEF lets escape. Empty if it - /// does not hold \p TargetLoan. - llvm::SmallVector<OriginID> buildOriginFlowChain(const OriginEscapesFact *OEF, - const LoanID TargetLoan, - const CFG *Cfg) const; - private: class Impl; std::unique_ptr<Impl> PImpl; diff --git a/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp b/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp index 7db184a09a41e0..4f3ee8c7dab8a7 100644 --- a/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp +++ b/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp @@ -356,14 +356,7 @@ llvm::SmallVector<OriginID> LoanPropagationAnalysis::buildOriginFlowChain( if (const auto *UF = llvm::dyn_cast<UseFact>(F)) return PImpl->buildOriginFlowChain(UF, TargetLoan, Cfg); if (const auto *OEF = llvm::dyn_cast<OriginEscapesFact>(F)) - return PImpl->buildOriginFlowChain(OEF, OEF->getEscapedOriginID(), - TargetLoan, Cfg); + return PImpl->buildOriginFlowChain(OEF, TargetLoan, Cfg); llvm_unreachable("Unhandled Fact type"); } -llvm::SmallVector<OriginID> -LoanPropagationAnalysis::buildOriginFlowChain(const OriginEscapesFact *OEF, - const LoanID TargetLoan, - const CFG *Cfg) const { - return PImpl->buildOriginFlowChain(OEF, TargetLoan, Cfg); -} } // namespace clang::lifetimes::internal diff --git a/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp b/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp index 2ca3a94f41b7ac..70ef67ceacd916 100644 --- a/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp +++ b/clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp @@ -528,8 +528,7 @@ struct CaptureRefToView { CaptureRefToView test_ref_to_view() { MyObj obj; CaptureRefToView x(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} - return x; // expected-note {{returned here}} \ - // expected-note {{local variable 'x' aliases the storage of local variable 'obj'}} + return x; // expected-note {{returned here}} } struct CaptureRefToPtr { @@ -540,8 +539,7 @@ struct CaptureRefToPtr { CaptureRefToPtr test_ref_to_ptr() { MyObj obj; CaptureRefToPtr x(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} - return x; // expected-note {{returned here}} \ - // expected-note {{local variable 'x' aliases the storage of local variable 'obj'}} + return x; // expected-note {{returned here}} } struct CaptureViewToView { @@ -564,8 +562,7 @@ struct CapturePtrToPtr { CapturePtrToPtr test_ptr_to_ptr() { MyObj obj; CapturePtrToPtr x(&obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} - return x; // expected-note {{returned here}} \ - // expected-note {{local variable 'x' aliases the storage of local variable 'obj'}} + return x; // expected-note {{returned here}} } struct CaptureRefToRef { @@ -576,8 +573,7 @@ struct CaptureRefToRef { CaptureRefToRef test_ref_to_ref() { MyObj obj; CaptureRefToRef x(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} - return x; // expected-note {{returned here}} \ - // expected-note {{local variable 'x' aliases the storage of local variable 'obj'}} + return x; // expected-note {{returned here}} } struct BaseWithView { @@ -592,8 +588,7 @@ struct CaptureRefToBaseView : BaseWithView { CaptureRefToBaseView test_ref_to_base_view() { MyObj obj; CaptureRefToBaseView x(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} - return x; // expected-note {{returned here}} \ - // expected-note {{local variable 'x' aliases the storage of local variable 'obj'}} + return x; // expected-note {{returned here}} } } // namespace capturing_constructor @@ -665,8 +660,7 @@ struct HasCtorField { HasCtorField test_dangling_field_ctor() { MyObj obj; HasCtorField x(obj); // expected-warning {{stack memory associated with local variable 'obj' is returned}} - return x; // expected-note {{returned here}} \ - // expected-note {{local variable 'x' aliases the storage of local variable 'obj'}} + return x; // expected-note {{returned here}} } struct HasSetterField { diff --git a/clang/test/Sema/LifetimeSafety/capture-by.cpp b/clang/test/Sema/LifetimeSafety/capture-by.cpp index 8331c6a5437d4a..f6bf9d71d4c903 100644 --- a/clang/test/Sema/LifetimeSafety/capture-by.cpp +++ b/clang/test/Sema/LifetimeSafety/capture-by.cpp @@ -196,7 +196,7 @@ void temporary_pointer_lifetimebound_capture() { } void temporary_nested_lifetimebound_capture() { - capturePointer(getLifetimeBoundPointer(*getLifetimeBoundPointer( // cfg-note 2 {{result of call to 'getLifetimeBoundPointer' aliases the storage of temporary object because parameter 's' is lifetimebound}} + capturePointer(getLifetimeBoundPointer(*getLifetimeBoundPointer( // cfg-note 2 {{result of call to 'getLifetimeBoundPointer' aliases the storage of temporary object because parameter 's' is marked as lifetimebound}} std::string())), x); // expected-warning {{object whose reference is captured by 'x' will be destroyed at the end of the full-expression}} \ // cfg-warning {{stack memory associated with temporary object escapes to the global variable 'x' which will dangle}} } diff --git a/clang/test/Sema/LifetimeSafety/dangling-global.cpp b/clang/test/Sema/LifetimeSafety/dangling-global.cpp index 3681ae9fcab669..2013f9479a7842 100644 --- a/clang/test/Sema/LifetimeSafety/dangling-global.cpp +++ b/clang/test/Sema/LifetimeSafety/dangling-global.cpp @@ -27,7 +27,7 @@ void invoke_function_with_side_effects() { void inlined() { int local; global = &local; // expected-warning {{stack memory associated with local variable 'local' escapes to the global variable 'global_backup' which will dangle}} - global_backup = global; // expected-note {{global variable 'global' aliases the storage of local variable 'local'}} + global_backup = global; global = nullptr; } diff --git a/clang/test/Sema/LifetimeSafety/explicit-object-param-no-crash.cpp b/clang/test/Sema/LifetimeSafety/explicit-object-param-no-crash.cpp index 4437ba773ffffc..31c07d9d7f1028 100644 --- a/clang/test/Sema/LifetimeSafety/explicit-object-param-no-crash.cpp +++ b/clang/test/Sema/LifetimeSafety/explicit-object-param-no-crash.cpp @@ -78,16 +78,14 @@ const int *t1(Holder h) { const int *ptr = h.borrow(); // expected-warning {{stack memory associated with parameter 'h' is returned}} \ // expected-note {{result of call to 'borrow' aliases the storage of parameter 'h' because the implicit object parameter is marked as lifetimebound}} static_cast<Holder &&>(h).consume(); - return ptr; // expected-note {{returned here}} \ - // expected-note {{local variable 'ptr' aliases the storage of parameter 'h'}} + return ptr; // expected-note {{returned here}} } const int *t2(Holder h) { const int *ptr = h.borrow(); // expected-warning {{stack memory associated with parameter 'h' is returned}} \ // expected-note {{result of call to 'borrow' aliases the storage of parameter 'h' because the implicit object parameter is marked as lifetimebound}} std::move(h).consume(); - return ptr; // expected-note {{returned here}} \ - // expected-note {{local variable 'ptr' aliases the storage of parameter 'h'}} + return ptr; // expected-note {{returned here}} } struct Set { diff --git a/clang/test/Sema/LifetimeSafety/invalidations.cpp b/clang/test/Sema/LifetimeSafety/invalidations.cpp index af09676981d0db..3d9eb493cfdb43 100644 --- a/clang/test/Sema/LifetimeSafety/invalidations.cpp +++ b/clang/test/Sema/LifetimeSafety/invalidations.cpp @@ -578,8 +578,7 @@ struct SinkOwnerBorrow { struct SinkInteriorBorrow { const char *dest_; // expected-note {{this field dangles}} - SinkInteriorBorrow(std::string *dest, int n) : dest_(dest->data()) { // expected-warning {{parameter 'dest' escapes to the field 'dest_' and is later invalidated}} \ - // expected-note {{result of call to 'data' aliases the storage of parameter 'dest'}} + SinkInteriorBorrow(std::string *dest, int n) : dest_(dest->data()) { // expected-warning {{parameter 'dest' escapes to the field 'dest_' and is later invalidated}} if (n > 0) dest->clear(); // expected-note {{parameter 'dest' is invalidated here}} } @@ -599,14 +598,14 @@ struct S { std::vector<std::string> strings; FieldFromLocalVector = *strings.begin(); // expected-warning {{local variable 'strings' escapes to the field 'FieldFromLocalVector' and is later invalidated}} \ // expected-note {{result of call to 'begin' aliases the storage of local variable 'strings'}} \ - // expected-note {{expression aliases the storage of local variable 'strings'}} + // expected-note {{result of call to 'operator*' aliases the storage of local variable 'strings' because the implicit object parameter is inferred as lifetimebound}} strings.push_back("1"); // expected-note {{local variable 'strings' is invalidated here}} } void InvalidatedFieldByValueParamVector(std::vector<std::string> strings) { FieldFromByValueParamVector = *strings.begin(); // expected-warning {{parameter 'strings' escapes to the field 'FieldFromByValueParamVector' and is later invalidated}} \ // expected-note {{result of call to 'begin' aliases the storage of parameter 'strings'}} \ - // expected-note {{expression aliases the storage of parameter 'strings'}} + // expected-note {{result of call to 'operator*' aliases the storage of parameter 'strings' because the implicit object parameter is inferred as lifetimebound}} strings.push_back("1"); // expected-note {{parameter 'strings' is invalidated here}} } @@ -628,7 +627,7 @@ struct S { void InvalidatedFieldDelete() { int *p = new int; // expected-warning {{allocated object escapes to the field 'FieldFromNew' and is later invalidated}} - FieldFromNew = p; // expected-note {{local variable 'p' aliases the storage of allocated object}} + FieldFromNew = p; delete p; // expected-note {{allocated object is freed here}} } @@ -663,7 +662,7 @@ void InvalidatedGlobalLocalVector() { std::vector<std::string> strings; GlobalFromLocalVector = *strings.begin(); // expected-warning {{local variable 'strings' escapes to the global variable 'GlobalFromLocalVector' and is later invalidated}} \ // expected-note {{result of call to 'begin' aliases the storage of local variable 'strings'}} \ - // expected-note {{expression aliases the storage of local variable 'strings'}} + // expected-note {{result of call to 'operator*' aliases the storage of local variable 'strings' because the implicit object parameter is inferred as lifetimebound}} strings.push_back("1"); // expected-note {{local variable 'strings' is invalidated here}} } @@ -679,7 +678,7 @@ void InvalidatedGlobalRefParamString(std::string &s) { // expected-warning {{par void InvalidatedGlobalDelete() { int *p = new int; // expected-warning {{allocated object escapes to the global variable 'GlobalFromNew' and is later invalidated}} - GlobalFromNew = p; // expected-note {{local variable 'p' aliases the storage of allocated object}} + GlobalFromNew = p; delete p; // expected-note {{allocated object is freed here}} } diff --git a/clang/test/Sema/LifetimeSafety/nocfg.cpp b/clang/test/Sema/LifetimeSafety/nocfg.cpp index 405312b35eff45..82aec5d3b279df 100644 --- a/clang/test/Sema/LifetimeSafety/nocfg.cpp +++ b/clang/test/Sema/LifetimeSafety/nocfg.cpp @@ -375,7 +375,7 @@ const char *trackThroughMultiplePointer() { struct X { X(std::unique_ptr<int> up) : pointee(*up), // cfg-warning {{may have been moved.}} \ - // cfg-note {{expression aliases the storage of parameter 'up'}} + // cfg-note {{result of call to 'operator*' aliases the storage of parameter 'up' because the implicit object parameter is inferred as lifetimebound}} pointee2(up.get()), // cfg-warning {{may have been moved.}} \ // cfg-note {{result of call to 'get' aliases the storage of parameter 'up'}} pointer(std::move(up)) {} // cfg-note 2 {{potentially moved here}} @@ -613,12 +613,10 @@ FooView test3(int i, std::optional<Foo> a) { return *a; // expected-warning {{address of stack memory}} \ // cfg-note {{result of call to 'operator*' aliases the storage of parameter 'a' because the implicit object parameter is inferred as lifetimebound}} \ // cfg-warning {{stack memory associated with parameter 'a' is returned}} \ - // cfg-note {{expression aliases the storage of parameter 'a'}} \ // cfg-note {{returned here}} return a.value(); // expected-warning {{address of stack memory}} \ // cfg-note {{result of call to 'value' aliases the storage of parameter 'a' because the implicit object parameter is inferred as lifetimebound}} \ // cfg-warning {{stack memory associated with parameter 'a' is returned}} \ - // cfg-note {{result of call to 'value' aliases the storage of parameter 'a'}} \ // cfg-note {{returned here}} } } // namespace GH93386 diff --git a/clang/test/Sema/LifetimeSafety/safety-c.c b/clang/test/Sema/LifetimeSafety/safety-c.c index ed0b9e21eb53ee..8e6ca521c18046 100644 --- a/clang/test/Sema/LifetimeSafety/safety-c.c +++ b/clang/test/Sema/LifetimeSafety/safety-c.c @@ -181,8 +181,7 @@ void *void_pointer_dereference(void) { int *atomic_pointer_declref(void) { int value; _Atomic(int *) p = &value; // expected-warning {{stack memory associated with local variable 'value' is returned}} - return p; // expected-note {{returned here}} \ - // expected-note {{local variable 'p' aliases the storage of local variable 'value'}} + return p; // expected-note {{returned here}} } int *atomic_pointer_static(void) { @@ -194,8 +193,7 @@ int *atomic_pointer_static(void) { int **atomic_pointer_multilevel(void) { int *inner; _Atomic(int **) p = &inner; // expected-warning {{stack memory associated with local variable 'inner' is returned}} - return p; // expected-note {{returned here}} \ - // expected-note {{local variable 'p' aliases the storage of local variable 'inner'}} + return p; // expected-note {{returned here}} } // In C, a pointer compound assignment is a prvalue; its result still carries diff --git a/clang/test/Sema/LifetimeSafety/safety.cpp b/clang/test/Sema/LifetimeSafety/safety.cpp index 2abd81eb2b0bc8..63f79324cd8696 100644 --- a/clang/test/Sema/LifetimeSafety/safety.cpp +++ b/clang/test/Sema/LifetimeSafety/safety.cpp @@ -530,8 +530,7 @@ View conditional_assign_both_branches(const MyObj& safe, bool c) { else { p = safe; } - return p; // expected-note {{returned here}} \ - // expected-note {{local variable 'p' aliases the storage of local variable 's'}} + return p; // expected-note {{returned here}} } @@ -539,8 +538,7 @@ View reassign_safe_to_local(const MyObj& safe) { MyObj local; View p = safe; p = local; // expected-warning {{stack memory associated with local variable 'local' is returned}} - return p; // expected-note {{returned here}} \ - // expected-note {{local variable 'p' aliases the storage of local variable 'local'}} + return p; // expected-note {{returned here}} } View pointer_chain_to_local() { @@ -556,13 +554,11 @@ View multiple_assign_multiple_return(const MyObj& safe, bool c1, bool c2) { View p; if (c1) { p = local1; // expected-warning {{stack memory associated with local variable 'local1' is returned}} - return p; // expected-note {{returned here}} \ - // expected-note {{local variable 'p' aliases the storage of local variable 'local1'}} + return p; // expected-note {{returned here}} } else if (c2) { p = local2; // expected-warning {{stack memory associated with local variable 'local2' is returned}} - return p; // expected-note {{returned here}} \ - // expected-note {{local variable 'p' aliases the storage of local variable 'local2'}} + return p; // expected-note {{returned here}} } p = safe; return p; @@ -581,9 +577,7 @@ View multiple_assign_single_return(const MyObj& safe, bool c1, bool c2) { else { p = safe; } - return p; // expected-note 2 {{returned here}} \ - // expected-note {{local variable 'p' aliases the storage of local variable 'local1'}} \ - // expected-note {{local variable 'p' aliases the storage of local variable 'local2'}} + return p; // expected-note 2 {{returned here}} } View direct_return_of_local() { @@ -651,8 +645,7 @@ const int* return_pointer_to_parameter_via_reference(int a, int b, bool cond) { const int& return_pointer_to_parameter_via_reference_1(int a) { const int* d = &a; // expected-warning {{stack memory associated with parameter 'a' is returned}} - return *d; // expected-note {{returned here}} \ - // expected-note {{local variable 'd' aliases the storage of parameter 'a'}} + return *d; // expected-note {{returned here}} } const int& get_ref_to_local() { @@ -750,8 +743,7 @@ View uar_before_uaf(const MyObj& safe, bool c) { MyObj local_obj; p = local_obj; // expected-warning {{stack memory associated with local variable 'local_obj' is returned}} if (c) { - return p; // expected-note {{returned here}} \ - // expected-note {{local variable 'p' aliases the storage of local variable 'local_obj'}} + return p; // expected-note {{returned here}} } } p.use(); @@ -1981,8 +1973,7 @@ void bar() { namespace DereferenceViews { const MyObj& testDeref(MyObj obj) { View v = obj; // expected-warning {{stack memory associated with parameter 'obj' is returned}} - return *v; // expected-note {{returned here}} \ - // expected-note {{local variable 'v' aliases the storage of parameter 'obj'}} + return *v; // expected-note {{returned here}} } const MyObj* testDerefAddr(MyObj obj) { View v = obj; // expected-warning {{stack memory associated with parameter 'obj' is returned}} @@ -1991,8 +1982,7 @@ const MyObj* testDerefAddr(MyObj obj) { } const MyObj* testData(MyObj obj) { View v = obj; // expected-warning {{stack memory associated with parameter 'obj' is returned}} - return v.data(); // expected-note {{returned here}} \ - // expected-note {{local variable 'v' aliases the storage of parameter 'obj'}} + return v.data(); // expected-note {{returned here}} } const int* testLifetimeboundAccessorOfMyObj(MyObj obj) { View v = obj; // expected-warning {{stack memory associated with parameter 'obj' is returned}} @@ -2303,8 +2293,7 @@ View test1(std::string a) { View test2(std::string a) { View b = View(a); // expected-warning {{stack memory associated with parameter 'a' is returned}} - return b; // expected-note {{returned here}} \ - // expected-note {{local variable 'b' aliases the storage of parameter 'a'}} + return b; // expected-note {{returned here}} } View test3(std::string a) { @@ -2361,8 +2350,7 @@ namespace lambda_captures { auto return_ref_capture() { int local = 1; auto lambda = [&local]() { return local; }; // expected-warning {{stack memory associated with local variable 'local' is returned}} - return lambda; // expected-note {{returned here}} \ - // expected-note {{local variable 'lambda' aliases the storage of local variable 'local'}} + return lambda; // expected-note {{returned here}} } void safe_ref_capture() { @@ -2395,8 +2383,7 @@ auto capture_pointer_by_ref() { MyObj obj; MyObj* p = &obj; auto lambda = [&p]() { return p; }; // expected-warning {{stack memory associated with local variable 'p' is returned}} - return lambda; // expected-note {{returned here}} \ - // expected-note {{local variable 'lambda' aliases the storage of local variable 'p'}} + return lambda; // expected-note {{returned here}} } auto capture_multiple() { @@ -2405,9 +2392,7 @@ auto capture_multiple() { &a, // expected-warning {{stack memory associated with local variable 'a' is returned}} &b // expected-warning {{stack memory associated with local variable 'b' is returned}} ]() { return a + b; }; - return lambda; // expected-note 2 {{returned here}} \ - // expected-note {{local variable 'lambda' aliases the storage of local variable 'a'}} \ - // expected-note {{local variable 'lambda' aliases the storage of local variable 'b'}} + return lambda; // expected-note 2 {{returned here}} } auto capture_raw_pointer_by_value() { @@ -2448,8 +2433,7 @@ auto return_copied_lambda() { auto implicit_ref_capture() { int local = 1; auto lambda = [&]() { return local; }; // expected-warning {{stack memory associated with local variable 'local' is returned}} - return lambda; // expected-note {{returned here}} \ - // expected-note {{local variable 'lambda' aliases the storage of local variable 'local'}} + return lambda; // expected-note {{returned here}} } // TODO: Include the name of the variable in the diagnostic to improve @@ -2458,9 +2442,7 @@ auto implicit_ref_capture() { auto implicit_ref_capture_multiple() { int local = 1, local2 = 2; auto lambda = [&]() { return local + local2; }; // expected-warning {{stack memory associated with local variable 'local2' is returned}} expected-warning {{stack memory associated with local variable 'local' is returned}} - return lambda; // expected-note 2 {{returned here}} \ - // expected-note {{local variable 'lambda' aliases the storage of local variable 'local2'}} \ - // expected-note {{local variable 'lambda' aliases the storage of local variable 'local'}} + return lambda; // expected-note 2 {{returned here}} } auto implicit_value_capture() { @@ -2498,8 +2480,7 @@ auto capture_static_address_by_ref() { static int local = 1; int* p = &local; auto lambda = [&p]() { return p; }; // expected-warning {{stack memory associated with local variable 'p' is returned}} - return lambda; // expected-note {{returned here}} \ - // expected-note {{local variable 'lambda' aliases the storage of local variable 'p'}} + return lambda; // expected-note {{returned here}} } auto capture_multilevel_pointer() { @@ -3137,8 +3118,7 @@ void binary_conditional_throw_void(int *in) { int *binary_conditional_throw_dangling() { int x; int *p = &x; // expected-warning {{stack memory associated with local variable 'x' is returned}} - return p ?: throw 1; // expected-note {{returned here}} \ - // expected-note {{local variable 'p' aliases the storage of local variable 'x'}} + return p ?: throw 1; // expected-note {{returned here}} } #endif @@ -3821,8 +3801,7 @@ std::function<void()> reassign_safe_then_unsafe() { int local = 2; std::function<void()> f = []() { (void)safe; }; f = [&local]() { (void)local; }; // expected-warning {{stack memory associated with local variable 'local' is returned}} - return f; // expected-note {{returned here}} \ - // expected-note {{local variable 'f' aliases the storage of local variable 'local'}} + return f; // expected-note {{returned here}} } std::function<void()> reassign_unsafe_then_safe() { @@ -3995,8 +3974,7 @@ View use_after_return_capture_by() { MyObj a; View res; setCaptureBy(res, a); // expected-warning {{stack memory associated with local variable 'a' is returned}} - return res; // expected-note {{returned here}} \ - // expected-note {{local variable 'res' aliases the storage of local variable 'a'}} + return res; // expected-note {{returned here}} } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
