diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index fab50fe6768d8..077aace321264 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10999,21 +10999,21 @@ def warn_lifetime_safety_invalidated_global DefaultIgnore; def warn_lifetime_safety_dangling_field - : Warning<"address of stack memory escapes to a field">, + : Warning<"stack memory associated with %0 escapes to the %1 which will dangle">, InGroup, DefaultIgnore; def warn_lifetime_safety_dangling_field_moved - : Warning<"address of stack memory escapes to a field. " + : Warning<"stack memory associated with %0 may escape to the %1 which will dangle. " "This could be a false positive as the storage may have been moved. " "Consider moving first and then aliasing later to resolve the issue">, InGroup, DefaultIgnore; def warn_lifetime_safety_dangling_global - : Warning<"address of stack memory escapes to global or static storage">, + : Warning<"stack memory associated with %0 escapes to the %1 which will dangle">, InGroup, DefaultIgnore; def warn_lifetime_safety_dangling_global_moved - : Warning<"address of stack memory escapes to global or static storage. " + : Warning<"stack memory associated with %0 may escape to the %1 which will dangle. " "This could be a false positive as the storage may have been moved. " "Consider moving first and then aliasing later to resolve the issue">, InGroup, diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h index 2c4cfeab845c9..40b43e439c73f 100644 --- a/clang/lib/Sema/SemaLifetimeSafety.h +++ b/clang/lib/Sema/SemaLifetimeSafety.h @@ -97,9 +97,13 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper { const FieldDecl *DanglingField, const Expr *MovedExpr, SourceLocation ExpiryLoc) override { - S.Diag(IssueExpr->getExprLoc(), - MovedExpr ? diag::warn_lifetime_safety_dangling_field_moved - : diag::warn_lifetime_safety_dangling_field) + unsigned DiagID = MovedExpr + ? diag::warn_lifetime_safety_dangling_field_moved + : diag::warn_lifetime_safety_dangling_field; + + S.Diag(IssueExpr->getExprLoc(), DiagID) + << getDiagSubjectDescription(IssueExpr) + << getDiagSubjectDescription(DanglingField) << IssueExpr->getSourceRange(); if (MovedExpr) S.Diag(MovedExpr->getExprLoc(), diag::note_lifetime_safety_moved_here) @@ -113,9 +117,13 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper { const VarDecl *DanglingGlobal, const Expr *MovedExpr, SourceLocation ExpiryLoc) override { - S.Diag(IssueExpr->getExprLoc(), - MovedExpr ? diag::warn_lifetime_safety_dangling_global_moved - : diag::warn_lifetime_safety_dangling_global) + unsigned DiagID = MovedExpr + ? diag::warn_lifetime_safety_dangling_global_moved + : diag::warn_lifetime_safety_dangling_global; + + S.Diag(IssueExpr->getExprLoc(), DiagID) + << getDiagSubjectDescription(IssueExpr) + << getDiagSubjectDescription(DanglingGlobal) << IssueExpr->getSourceRange(); if (MovedExpr) S.Diag(MovedExpr->getExprLoc(), diag::note_lifetime_safety_moved_here) @@ -404,7 +412,20 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper { std::string getDiagSubjectDescription(const ValueDecl *VD) { std::string Res; llvm::raw_string_ostream OS(Res); - OS << (isa(VD) ? "parameter" : "local variable"); + if (isa(VD)) { + OS << "field"; + } else if (isa(VD)) { + OS << "parameter"; + } else if (const auto *Var = dyn_cast(VD)) { + if (Var->isStaticLocal() || Var->isStaticDataMember()) + OS << "static variable"; + else if (Var->hasGlobalStorage()) + OS << "global variable"; + else + OS << "local variable"; + } else { + OS << "variable"; + } OS << " '"; VD->getNameForDiagnostic(OS, S.getPrintingPolicy(), /*Qualified=*/false); OS << "'"; diff --git a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp index fa9cd33cc2d61..41b07771c52c1 100644 --- a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp +++ b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp @@ -86,13 +86,13 @@ struct DanglingGslPtrField { MyLongPointerFromConversion p2; // expected-note {{pointer member declared here}} \ // cfg-note 2 {{this field dangles}} - DanglingGslPtrField(int i) : p(&i) {} // cfg-warning {{address of stack memory escapes to a field}} + DanglingGslPtrField(int i) : p(&i) {} // cfg-warning {{stack memory associated with parameter 'i' escapes to the field 'p' which will dangle}} DanglingGslPtrField() : p2(MyLongOwnerWithConversion{}) {} // expected-warning {{initializing pointer member 'p2' to point to a temporary object whose lifetime is shorter than the lifetime of the constructed object}} \ - // cfg-warning {{address of stack memory escapes to a field}} + // cfg-warning {{stack memory associated with local temporary object escapes to the field 'p2' which will dangle}} DanglingGslPtrField(double) : p(MyIntOwner{}) {} // expected-warning {{initializing pointer member 'p' to point to a temporary object whose lifetime is shorter than the lifetime of the constructed object}} \ - // cfg-warning {{address of stack memory escapes to a field}} - DanglingGslPtrField(MyIntOwner io) : p(io) {} // cfg-warning {{address of stack memory escapes to a field}} - DanglingGslPtrField(MyLongOwnerWithConversion lo) : p2(lo) {} // cfg-warning {{address of stack memory escapes to a field}} + // cfg-warning {{stack memory associated with local temporary object escapes to the field 'p' which will dangle}} + DanglingGslPtrField(MyIntOwner io) : p(io) {} // cfg-warning {{stack memory associated with parameter 'io' escapes to the field 'p' which will dangle}} + DanglingGslPtrField(MyLongOwnerWithConversion lo) : p2(lo) {} // cfg-warning {{stack memory associated with parameter 'lo' escapes to the field 'p2' which will dangle}} }; MyIntPointer danglingGslPtrFromLocal() { @@ -1124,7 +1124,7 @@ struct Foo2 { }; struct Test { - Test(Foo2 foo) : bar(foo.bar.get()), // cfg-warning-re {{address of stack memory escapes to a field. {{.*}} 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}} storage(std::move(foo.bar)) {}; // cfg-note {{potentially moved here}} Bar* bar; // cfg-note {{this field dangles}} diff --git a/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp b/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp index 5a4de105f217d..cb13f51b41355 100644 --- a/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp +++ b/clang/test/Sema/warn-lifetime-safety-dangling-field.cpp @@ -11,23 +11,23 @@ std::string_view construct_view(const std::string& str [[clang::lifetimebound]]) struct CtorInit { std::string_view view; // expected-note {{this field dangles}} - CtorInit(std::string s) : view(s) {} // expected-warning {{address of stack memory escapes to a field}} + CtorInit(std::string s) : view(s) {} // expected-warning {{stack memory associated with parameter 's' escapes to the field 'view' which will dangle}} }; struct CtorSet { std::string_view view; // expected-note {{this field dangles}} - CtorSet(std::string s) { view = s; } // expected-warning {{address of stack memory escapes to a field}} + CtorSet(std::string s) { view = s; } // expected-warning {{stack memory associated with parameter 's' escapes to the field 'view' which will dangle}} }; struct CtorInitLifetimeBound { std::string_view view; // expected-note {{this field dangles}} - CtorInitLifetimeBound(std::string s) : view(construct_view(s)) {} // expected-warning {{address of stack memory escapes to a field}} + CtorInitLifetimeBound(std::string s) : view(construct_view(s)) {} // expected-warning {{stack memory associated with parameter 's' escapes to the field 'view' which will dangle}} }; struct CtorInitButMoved { std::string_view view; // expected-note {{this field dangles}} CtorInitButMoved(std::string s) - : view(s) { // expected-warning-re {{address of stack memory escapes to a field. {{.*}} may have been moved}} + : view(s) { // expected-warning-re {{stack memory associated with parameter 's' may escape to the field 'view' which will dangle. {{.*}} may have been moved}} takeString(std::move(s)); // expected-note {{potentially moved here}} } }; @@ -36,7 +36,7 @@ struct CtorInitButMovedOwned { std::string_view view; // expected-note {{this field dangles}} std::string owned; CtorInitButMovedOwned(std::string s) - : view(s), // expected-warning-re {{address of stack memory escapes to a field. {{.*}} may have been moved}} + : view(s), // expected-warning-re {{stack memory associated with parameter 's' may escape to the field 'view' which will dangle. {{.*}} may have been moved}} owned(std::move(s)) {} // expected-note {{potentially moved here}} }; @@ -50,28 +50,28 @@ struct CtorInitButMovedOwnedOrderedCorrectly { struct CtorInitMultipleViews { std::string_view view1; // expected-note {{this field dangles}} std::string_view view2; // expected-note {{this field dangles}} - CtorInitMultipleViews(std::string s) : view1(s), // expected-warning {{address of stack memory escapes to a field}} - view2(s) {} // expected-warning {{address of stack memory escapes to a field}} + CtorInitMultipleViews(std::string s) : view1(s), // expected-warning {{stack memory associated with parameter 's' escapes to the field 'view1' which will dangle}} + view2(s) {} // expected-warning {{stack memory associated with parameter 's' escapes to the field 'view2' which will dangle}} }; struct CtorInitMultipleParams { std::string_view view1; // expected-note {{this field dangles}} std::string_view view2; // expected-note {{this field dangles}} - CtorInitMultipleParams(std::string s1, std::string s2) : view1(s1), // expected-warning {{address of stack memory escapes to a field}} - view2(s2) {} // expected-warning {{address of stack memory escapes to a field}} + CtorInitMultipleParams(std::string s1, std::string s2) : view1(s1), // expected-warning {{stack memory associated with parameter 's1' escapes to the field 'view1' which will dangle}} + view2(s2) {} // expected-warning {{stack memory associated with parameter 's2' escapes to the field 'view2' which will dangle}} }; struct CtorRefField { const std::string& str; // expected-note {{this field dangles}} const std::string_view& view; // expected-note {{this field dangles}} - CtorRefField(std::string s, std::string_view v) : str(s), // expected-warning {{address of stack memory escapes to a field}} - view(v) {} // expected-warning {{address of stack memory escapes to a field}} + CtorRefField(std::string s, std::string_view v) : str(s), // expected-warning {{stack memory associated with parameter 's' escapes to the field 'str' which will dangle}} + view(v) {} // expected-warning {{stack memory associated with parameter 'v' escapes to the field 'view' which will dangle}} CtorRefField(Dummy<1> ok, const std::string& s, const std::string_view& v): str(s), view(v) {} }; struct CtorPointerField { const char* ptr; // expected-note {{this field dangles}} - CtorPointerField(std::string s) : ptr(s.data()) {} // expected-warning {{address of stack memory escapes to a field}} + CtorPointerField(std::string s) : ptr(s.data()) {} // expected-warning {{stack memory associated with parameter 's' escapes to the field 'ptr' which will dangle}} CtorPointerField(Dummy<1> ok, const std::string& s) : ptr(s.data()) {} CtorPointerField(Dummy<2> ok, std::string_view view) : ptr(view.data()) {} }; @@ -81,13 +81,13 @@ struct MemberSetters { const char* p; // expected-note 6 {{this field dangles}} void setWithParam(std::string s) { - view = s; // expected-warning {{address of stack memory escapes to a field}} - p = s.data(); // expected-warning {{address of stack memory escapes to a field}} + 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}} } void setWithParamAndReturn(std::string s) { - view = s; // expected-warning {{address of stack memory escapes to a field}} - p = s.data(); // expected-warning {{address of stack memory escapes to a field}} + 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}} return; } @@ -104,14 +104,14 @@ struct MemberSetters { void setWithLocal() { std::string s; - view = s; // expected-warning {{address of stack memory escapes to a field}} - p = s.data(); // expected-warning {{address of stack memory escapes to a field}} + 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}} } void setWithLocalButMoved() { std::string s; - view = s; // expected-warning-re {{address of stack memory escapes to a field. {{.*}} may have been moved}} - p = s.data(); // expected-warning-re {{address of stack memory escapes to a field. {{.*}} may have been moved}} + 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}} takeString(std::move(s)); // expected-note 2 {{potentially moved here}} } @@ -134,15 +134,15 @@ struct MemberSetters { p = kGlobal.data(); std::string local; - view = local; // expected-warning {{address of stack memory escapes to a field}} - p = local.data(); // expected-warning {{address of stack memory escapes to a field}} + 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}} } void use_after_scope() { { std::string local; - view = local; // expected-warning {{address of stack memory escapes to a field}} - p = local.data(); // expected-warning {{address of stack memory escapes to a field}} + 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}} } (void)view; (void)p; @@ -193,7 +193,7 @@ struct BaseWithPointer { struct DerivedWithCtor : BaseWithPointer { DerivedWithCtor(std::string s) { - view = s; // expected-warning {{address of stack memory escapes to a field}} + view = s; // expected-warning {{stack memory associated with parameter 's' escapes to the field 'view' which will dangle}} } }; } // namespace DanglingPointerFieldInBaseClass @@ -205,7 +205,7 @@ struct HasCallback { void set_callback() { int local; - callback = [&local]() { (void)local; }; // expected-warning {{address of stack memory escapes to a field}} + callback = [&local]() { (void)local; }; // expected-warning {{stack memory associated with local variable 'local' escapes to the field 'callback' which will dangle}} } }; @@ -222,7 +222,7 @@ struct HasUniquePtrField { std::unique_ptr field; // tu-note {{this field dangles}} void setWithParam(MyObj obj) { - field = std::make_unique(obj); // tu-warning {{address of stack memory escapes to a field}} + field = std::make_unique(obj); // tu-warning {{stack memory associated with parameter 'obj' escapes to the field 'field' which will dangle}} } }; } // namespace MakeUnique diff --git a/clang/test/Sema/warn-lifetime-safety-dangling-global.cpp b/clang/test/Sema/warn-lifetime-safety-dangling-global.cpp index ac40c7df5a8f5..98f8905d0e2da 100644 --- a/clang/test/Sema/warn-lifetime-safety-dangling-global.cpp +++ b/clang/test/Sema/warn-lifetime-safety-dangling-global.cpp @@ -22,14 +22,14 @@ void invoke_function_with_side_effects() { // We can however catch the inlined one of course! void inlined() { int local; - global = &local; // expected-warning {{address of stack memory escapes to global or static storage}} + 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 = nullptr; } void store_local_in_global() { int local; - global = &local; // expected-warning {{address of stack memory escapes to global or static storage}} + global = &local; // expected-warning {{stack memory associated with local variable 'local' escapes to the global variable 'global' which will dangle}} } void store_then_clear() { @@ -40,5 +40,5 @@ void store_then_clear() { void dangling_static_field() { int local; - ObjWithStaticField::static_field = &local; // expected-warning {{address of stack memory escapes to global or static storage}} -} \ No newline at end of file + ObjWithStaticField::static_field = &local; // expected-warning {{stack memory associated with local variable 'local' escapes to the static variable 'static_field' which will dangle}} +} diff --git a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp index 94b1febbcef93..f5a3cf89e4c8d 100644 --- a/clang/test/Sema/warn-lifetime-safety-suggestions.cpp +++ b/clang/test/Sema/warn-lifetime-safety-suggestions.cpp @@ -665,7 +665,7 @@ struct HasSetterField { } void reset() { MyObj obj; - field = new LifetimeBoundCtor(obj); // expected-warning {{address of stack memory escapes to a field}} + field = new LifetimeBoundCtor(obj); // expected-warning {{stack memory associated with local variable 'obj' escapes to the field 'field' which will dangle}} } }; diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp index 9a8cfe6b61bc0..06097d4600af5 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -2449,7 +2449,7 @@ void from_template_instantiation() { struct FieldInitFromLifetimebound { S value; // expected-note {{this field dangles}} - FieldInitFromLifetimebound() : value(getS(std::string("temp"))) {} // expected-warning {{address of stack memory escapes to a field}} + FieldInitFromLifetimebound() : value(getS(std::string("temp"))) {} // expected-warning {{stack memory associated with local temporary object escapes to the field 'value' which will dangle}} }; S S::return_self_after_registration() const { @@ -2639,12 +2639,12 @@ void nested_local_pointer() { struct PFieldFromParam { Pointer value; // expected-note {{this field dangles}} - PFieldFromParam(Bar bar) : value(bar) {} // expected-warning {{address of stack memory escapes to a field}} + PFieldFromParam(Bar bar) : value(bar) {} // expected-warning {{stack memory associated with parameter 'bar' escapes to the field 'value' which will dangle}} }; struct PFieldFromTemp { Pointer value; // expected-note {{this field dangles}} - PFieldFromTemp() : value(Bar{}) {} // expected-warning {{address of stack memory escapes to a field}} + PFieldFromTemp() : value(Bar{}) {} // expected-warning {{stack memory associated with local temporary object escapes to the field 'value' which will dangle}} }; } // namespace gslpointer_construction_from_lifetimebound @@ -3210,7 +3210,7 @@ struct S2 : S { namespace CXXDefaultInitExprTests { struct Holder { - std::string_view view = std::string("temporary"); // expected-warning {{address of stack memory escapes to a field}} expected-note {{this field dangles}} + std::string_view view = std::string("temporary"); // expected-warning {{stack memory associated with local temporary object escapes to the field 'view' which will dangle}} expected-note {{this field dangles}} Holder() {} }; } // namespace CXXDefaultInitExprTests @@ -3222,7 +3222,7 @@ struct Y : X { void bar() { { int a; - x = &a; // expected-warning {{address of stack memory escapes to a field}} + x = &a; // expected-warning {{stack memory associated with local variable 'a' escapes to the field 'x' which will dangle}} } (void)x; }