[clang] [clang] Don't consider the lifetimeboundCall when analyzing the gsl pointer construction. (PR #114044)
Haojian Wu via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 29 05:58:12 PDT 2024
https://github.com/hokein created https://github.com/llvm/llvm-project/pull/114044
This fixes a bug raised in https://github.com/llvm/llvm-project/pull/112751#issuecomment-2443566707.
>From 32d808a6c30cb572c7905f93b9c14b5d8a25599d Mon Sep 17 00:00:00 2001
From: Haojian Wu <hokein.wu at gmail.com>
Date: Tue, 29 Oct 2024 13:53:35 +0100
Subject: [PATCH] [clang] Don't consider the lifetimeboundCall when analyzing
the gsl pointer construction.
---
clang/lib/Sema/CheckExprLifetime.cpp | 23 +++++++++++-
.../Sema/warn-lifetime-analysis-nocfg.cpp | 37 ++++++++++++++++---
clang/test/SemaCXX/attr-lifetimebound.cpp | 2 +-
3 files changed, 55 insertions(+), 7 deletions(-)
diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp
index aa0a2e223e708f..b19b320fe30228 100644
--- a/clang/lib/Sema/CheckExprLifetime.cpp
+++ b/clang/lib/Sema/CheckExprLifetime.cpp
@@ -1094,6 +1094,24 @@ static bool pathOnlyHandlesGslPointer(IndirectLocalPath &Path) {
return false;
}
+static bool
+isLifetimeboundInterleaveInGSL(llvm::ArrayRef<IndirectLocalPathEntry> PathRef) {
+ if (auto FirstGSLPointer = llvm::find_if(
+ PathRef,
+ [](const IndirectLocalPathEntry &Path) {
+ return Path.Kind == IndirectLocalPathEntry::GslPointerInit ||
+ Path.Kind == IndirectLocalPathEntry::GslPointerAssignment;
+ });
+ FirstGSLPointer != PathRef.end()) {
+ return llvm::find_if(
+ PathRef.drop_front(FirstGSLPointer - PathRef.begin() + 1),
+ [](const IndirectLocalPathEntry &Path) {
+ return Path.Kind == IndirectLocalPathEntry::LifetimeBoundCall;
+ }) != PathRef.end();
+ }
+ return false;
+}
+
static bool isAssignmentOperatorLifetimeBound(CXXMethodDecl *CMD) {
if (!CMD)
return false;
@@ -1141,7 +1159,8 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
// someContainer.add(std::move(localUniquePtr));
// return p;
IsLocalGslOwner = isRecordWithAttr<OwnerAttr>(L->getType());
- if (pathContainsInit(Path) || !IsLocalGslOwner)
+ if (pathContainsInit(Path) || !IsLocalGslOwner ||
+ isLifetimeboundInterleaveInGSL(Path))
return false;
} else {
IsGslPtrValueFromGslTempOwner =
@@ -1152,6 +1171,8 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
// a local or temporary owner or the address of a local variable/param.
if (!IsGslPtrValueFromGslTempOwner)
return true;
+ if (isLifetimeboundInterleaveInGSL(Path))
+ return false;
}
}
diff --git a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
index 688f55edfe84df..b97e34840c0d9b 100644
--- a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
+++ b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
@@ -714,8 +714,8 @@ struct [[gsl::Pointer]] Span {
// Pointer from Owner<Pointer>
std::string_view test5() {
- std::string_view a = StatusOr<std::string_view>().valueLB(); // expected-warning {{object backing the pointer will be dest}}
- return StatusOr<std::string_view>().valueLB(); // expected-warning {{returning address of local temporary}}
+ std::string_view a = StatusOr<std::string_view>().valueLB();
+ return StatusOr<std::string_view>().valueLB();
// No dangling diagnostics on non-lifetimebound methods.
std::string_view b = StatusOr<std::string_view>().valueNoLB();
@@ -746,7 +746,7 @@ std::vector<int*> test8(StatusOr<std::vector<int*>> aa) {
// Pointer<Pointer> from Owner<Owner<Pointer>>
Span<int*> test9(StatusOr<std::vector<int*>> aa) {
- return aa.valueLB(); // expected-warning {{address of stack memory associated}}
+ return aa.valueLB(); //
return aa.valueNoLB(); // OK.
}
@@ -754,7 +754,7 @@ Span<int*> test9(StatusOr<std::vector<int*>> aa) {
// Pointer<Owner>> from Owner<Owner>
Span<std::string> test10(StatusOr<std::vector<std::string>> aa) {
- return aa.valueLB(); // expected-warning {{address of stack memory}}
+ return aa.valueLB(); //
return aa.valueNoLB(); // OK.
}
@@ -762,7 +762,7 @@ Span<std::string> test10(StatusOr<std::vector<std::string>> aa) {
// Pointer<Owner>> from Owner<Pointer<Owner>>
Span<std::string> test11(StatusOr<Span<std::string>> aa) {
- return aa.valueLB(); // expected-warning {{address of stack memory}}
+ return aa.valueLB(); //
return aa.valueNoLB(); // OK.
}
@@ -780,3 +780,30 @@ void test13() {
}
} // namespace GH100526
+
+namespace test {
+
+struct [[gsl::Pointer]] FooOwner {};
+struct [[gsl::Pointer]] FooPointer {
+ FooPointer(const FooOwner&);
+};
+
+template<typename T>
+struct [[gsl::Owner]] Container {
+ const T& get() const [[clang::lifetimebound]];
+};
+
+FooPointer func() {
+ Container<FooPointer> foo;
+
+ FooPointer p = Container<FooPointer>().get();
+ p = Container<FooPointer>().get();
+ return foo.get();
+
+ FooPointer p2 = Container<FooOwner>().get();
+ p2 = Container<FooOwner>().get();
+ Container<FooOwner> foo2;
+ return foo2.get();
+}
+
+}
diff --git a/clang/test/SemaCXX/attr-lifetimebound.cpp b/clang/test/SemaCXX/attr-lifetimebound.cpp
index 804d61fb62ca40..70a80affceda54 100644
--- a/clang/test/SemaCXX/attr-lifetimebound.cpp
+++ b/clang/test/SemaCXX/attr-lifetimebound.cpp
@@ -153,7 +153,7 @@ namespace p0936r0_examples {
void f() {
std::string_view sv = "hi";
std::string_view sv2 = sv + sv; // expected-warning {{temporary}}
- sv2 = sv + sv; // expected-warning {{object backing the pointer}}
+ sv2 = sv + sv; // FIXME: warn here too.
}
struct X { int a, b; };
More information about the cfe-commits
mailing list