Skip to content

Commit 45fb75e

Browse files
committed
Add order-independent type definitions
Add order-independent type definitions, including order-independent dependencies between type definitions - see new test case code, pasted below in this commit message for convenience Note: This looks in pretty good shape, but it's a significant restructuring in the way the code is lowered to Cpp1, so there will probably be some corner cases to tweak in follow-on commits There are now three (not two) Cpp1 lowering passes: 1. type forward declarations (new) 2. type definitions (new) and function forward declarations (existing) 3. function definitions, including type-scope/member function out-of-line definitions (new) and non-type-scope functions (existing) When compiling `.h2` files, phases 1 and 2 go into the generated `.h` and phase 3 goes into the generated `.hpp` Comments written in Cpp2 all go on an entity's definition, because there are no forward declarations. So when lowering to Cpp1, comments are now split into two groups to put them where a reader of the Cpp1 code would naturally expect to see them: - comments not within function bodies are emitted in phase 2, where they belong on the types and function declarations (new) - comments within function bodies are emitted in phase 3, likewise where they belong Also: - Added support for `out` parameters on constructors. For example, this is useful when safely creating pointer cycles among types that refer to each other, respecting Cpp2's guaranteed program-meaningful initialization safety rules (demonstrated in the test case in this commit, pasted below) - Added support for `_` as the name of an anonymous object. This supports uses of RAII guards such as `_ := std::lock_guard(my_mutex);` and `_ := finally( :()= print("done"); ); );` - see example in test case below - Removed unused `offset` variable, closes #309 ### Regression test to demonstrate code that now works... convenience copy of `regression-tests\pure2-types-order-independence-and-nesting.cpp2` ``` N: namespace = { // A type X, that uses Y (defined later) // X: type = { py: *Y; // Note: A constructor with an 'out' parameter operator=: (out this, out y: Y) = { // === The following comments will stay close to, but not exactly at, // the corresponding lines that get moved to the Cpp1 mem-init-list // At this point, 'this' is now in scope and can safely be used. // The guaranteed initialization rules ensure we cannot use an // unconstructed object, and if a constructor that has begun chooses to // hand out 'this&' (as in the next line below) then it is explicitly // aware it's doing so - this constructor knows that if y's constructor // uses the pointer it will see 'this' object's state as of this line // 'out' parameters are constructed first y = this&; // ok, construct 'y' to refer to 'this' // at this point, 'y' is now initialized and can safely be used // then members are constructed next py = y&; // ok, set 'this' to refer to 'y' // === from here onward, the comments stick with their code // then do anything else the constructor wants to do std::cout << "made a safely initialized cycle\n"; } // X::exx member function description here exx: (this, count: int) = { // Exercise '_' anonymous objects too while we're at it _ := cpp2::finally( :()= std::cout << "leaving call to 'why((count)$)'\n"; ); if count < 5 { py*.why( count+1 ); // use Y object from X } } } // Another type Y, that uses X // Y: type = { px: *X; operator=: (out this, x: *X) = px = x; why: (this, count: int) = px*.exx( count+1 ); // use X object from Y } M: namespace = { // Testing nested templated types A: <T, U> type = { B: <I: int> type = { f: <V, J: int, W> (w: W) = std::cout << "hallo (w)$\n"; } } } } // Mainline - gratuitous comment just to check that this comment // stays on the function declaration when lowering main: () = { y: N::Y; // declare an uninitialized Y object x: N::X = (out y); // construct y and x, and point them at each other // now have the two objects call each other back and forth a few times x.exx(1); // and test a nested template out-of-line definition N::M::A<int, int>::B<42>::f<int, 43>("welt"); } ```
1 parent b370ab8 commit 45fb75e

File tree

83 files changed

+2057
-859
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+2057
-859
lines changed

include/cpp2util.h

+3-17
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,7 @@ class out {
570570
}
571571

