[clang] [clang] Fix the post-filtering heuristic for GSLPointer. (PR #114044)
Utkarsh Saxena via cfe-commits
cfe-commits at lists.llvm.org
Tue Nov 19 05:11:36 PST 2024
================
@@ -793,3 +800,86 @@ void test13() {
}
} // namespace GH100526
+
+namespace LifetimeboundInterleave {
+
+const std::string& Ref(const std::string& abc [[clang::lifetimebound]]);
+
+std::string_view TakeSv(std::string_view abc [[clang::lifetimebound]]);
+std::string_view TakeStrRef(const std::string& abc [[clang::lifetimebound]]);
+std::string_view TakeStr(std::string abc [[clang::lifetimebound]]);
+
+std::string_view test1() {
+ std::string_view t1 = Ref(std::string()); // expected-warning {{object backing}}
+ t1 = Ref(std::string()); // expected-warning {{object backing}}
+ return Ref(std::string()); // expected-warning {{returning address}}
+
+ std::string_view t2 = TakeSv(std::string()); // expected-warning {{object backing}}
+ t2 = TakeSv(std::string()); // expected-warning {{object backing}}
+ return TakeSv(std::string()); // expected-warning {{returning address}}
+
+ std::string_view t3 = TakeStrRef(std::string()); // expected-warning {{temporary}}
+ t3 = TakeStrRef(std::string()); // expected-warning {{object backing}}
+ return TakeStrRef(std::string()); // expected-warning {{returning address}}
+
+
+ std::string_view t4 = TakeStr(std::string());
+ t4 = TakeStr(std::string());
+ return TakeStr(std::string());
+}
+
+template <typename T>
+struct Foo {
+ const T& get() const [[clang::lifetimebound]];
+ const T& getNoLB() const;
+};
+std::string_view test2(Foo<std::string> r1, Foo<std::string_view> r2) {
+ std::string_view t1 = Foo<std::string>().get(); // expected-warning {{object backing}}
+ t1 = Foo<std::string>().get(); // expected-warning {{object backing}}
+ return r1.get(); // expected-warning {{address of stack}}
+
+ std::string_view t2 = Foo<std::string_view>().get();
+ t2 = Foo<std::string_view>().get();
+ return r2.get();
+
+ // no warning on no-LB-annotated method.
+ std::string_view t3 = Foo<std::string>().getNoLB();
+ t3 = Foo<std::string>().getNoLB();
+ return r1.getNoLB();
+}
+
+struct Bar {};
+struct [[gsl::Pointer]] Pointer {
+ Pointer(const Bar & bar [[clang::lifetimebound]]);
+};
+Pointer test3(Bar bar) {
+ Pointer p = Pointer(Bar()); // expected-warning {{temporary}}
+ p = Pointer(Bar()); // expected-warning {{object backing}}
+ return bar; // expected-warning {{address of stack}}
+}
+
+template<typename T>
+struct MySpan {
+ MySpan(const std::vector<T>& v);
+ using iterator = std::iterator<T>;
+ iterator begin() const [[clang::lifetimebound]];
+};
+template <typename T>
+typename MySpan<T>::iterator ReturnFirstIt(const MySpan<T>& v [[clang::lifetimebound]]);
+
+void test4() {
+ std::vector<int> v{1};
+ // MySpan<T> doesn't own any underlying T objects, the pointee object of
+ // the MySpan iterator is still alive when the whole span is destroyed, thus
+ // no diagnostic.
+ const int& t1 = *MySpan<int>(v).begin();
+ const int& t2 = *ReturnFirstIt(MySpan<int>(v));
+ // Ideally, we would diagnose the following case, but due to implementation
+ // constraints, we do not.
+ const int& t4 = *MySpan<int>(std::vector<int>{}).begin();
+
+ auto it1 = MySpan<int>(v).begin(); // expected-warning {{temporary whose address is use}}
----------------
usx95 wrote:
Do you think this is correct behaviour ?
Specially what about when `MySpan` is also a pointer ?
https://github.com/llvm/llvm-project/pull/114044
More information about the cfe-commits
mailing list