[clang] [llvm] [clang] Implement lifetime analysis for lifetime_capture_by(X) (PR #115921)
Haojian Wu via cfe-commits
cfe-commits at lists.llvm.org
Mon Nov 18 05:31:58 PST 2024
================
@@ -3922,16 +3922,41 @@ def LifetimeCaptureByDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
Similar to `lifetimebound`_, the ``lifetime_capture_by(X)`` attribute on a function
-parameter or implicit object parameter indicates that that objects that are referred to
-by that parameter may also be referred to by the capturing entity ``X``.
+parameter or implicit object parameter indicates that objects that are referred to by
+that parameter may also be referred to by a capturing entity ``X``.
+
+Below is a list of types of the parameters and what they're considered to refer to:
+
+- A reference param is considered to refer to its referenced object.
+- A pointer param is considered to refer to its pointee.
+- A ``std::initializer_list<T>`` is considered to refer to its underlying array.
+- Aggregates (arrays and simple ``struct``\s) are considered to refer to all
----------------
hokein wrote:
> Added a captureVector case. Let me know if you wanted something else.
Thanks. Sorry for not being clear earilier -- I was actually thinking of examples involving raw arrays and initializer lists.
For raw arrays, an example using `lifetimebound` might look like this:
```cpp
int* k(int array [[clang::lifetimebound]] [2]);
int* test() {
int array[2];
return k(array); // Dangling: returns a pointer to a stack address
}
```
However, it doesn’t seem feasible to use `lifetimebound_capture_by` for raw arrays because there isn't a way to generate a temporary array within a function call statement.
For initializer lists, the idea is something like:
```cpp
void k(std::initializer_list<int> abc [[clang::lifetime_capture_by(x)]], Set& x);
void test() {
k({1, 2}, x); // Warning: the initializer list might outlive the captured storage
}
```
> I’m planning to add an error check in a follow-up to ensure that the parameter must be a `gsl::Pointer` or a reference type. What are your thoughts on this?
For simple structs, I think the current implementation still works like:
```cpp
struct Foo {
const int& b;
};
int* test(Foo param [[clang::lifetimebound]]);
void capture(Foo param [[clang::lifetime_capture_by(x)]], std::set<Foo>& x);
void example() {
int* b = test(Foo{1}); // Dangling: reference to a temporary constant object
capture(Foo{1}, x); // Warning
}
```
https://github.com/llvm/llvm-project/pull/115921
More information about the cfe-commits
mailing list