572572
auto construct(auto&& ...args) -> void {
573-
if (has_t) {
573+
if (has_t || called_construct()) {
574574
Default.expects( t );
575575
*t = T(std::forward<decltype(args)>(args)...);
576576
}
@@ -587,7 +587,7 @@ class out {
587587
}
588588

589589
auto construct_list(auto&& ...args) -> void {
590-
if (has_t) {
590+
if (has_t || called_construct()) {
591591
Default.expects( t );
592592
*t = T{std::forward<decltype(args)>(args)...};
593593
}
@@ -631,21 +631,7 @@ class out {
631631
#endif
632632

633633

634-
// === NOTE: (see also corresponding note in cppfront.cpp)
635-
//
636-
// This "&" capture default is to work around 'if constexpr' bugs in Clang and MSVC...
637-
// If we don't emit a not-actually-used "[&]" here, then both compilers get tripped up
638-
// if we attempt UFCS for a member function name... the reason is that the UFCS macro
639-
// generates a lambda that does an 'if constexpr' to call the member function if
640-
// available, but Clang and MSVC look into the NOT-taken 'if constexpr' branch (which
641-
// they shouldn't) and see the nonmember function call syntax and think it's trying to
642-
// use the member function with implicit 'this->' and choke... (see issue #281, and
643-
// https://godbolt.org/z/M47zzMsoT for a distilled repro)
644-
//
645-
// The workaround that seems to be effective is to add TWO actually-unused "&" captures:
646-
// - here, and
647-
// - and also in the cppfront.cpp build_capture_lambda_intro_for() code
648-
//
634+
// Note: [&] is because a nested UFCS might be viewed as trying to capture 'this'
649635

650636
#define CPP2_UFCS(FUNCNAME,PARAM1,...) \
651637
[&](auto&& obj, auto&& ...params) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) { \

regression-tests/mixed-function-expression-and-std-for-each.cpp2

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#include <iostream>
66

77
main: () -> int = {
8-
vec: std::vector<std::string>
8+
vec: std::vector<std::string>
99
= ("hello", "2022");
1010
view: std::span = vec;
1111

@@ -16,7 +16,7 @@ main: () -> int = {
1616
:(inout x:_) = x += "-ish";
1717
);
1818

19-
// Initializating from a function expression
19+
// Initializing from a function expression
2020
callback := :(inout x:_) = x += " maybe";
2121
std::for_each(
2222
view.begin(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
2+
N: namespace = {
3+
4+
// A type X, that uses Y (defined later)
5+
//
6+
X: type = {
7+
py: *Y;
8+
9+
// Note: A constructor with an 'out' parameter
10+
operator=: (out this, out y: Y) = {
11+
// === The following comments will stay close to, but not exactly at,
12+
// the corresponding lines that get moved to the Cpp1 mem-init-list
13+
14+
// At this point, 'this' is now in scope and can safely be used.
15+
// The guaranteed initialization rules ensure we cannot use an
16+
// unconstructed object, and if a constructor that has begun chooses to
17+
// hand out 'this&' (as in the next line below) then it is explicitly
18+
// aware it's doing so - this constructor knows that if y's constructor
19+
// uses the pointer it will see 'this' object's state as of this line
20+
21+
// 'out' parameters are constructed first
22+
y = this&; // ok, construct 'y' to refer to 'this'
23+
// at this point, 'y' is now initialized and can safely be used
24+
25+
// then members are constructed next
26+
py = y&; // ok, set 'this' to refer to 'y'
27+
28+
// === from here onward, the comments stick with their code
29+
30+
// then do anything else the constructor wants to do
31+
std::cout << "made a safely initialized cycle\n";
32+
}
33+
34+
// X::exx member function description here
35+
exx: (this, count: int) = {
36+
// Exercise '_' anonymous objects too while we're at it
37+
_ := cpp2::finally( :()= std::cout << "leaving call to 'why((count)$)'\n"; );
38+
if count < 5 {
39+
py*.why( count+1 ); // use Y object from X
40+
}
41+
}
42+
}
43+
44+
// Another type Y, that uses X
45+
//
46+
Y: type = {
47+
px: *X;
48+
49+
operator=: (out this, x: *X) = px = x;
50+
51+
why: (this, count: int) =
52+
px*.exx( count+1 ); // use X object from Y
53+
}
54+
55+
M: namespace = {
56+
57+
// Testing nested templated types
58+
A: <T, U> type = {
59+
B: <I: int> type = {
60+
f: <V, J: int, W> (w: W) = std::cout << "hallo (w)$\n";
61+
}
62+
}
63+
64+
}
65+
66+
}
67+
68+
// Mainline - gratuitous comment just to check that this comment
69+
// stays on the function declaration when lowering
70+
main: () =
71+
{
72+
y: N::Y; // declare an uninitialized Y object
73+
x: N::X = (out y); // construct y and x, and point them at each other
74+
75+
// now have the two objects call each other back and forth a few times
76+
x.exx(1);
77+
78+
// and test a nested template out-of-line definition
79+
N::M::A<int, int>::B<42>::f<int, 43>("welt");
80+
}

regression-tests/test-results/clang-12/mixed-float-literals.cpp.output

+40-40
Original file line numberDiff line numberDiff line change
@@ -1,121 +1,121 @@
1-
mixed-float-literals.cpp2:3:3: warning: expression result unused [-Wunused-value]
1+
mixed-float-literals.cpp:13:3: warning: expression result unused [-Wunused-value]
22
123;
33
^~~
4-
mixed-float-literals.cpp2:4:3: warning: expression result unused [-Wunused-value]
4+
mixed-float-literals.cpp:14:3: warning: expression result unused [-Wunused-value]
55
123u;
66
^~~~
7-
mixed-float-literals.cpp2:5:3: warning: expression result unused [-Wunused-value]
7+
mixed-float-literals.cpp:15:3: warning: expression result unused [-Wunused-value]
88
123ul;
99
^~~~~
10-
mixed-float-literals.cpp2:6:3: warning: expression result unused [-Wunused-value]
10+
mixed-float-literals.cpp:16:3: warning: expression result unused [-Wunused-value]
1111
123ull;
1212
^~~~~~
13-
mixed-float-literals.cpp2:7:3: warning: expression result unused [-Wunused-value]
13+
mixed-float-literals.cpp:17:3: warning: expression result unused [-Wunused-value]
1414
123l;
1515
^~~~
16-
mixed-float-literals.cpp2:8:3: warning: expression result unused [-Wunused-value]
16+
mixed-float-literals.cpp:18:3: warning: expression result unused [-Wunused-value]
1717
123ll;
1818
^~~~~
19-
mixed-float-literals.cpp2:9:3: warning: expression result unused [-Wunused-value]
19+
mixed-float-literals.cpp:19:3: warning: expression result unused [-Wunused-value]
2020
123'456ll;
2121
^~~~~~~~~
22-
mixed-float-literals.cpp2:10:3: warning: expression result unused [-Wunused-value]
22+
mixed-float-literals.cpp:20:3: warning: expression result unused [-Wunused-value]
2323
123;
2424
^~~
25-
mixed-float-literals.cpp2:11:3: warning: expression result unused [-Wunused-value]
25+
mixed-float-literals.cpp:21:3: warning: expression result unused [-Wunused-value]
2626
123U;
2727
^~~~
28-
mixed-float-literals.cpp2:12:3: warning: expression result unused [-Wunused-value]
28+
mixed-float-literals.cpp:22:3: warning: expression result unused [-Wunused-value]
2929
123UL;
3030
^~~~~
31-
mixed-float-literals.cpp2:13:3: warning: expression result unused [-Wunused-value]
31+
mixed-float-literals.cpp:23:3: warning: expression result unused [-Wunused-value]
3232
123ULL;
3333
^~~~~~
34-
mixed-float-literals.cpp2:14:3: warning: expression result unused [-Wunused-value]
34+
mixed-float-literals.cpp:24:3: warning: expression result unused [-Wunused-value]
3535
123L;
3636
^~~~
37-
mixed-float-literals.cpp2:15:3: warning: expression result unused [-Wunused-value]
37+
mixed-float-literals.cpp:25:3: warning: expression result unused [-Wunused-value]
3838
123LL;
3939
^~~~~
40-
mixed-float-literals.cpp2:16:3: warning: expression result unused [-Wunused-value]
40+
mixed-float-literals.cpp:26:3: warning: expression result unused [-Wunused-value]
4141
123'456LL;
4242
^~~~~~~~~
43-
mixed-float-literals.cpp2:18:3: warning: expression result unused [-Wunused-value]
43+
mixed-float-literals.cpp:28:3: warning: expression result unused [-Wunused-value]
4444
123'456.0f;
4545
^~~~~~~~~~
46-
mixed-float-literals.cpp2:19:3: warning: expression result unused [-Wunused-value]
46+
mixed-float-literals.cpp:29:3: warning: expression result unused [-Wunused-value]
4747
123'456.f;
4848
^~~~~~~~~
49-
mixed-float-literals.cpp2:20:3: warning: expression result unused [-Wunused-value]
49+
mixed-float-literals.cpp:30:3: warning: expression result unused [-Wunused-value]
5050
456.0;
5151
^~~~~
52-
mixed-float-literals.cpp2:21:3: warning: expression result unused [-Wunused-value]
52+
mixed-float-literals.cpp:31:3: warning: expression result unused [-Wunused-value]
5353
456.;
5454
^~~~
55-
mixed-float-literals.cpp2:22:3: warning: expression result unused [-Wunused-value]
55+
mixed-float-literals.cpp:32:3: warning: expression result unused [-Wunused-value]
5656
1.0e10;
5757
^~~~~~
58-
mixed-float-literals.cpp2:23:3: warning: expression result unused [-Wunused-value]
58+
mixed-float-literals.cpp:33:3: warning: expression result unused [-Wunused-value]
5959
1.0e+10;
6060
^~~~~~~
61-
mixed-float-literals.cpp2:24:3: warning: expression result unused [-Wunused-value]
61+
mixed-float-literals.cpp:34:3: warning: expression result unused [-Wunused-value]
6262
1.0e-10;
6363
^~~~~~~
64-
mixed-float-literals.cpp2:25:3: warning: expression result unused [-Wunused-value]
64+
mixed-float-literals.cpp:35:3: warning: expression result unused [-Wunused-value]
6565
1.0e-10f;
6666
^~~~~~~~
67-
mixed-float-literals.cpp2:26:3: warning: expression result unused [-Wunused-value]
67+
mixed-float-literals.cpp:36:3: warning: expression result unused [-Wunused-value]
6868
1.e-10;
6969
^~~~~~
70-
mixed-float-literals.cpp2:27:3: warning: expression result unused [-Wunused-value]
70+
mixed-float-literals.cpp:37:3: warning: expression result unused [-Wunused-value]
7171
1.e-10f;
7272
^~~~~~~
73-
mixed-float-literals.cpp2:28:3: warning: expression result unused [-Wunused-value]
73+
mixed-float-literals.cpp:38:3: warning: expression result unused [-Wunused-value]
7474
1e-10;
7575
^~~~~
76-
mixed-float-literals.cpp2:29:3: warning: expression result unused [-Wunused-value]
76+
mixed-float-literals.cpp:39:3: warning: expression result unused [-Wunused-value]
7777
1e-10f;
7878
^~~~~~
79-
mixed-float-literals.cpp2:30:3: warning: expression result unused [-Wunused-value]
79+
mixed-float-literals.cpp:40:3: warning: expression result unused [-Wunused-value]
8080
1e-1'0;
8181
^~~~~~
82-
mixed-float-literals.cpp2:31:3: warning: expression result unused [-Wunused-value]
82+
mixed-float-literals.cpp:41:3: warning: expression result unused [-Wunused-value]
8383
123'456.0F;
8484
^~~~~~~~~~
85-
mixed-float-literals.cpp2:32:3: warning: expression result unused [-Wunused-value]
85+
mixed-float-literals.cpp:42:3: warning: expression result unused [-Wunused-value]
8686
123'456.F;
8787
^~~~~~~~~
88-
mixed-float-literals.cpp2:33:3: warning: expression result unused [-Wunused-value]
88+
mixed-float-literals.cpp:43:3: warning: expression result unused [-Wunused-value]
8989
456.0;
9090
^~~~~
91-
mixed-float-literals.cpp2:34:3: warning: expression result unused [-Wunused-value]
91+
mixed-float-literals.cpp:44:3: warning: expression result unused [-Wunused-value]
9292
456.;
9393
^~~~
94-
mixed-float-literals.cpp2:35:3: warning: expression result unused [-Wunused-value]
94+
mixed-float-literals.cpp:45:3: warning: expression result unused [-Wunused-value]
9595
1.0E10;
9696
^~~~~~
97-
mixed-float-literals.cpp2:36:3: warning: expression result unused [-Wunused-value]
97+
mixed-float-literals.cpp:46:3: warning: expression result unused [-Wunused-value]
9898
1.0E+10;
9999
^~~~~~~
100-
mixed-float-literals.cpp2:37:3: warning: expression result unused [-Wunused-value]
100+
mixed-float-literals.cpp:47:3: warning: expression result unused [-Wunused-value]
101101
1.0E-10;
102102
^~~~~~~
103-
mixed-float-literals.cpp2:38:3: warning: expression result unused [-Wunused-value]
103+
mixed-float-literals.cpp:48:3: warning: expression result unused [-Wunused-value]
104104
1.0E-10F;
105105
^~~~~~~~
106-
mixed-float-literals.cpp2:39:3: warning: expression result unused [-Wunused-value]
106+
mixed-float-literals.cpp:49:3: warning: expression result unused [-Wunused-value]
107107
1.E-10;
108108
^~~~~~
109-
mixed-float-literals.cpp2:40:3: warning: expression result unused [-Wunused-value]
109+
mixed-float-literals.cpp:50:3: warning: expression result unused [-Wunused-value]
110110
1.E-10F;
111111
^~~~~~~
112-
mixed-float-literals.cpp2:41:3: warning: expression result unused [-Wunused-value]
112+
mixed-float-literals.cpp:51:3: warning: expression result unused [-Wunused-value]
113113
1E-10;
114114
^~~~~
115-
mixed-float-literals.cpp2:42:3: warning: expression result unused [-Wunused-value]
115+
mixed-float-literals.cpp:52:3: warning: expression result unused [-Wunused-value]
116116
1E-10F;
117117
^~~~~~
118-
mixed-float-literals.cpp2:43:3: warning: expression result unused [-Wunused-value]
118+
mixed-float-literals.cpp:53:3: warning: expression result unused [-Wunused-value]
119119
1E-1'0;
120120
^~~~~~
121121
mixed-float-literals.cpp2:59:3: warning: expression result unused [-Wunused-value]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
made a safely initialized cycle
2+
leaving call to 'why(5)'
3+
leaving call to 'why(3)'
4+
leaving call to 'why(1)'
5+
hallo welt

regression-tests/test-results/clang-12/pure2-types-order-independence-and-nesting.cpp.output

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
made a safely initialized cycle
2+
leaving call to 'why(5)'
3+
leaving call to 'why(3)'
4+
leaving call to 'why(1)'
5+
hallo welt

regression-tests/test-results/gcc-10/pure2-types-order-independence-and-nesting.cpp.output

Whitespace-only changes.

regression-tests/test-results/mixed-as-for-variant-20-types.cpp

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11

2-
#line 1 "mixed-as-for-variant-20-types.cpp2"
3-
template<int I>
4-
struct X { operator int() const { return I; } };
2+
3+
//=== Cpp2 type declarations ====================================================
4+
55

66
#include "cpp2util.h"
77

8+
9+
//=== Cpp2 type definitions and function declarations ===========================
10+
11+
template<int I>
12+
struct X { operator int() const { return I; } };
13+
814
#line 4 "mixed-as-for-variant-20-types.cpp2"
915
[[nodiscard]] auto main() -> int;
1016

11-
//=== Cpp2 definitions ==========================================================
17+
//=== Cpp2 function definitions =================================================
1218

1319

1420
#line 4 "mixed-as-for-variant-20-types.cpp2"

regression-tests/test-results/mixed-bounds-check.cpp

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11

2-
#line 1 "mixed-bounds-check.cpp2"
32

4-
#include <vector>
3+
//=== Cpp2 type declarations ====================================================
4+
55

66
#include "cpp2util.h"
77

8+
9+
//=== Cpp2 type definitions and function declarations ===========================
10+
11+
12+
#include <vector>
13+
814
#line 4 "mixed-bounds-check.cpp2"
915
[[nodiscard]] auto main() -> int;
1016

11-
//=== Cpp2 definitions ==========================================================
17+
//=== Cpp2 function definitions =================================================
1218

1319

1420
#line 4 "mixed-bounds-check.cpp2"

regression-tests/test-results/mixed-bounds-safety-with-assert-2.cpp

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11

22

3+
//=== Cpp2 type declarations ====================================================
4+
5+
36
#include "cpp2util.h"
47

8+
9+
//=== Cpp2 type definitions and function declarations ===========================
10+
11+
512
#line 2 "mixed-bounds-safety-with-assert-2.cpp2"
613
[[nodiscard]] auto main() -> int;
714

@@ -13,7 +20,7 @@ auto add_42_to_subrange(auto& rng, cpp2::in<int> start, cpp2::in<int> end) -> vo
1320
#include <span>
1421
#include <iostream>
1522

16-
//=== Cpp2 definitions ==========================================================
23+
//=== Cpp2 function definitions =================================================
1724

1825

1926
#line 2 "mixed-bounds-safety-with-assert-2.cpp2"

0 commit comments

Comments
 (0)