Skip to content

Commit 5a6a18f

Browse files
committed
Added draft-lifetimes document
1 parent 4c599c1 commit 5a6a18f

12 files changed

+2098
-2
lines changed

docs/draft-lifetimes.html

+1,323
Large diffs are not rendered by default.

docs/index.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<html>
22
<head>
3-
<meta http-equiv="refresh" content="0; URL=P3390R0.html">
3+
<meta http-equiv="refresh" content="0; URL=draft.html">
44
</head>
55
<body>
66
Automatic redirection failed, please go to
7-
<a href="P3390R0.html">P3390R0.html</a>.
7+
<a href="draft.html">draft.html</a>.
88
</body>
99
</html>

lifetimes/draft-lifetimes.md

+571
Large diffs are not rendered by default.

lifetimes/lifetimes1.cxx

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#feature on safety
2+
3+
// Function parameters have different lifetime parameters.
4+
// Return type is constrained by x's lifetime.
5+
auto f1/(a, b)(int^/a x, int^/b y, bool pred) safe -> int^/a {
6+
// Error:
7+
// function auto f1/(a, b)(int^/a, int^/b) -> int^/a returns
8+
// object with lifetime b, but b doesn't outlive a
9+
// return y;
10+
return pred ? x : y;
11+
}
12+
13+
// Function parameters have a common lifetime parameter.
14+
auto f2/(a)(int^/a x, int^/a y, bool pred) safe -> int^/a {
15+
// Ok
16+
return pred ? x : y;
17+
}
18+
19+
// Error:
20+
// cannot use lifetime elision for return type int^
21+
auto f3(int^ x, int^ y) safe -> int^;

lifetimes/lifetimes2.cxx

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#feature on safety
2+
3+
// New elision rules:
4+
// All parameters are constrained by a common lifetime.
5+
// The common lifetime constrains the return type.
6+
int% f4(int% x, int% y, bool pred) safe {
7+
// Can return either x or y, because they outlive the common lifetime
8+
// and the common lifetime outlives the result object.
9+
return pred ? x : y;
10+
}

lifetimes/lifetimes3.cxx

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#feature on safety
2+
3+
const int% f1(const int% x, const int% y, bool pred) safe {
4+
// The return reference is constrained by all reference parameters: x and y.
5+
return pred ? x : y;
6+
}
7+
8+
struct Obj {
9+
const int% f2(const int% arg) const % safe {
10+
// Non-static member functions are constrained by the implicit
11+
// object lifetime.
12+
// It's OK to return `x`, because self outlives the return.
13+
return %x;
14+
}
15+
16+
const int% f3(const int% arg) const % safe {
17+
// Error: arg does not outlive the return reference.
18+
return arg;
19+
}
20+
21+
const int% f4(const self%, const int% arg) safe {
22+
// OK - f4 is a free function with an explicit self parameter.
23+
return arg;
24+
}
25+
26+
int x;
27+
};
28+
29+
int main() {
30+
int x = 1, y = 2;
31+
f1(x, y, true); // OK
32+
33+
Obj obj { };
34+
obj.f2(x); // OK
35+
obj.f3(x); // Error
36+
obj.f4(x); // OK.
37+
}

lifetimes/lifetimes4.cxx

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#feature on safety

lifetimes/lifetimes5.cxx

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#feature on safety
2+
3+
class string_view/(a) {
4+
// Keep a borrow to a slice over the string data.
5+
const [char; dyn]^/a p_;
6+
public:
7+
};
8+
9+
class info/(a) {
10+
// The handle has lifetime /a.
11+
string_view/a sv;
12+
13+
public:
14+
void swap(self^, info^ rhs) safe {
15+
string_view temp = self->sv;
16+
self->sv = rhs->sv;
17+
rhs->sv = temp;
18+
}
19+
};
20+
21+
void func/(a)(info/a^ lhs, info/a^ rhs) safe {
22+
lhs.swap(rhs);
23+
}
24+
25+
void func2(info^ lhs, info^ rhs) safe {
26+
lhs.swap(rhs);
27+
}

lifetimes/vector1.cxx

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <vector>
2+
3+
void f1(std::vector<float>& vec, float& x) {
4+
// Do vec and x alias? If so, the push_back may invalidate x.
5+
vec.push_back(6);
6+
7+
// Potential UB: x may have been invalidated by the push_back.
8+
x = 6;
9+
}
10+
11+
int main() {
12+
std::vector<float> vec;
13+
vec.push_back(1):
14+
15+
// Legacy references permit aliasing.
16+
f1(vec, vec[0]);
17+
}

lifetimes/vector2.cxx

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#feature on safety
2+
#include <cstdint>
3+
4+
template<typename T>
5+
class Vec {
6+
public:
7+
void push_back(T value) % safe;
8+
9+
const T% operator[](size_t idx) const % safe;
10+
T% operator[](size_t idx) % safe;
11+
};
12+
13+
void f2(Vec<float>% vec, float% x) safe {
14+
// Does push_back potentially invalidate x?
15+
// No! Exclusivity prevents vec and x from aliasing.
16+
vec.push_back(7);
17+
18+
// Okay to store to x, because it doesn't point into vec's data.
19+
*x = 7;
20+
}
21+
22+
int main() safe {
23+
Vec<float> vec { };
24+
mut vec.push_back(1);
25+
26+
// Ill-formed: shared borrow of vec between its mutable borrow and its use
27+
f2(mut vec, mut vec[0]);
28+
}

lifetimes/vector3.cxx

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#feature on safety
2+
3+
template<typename Key, typename Value>
4+
class Map {
5+
public:
6+
// Non-static member functions do not constrain the result object to
7+
// the function parameters.
8+
auto get1(const Key% key) % safe -> Value%;
9+
10+
// Free function do constrain the result object to the f unction praameters.
11+
auto get2(self%, const Key% key) safe -> Value%;
12+
};
13+
14+
int main() safe {
15+
Map<float, long> map { };
16+
17+
// Bind the key reference to a materialized temporary.
18+
// The temporary expires at the end of this statement.
19+
long% value1 = mut map.get1(3.14f);
20+
21+
// We can still access value, because it's not constrained on the
22+
// key argument.
23+
*value1 = 1001;
24+
25+
// The call to get2 constrains the returned reference to the lifetime
26+
// of the key temporary.
27+
long% value2 = mut map.get2(1.6186f);
28+
29+
// This is ill-formed, because get2's key argument is out of scope.
30+
*value2 = 1002;
31+
}

lifetimes/vector4.cxx

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#feature on safety
2+
3+
template<typename Key, typename Value>
4+
class Map {
5+
public:
6+
// Lifetime elision rules constrain the return by self.
7+
auto get1(self^, const Key^ key) safe -> Value^;
8+
9+
// Use explicit parameterizations for alternate constraints.
10+
auto get2/(a)(self^/a, const Key^/a key) safe -> Value^/a;
11+
};
12+
13+
int main() safe {
14+
Map<float, long> map { };
15+
16+
// Bind the key reference to a materialized temporary.
17+
// The temporary expires at the end of this statement.
18+
long^ value1 = mut map.get1(3.14f);
19+
20+
// We can still access value, because it's not constrained on the
21+
// key argument.
22+
*value1 = 1001;
23+
24+
// The call to get2 constrains the returned reference to the lifetime
25+
// of the key temporary.
26+
long^ value2 = mut map.get2(1.6186f);
27+
28+
// This is ill-formed, because get2's key argument is out of scope.
29+
*value2 = 1002;
30+
}

0 commit comments

Comments
 (0)