Skip to content

Commit 212eb15

Browse files
authored
Starting over on function types - initial support for function types in <> lists (#1183)
* Starting over on function types - initial support for function types in <> lists Should generally support std::function<> style uses Aside: I'm happy to find that C++ allows parameter names in function types, thank you WG21! I hadn't seen those used in examples so I had been expecting that cppfront would have to suppress those, but std::function< int ( std::string& param_name ) > is legal code. Sweet. This commit does not yet support pointer-to-function local variables... * Add support for pointer-to-function variables * Add docs examples for function typeids with std::function & *pfn * Add support for pointer to function parameter types * Support function type ids in type aliases
1 parent 079b1b5 commit 212eb15

19 files changed

+660
-135
lines changed

Diff for: docs/cpp2/contracts.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ Contract groups are useful to enable or disable or [set custom handlers](#violat
5757
5858
You can create new contract groups just by creating new objects that have a `.report_violation` function. The object's name is the contract group's name. The object can be at any scope: local, global, or heap.
5959
60-
For example, here are some ways to use contract groups of type [`cpp2::contract_group`](#violation_handlers), which is a convenient group type:
60+
For example, here are some ways to use contract groups of type [`cpp2::contract_group`](#violation-handlers), which is a convenient group type:
6161
6262
``` cpp title="Using contract groups" hl_lines="1 4 6 10-12"
6363
group_a: cpp2::contract_group = (); // a global group

Diff for: docs/cpp2/functions.md

+28-6
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ func: ( /* no parameters */ ) = { /* empty body */ }
1212
```
1313
1414
15-
## <a id="parameters"></a> Parameters
15+
## <a id="function-signatures"></a> Function signatures: Parameters, returns, and using function types
16+
17+
### <a id="parameters"></a> Parameters
1618
1719
The parameter list is a [list](common.md#lists) enclosed by `(` `)` parentheses. Each parameter is declared using the [same unified syntax](declarations.md) as used for all declarations. For example:
1820
@@ -72,7 +74,7 @@ wrap_f: (
7274
```
7375

7476

75-
## <a id="return-values"></a> Return values
77+
### <a id="return-values"></a> Return values
7678

7779
A function can return either of the following. The default is `#!cpp -> void`.
7880

@@ -152,7 +154,7 @@ main: () = {
152154
```
153155

154156

155-
### <a id="nodiscard-outputs"></a> Function outputs are not implicitly discardable
157+
#### <a id="nodiscard-outputs"></a> Function outputs are not implicitly discardable
156158

157159
A function's outputs are its return values, and the "out" state of any `out` and `inout` parameters.
158160

@@ -200,9 +202,29 @@ main: ()
200202
> - A function call written in Cpp2 `x.f()` member call syntax always treats a non-`#!cpp void` return type as not discardable, even if the function was written in Cpp1 syntax that did not write `[[nodiscard]]`.
201203
202204

205+
### <a id = "function-types"></a> Using function types
206+
207+
The same function parameter/return syntax can be used as a function type, for example to instantiate `std::function` or to declare a pointer to function variable. For example:
208+
209+
``` cpp title="Using function types with std::function and *pfunc" hl_lines="4 7"
210+
decorate_int: (i: i32) -> std::string = "--> (i)$ <--";
211+
212+
main: () = {
213+
pf1: std::function< (i: i32) -> std::string > = decorate_int&;
214+
std::cout << "pf1(123) returned \"(pf1(123))$\"\n";
215+
216+
pf2: * (i: i32) -> std::string = decorate_int&;
217+
std::cout << "pf2(456) returned \"(pf2(456))$\"\n";
218+
}
219+
// Prints:
220+
// pf1 returned "--> 123 <--"
221+
// pf2 returned "--> 456 <--"
222+
```
223+
224+
203225
## <a id="control flow"></a> Control flow
204226

205-
## <a id="branches"></a> `#!cpp if`, `#!cpp else` — Branches
227+
### <a id="branches"></a> `#!cpp if`, `#!cpp else` — Branches
206228

207229
`if` and `else` are like always in C++, except that `(` `)` parentheses around the condition are not required. Instead, `{` `}` braces around a branch body *are* required. For example:
208230

@@ -216,7 +238,7 @@ else {
216238
```
217239

218240

219-
## <a id="loops"></a> `#!cpp for`, `#!cpp while`, `#!cpp do` — Loops
241+
### <a id="loops"></a> `#!cpp for`, `#!cpp while`, `#!cpp do` — Loops
220242

221243
**`#!cpp do`** and **`#!cpp while`** are like always in C++, except that `(` `)` parentheses around the condition are not required. Instead, `{` `}` braces around the loop body *are* required.
222244

@@ -296,7 +318,7 @@ Line by line:
296318
- `next i++`: The end-of-loop-iteration statement. Note `++` is always postfix in Cpp2.
297319

298320

299-
### Loop names, `#!cpp break`, and `#!cpp continue`
321+
#### Loop names, `#!cpp break`, and `#!cpp continue`
300322

301323
Loops can be named using the usual **name `:`** syntax that introduces all names, and `#!cpp break` and `#!cpp continue` can refer to those names. For example:
302324

Diff for: include/cpp2util.h

+7-5
Original file line numberDiff line numberDiff line change
@@ -518,15 +518,17 @@ inline std::string join(List const& list) {
518518
//
519519
// Conveniences for expressing Cpp1 references (rarely useful)
520520
//
521-
// Note: Only needed in rare cases to take full control of matching a
522-
// Cpp1 signature exactly. Most cases don't need this, for example
523-
// a Cpp1 virtual function signature declaration like
521+
// Note: Only needed in rare cases to take full control of matching an
522+
// odd Cpp1 signature exactly. Most cases don't need this... for
523+
// example, a Cpp1 virtual function signature declaration like
524524
//
525-
// virtual void f(int&) const
525+
// virtual void myfunc(int& val) const
526526
//
527527
// can already be directly overriden by a Cpp2 declaration of
528528
//
529-
// f: (override this, inout val : int)
529+
// myfunc: (override this, inout val: int)
530+
// // identical to this in Cpp1 syntax:
531+
// // void myfunc(int& val) const override
530532
//
531533
// without any need to say cpp1_ref on the int parameter.
532534
//

Diff for: regression-tests/pure2-function-typeids.cpp2

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
2+
// --- Scaffolding
3+
4+
f: () = std::cout << "hello world!\n";
5+
6+
g_in : ( s: std::string) = std::cout << "Come in, (s)$\n";
7+
g_inout: (inout s: std::string) = std::cout << "Come in awhile, but take some biscuits on your way out, (s)$!\n";
8+
g_out : (out s: std::string) = s = "A Powerful Mage";
9+
g_move : (move s: std::string) = std::cout << "I hear you've moving, (s)$?\n";
10+
11+
h_forward: (inout s: std::string) -> forward std::string = { std::cout << "Inout (s)$ ... "; return s; }
12+
h_out : ( s: std::string) -> std::string = { std::cout << "In (s)$ ... "; return "yohoho"; }
13+
14+
f1: (a: std::function< (x:int) -> int >) -> int = a(1);
15+
f2: (a: * (x:int) -> int ) -> int = a(2);
16+
g : (x:int) -> int = x+42;
17+
18+
19+
// --- Tests for type aliases
20+
21+
A_h_forward: type == (inout s: std::string) -> forward std::string;
22+
23+
24+
main: () =
25+
{
26+
// --- Test basic/degenerate cases
27+
28+
// Test std::function< void() >
29+
ff: std::function< () -> void > = f&;
30+
ff();
31+
32+
// Ordinary pointer to function, deduced (always worked)
33+
pf: * () -> void = f&;
34+
pf();
35+
36+
37+
// --- Tests for parameters
38+
// Note: Not forward parameters which imply a template...
39+
// function type-ids are for single function signatures
40+
41+
fg_in : std::function< ( s: std::string) -> void > = g_in&;
42+
fg_inout: std::function< (inout s: std::string) -> void > = g_inout&;
43+
fg_out : std::function< (out s: std::string) -> void > = g_out&;
44+
fg_move : std::function< (move s: std::string) -> void > = g_move&;
45+
pg_in : * ( s: std::string) -> void = g_in&;
46+
pg_inout: * (inout s: std::string) -> void = g_inout&;
47+
pg_out : * (out s: std::string) -> void = g_out&;
48+
pg_move : * (move s: std::string) -> void = g_move&;
49+
50+
frodo: std::string = "Frodo";
51+
sam : std::string = "Sam";
52+
53+
// Test in param
54+
fg_in(frodo);
55+
pg_in(sam);
56+
57+
// Test inout
58+
fg_inout(frodo);
59+
pg_inout(sam);
60+
61+
// Test out
62+
gandalf : std::string;
63+
galadriel: std::string;
64+
fg_out(out gandalf);
65+
std::cout << "fg_out initialized gandalf to: (gandalf)$\n";
66+
pg_out(out galadriel);
67+
std::cout << "pg_out initialized galadriel to: (galadriel)$\n";
68+
gandalf = "Gandalf";
69+
galadriel = "Galadriel";
70+
71+
// Test move
72+
fg_move(frodo); // last use, so (move frodo) is not required
73+
pg_move(sam); // last use, so (move sam) is not required
74+
75+
76+
// --- Tests for single anonymous returns
77+
// Note: Not multiple named return values... function-type-ids
78+
// are for Cpp1-style (single anonymous, possibly void) returns
79+
80+
fh_forward: std::function< (inout s: std::string) -> forward std::string > = h_forward&;
81+
fh_out : std::function< ( s: std::string) -> std::string > = h_out&;
82+
ph_forward: * (inout s: std::string) -> forward std::string = h_forward&;
83+
ph_out : * ( s: std::string) -> std::string = h_out&;
84+
85+
ph_forward2: * A_h_forward = h_forward&;
86+
87+
// Test forward return
88+
std::cout << "fh_forward returned: (fh_forward(gandalf))$\n";
89+
std::cout << "ph_forward returned: (ph_forward(galadriel))$\n";
90+
std::cout << "ph_forward2 returned: (ph_forward2(galadriel))$\n";
91+
92+
// Test out return
93+
std::cout << "fh_out returned: (fh_out(gandalf))$\n";
94+
std::cout << "ph_out returned: (ph_out(galadriel))$\n";
95+
96+
97+
// --- Tests for function parameters
98+
std::cout << "(f1(g&))$\n";
99+
std::cout << "(f2(g&))$\n";
100+
101+
102+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
hello world!
2+
hello world!
3+
Come in, Frodo
4+
Come in, Sam
5+
Come in awhile, but take some biscuits on your way out, Frodo!
6+
Come in awhile, but take some biscuits on your way out, Sam!
7+
fg_out initialized gandalf to: A Powerful Mage
8+
pg_out initialized galadriel to: A Powerful Mage
9+
I hear you've moving, Frodo?
10+
I hear you've moving, Sam?
11+
Inout Gandalf ... fh_forward returned: Gandalf
12+
Inout Galadriel ... ph_forward returned: Galadriel
13+
Inout Galadriel ... ph_forward2 returned: Galadriel
14+
In Gandalf ... fh_out returned: yohoho
15+
In Galadriel ... ph_out returned: yohoho
16+
43
17+
44

Diff for: regression-tests/test-results/clang-12-c++20/run-tests-clang-12.sh

+1
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,6 @@ do
2020
fi
2121
done
2222
rm -f *.obj *.exp *.lib
23+
find . -type f -exec bash -c "[ ! -s \"{}\" ] && rm \"{}\"" \;
2324
printf "\nDone: %s .cpp tests compiled\n" "$count"
2425
printf "\n %s .cpp executables generated and run\n" "$exe_count"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
hello world!
2+
hello world!
3+
Come in, Frodo
4+
Come in, Sam
5+
Come in awhile, but take some biscuits on your way out, Frodo!
6+
Come in awhile, but take some biscuits on your way out, Sam!
7+
fg_out initialized gandalf to: A Powerful Mage
8+
pg_out initialized galadriel to: A Powerful Mage
9+
I hear you've moving, Frodo?
10+
I hear you've moving, Sam?
11+
Inout Gandalf ... fh_forward returned: Gandalf
12+
Inout Galadriel ... ph_forward returned: Galadriel
13+
Inout Galadriel ... ph_forward2 returned: Galadriel
14+
In Gandalf ... fh_out returned: yohoho
15+
In Galadriel ... ph_out returned: yohoho
16+
43
17+
44

Diff for: regression-tests/test-results/gcc-10-c++20/run-tests-gcc-10.sh

+1
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,6 @@ do
2020
fi
2121
done
2222
rm -f *.obj *.exp *.lib
23+
find . -type f -exec bash -c "[ ! -s \"{}\" ] && rm \"{}\"" \;
2324
printf "\nDone: %s .cpp tests compiled\n" "$count"
2425
printf "\n %s .cpp executables generated and run\n" "$exe_count"
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,41 @@
11
In file included from mixed-bugfix-for-ufcs-non-local.cpp:6:
22
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
3-
2100 | class finally_success
3+
2100 |
44
| ^
55
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
6-
2137 | finally(finally&& that) noexcept
6+
2137 | ~finally() noexcept { f(); }
77
| ^
88
mixed-bugfix-for-ufcs-non-local.cpp2:13:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
99
mixed-bugfix-for-ufcs-non-local.cpp2:13:36: error: template argument 1 is invalid
1010
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
11-
2100 | class finally_success
11+
2100 |
1212
| ^
1313
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
14-
2137 | finally(finally&& that) noexcept
14+
2137 | ~finally() noexcept { f(); }
1515
| ^
1616
mixed-bugfix-for-ufcs-non-local.cpp2:21:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
1717
mixed-bugfix-for-ufcs-non-local.cpp2:21:36: error: template argument 1 is invalid
1818
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
19-
2100 | class finally_success
19+
2100 |
2020
| ^
2121
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
22-
2137 | finally(finally&& that) noexcept
22+
2137 | ~finally() noexcept { f(); }
2323
| ^
2424
mixed-bugfix-for-ufcs-non-local.cpp2:31:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
2525
mixed-bugfix-for-ufcs-non-local.cpp2:31:36: error: template argument 1 is invalid
2626
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
27-
2100 | class finally_success
27+
2100 |
2828
| ^
2929
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
30-
2137 | finally(finally&& that) noexcept
30+
2137 | ~finally() noexcept { f(); }
3131
| ^
3232
mixed-bugfix-for-ufcs-non-local.cpp2:33:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
3333
mixed-bugfix-for-ufcs-non-local.cpp2:33:36: error: template argument 1 is invalid
3434
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
35-
2100 | class finally_success
35+
2100 |
3636
| ^
3737
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
38-
2137 | finally(finally&& that) noexcept
38+
2137 | ~finally() noexcept { f(); }
3939
| ^
4040
mixed-bugfix-for-ufcs-non-local.cpp2:21:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
4141
mixed-bugfix-for-ufcs-non-local.cpp2:21:36: error: template argument 1 is invalid
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
hello world!
2+
hello world!
3+
Come in, Frodo
4+
Come in, Sam
5+
Come in awhile, but take some biscuits on your way out, Frodo!
6+
Come in awhile, but take some biscuits on your way out, Sam!
7+
fg_out initialized gandalf to: A Powerful Mage
8+
pg_out initialized galadriel to: A Powerful Mage
9+
I hear you've moving, Frodo?
10+
I hear you've moving, Sam?
11+
Inout Gandalf ... fh_forward returned: Gandalf
12+
Inout Galadriel ... ph_forward returned: Galadriel
13+
Inout Galadriel ... ph_forward2 returned: Galadriel
14+
In Gandalf ... fh_out returned: yohoho
15+
In Galadriel ... ph_out returned: yohoho
16+
43
17+
44

Diff for: regression-tests/test-results/gcc-14-c++2b/run-tests-gcc-14.sh

+1
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,6 @@ do
2020
fi
2121
done
2222
rm -f *.obj *.exp *.lib
23+
find . -type f -exec bash -c "[ ! -s \"{}\" ] && rm \"{}\"" \;
2324
printf "\nDone: %s .cpp tests compiled\n" "$count"
2425
printf "\n %s .cpp executables generated and run\n" "$exe_count"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
hello world!
2+
hello world!
3+
Come in, Frodo
4+
Come in, Sam
5+
Come in awhile, but take some biscuits on your way out, Frodo!
6+
Come in awhile, but take some biscuits on your way out, Sam!
7+
fg_out initialized gandalf to: A Powerful Mage
8+
pg_out initialized galadriel to: A Powerful Mage
9+
I hear you've moving, Frodo?
10+
I hear you've moving, Sam?
11+
Inout Gandalf ... fh_forward returned: Gandalf
12+
Inout Galadriel ... ph_forward returned: Galadriel
13+
Inout Galadriel ... ph_forward2 returned: Galadriel
14+
In Gandalf ... fh_out returned: yohoho
15+
In Galadriel ... ph_out returned: yohoho
16+
43
17+
44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pure2-function-typeids.cpp

Diff for: regression-tests/test-results/msvc-2022-c++latest/run-tests-msvc-2022.bat

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ for %%f in (*.cpp) do (
2626
)
2727
)
2828
del pure2-*.obj mixed-*.obj *.exp *.lib
29+
..\..\rm-empty-files.bat
2930
echo.
3031
echo Done: %count% .cpp tests compiled
3132
echo.

0 commit comments

Comments
 (0)