Skip to content

Commit 13f765b

Browse files
committed
Take 2: Enable natural use of single named return value
This version works better for class types than the previous initial commit. For example: f: () -> (ret: int = 5) post (ret > ret$) = { ret += 1; } std::cout << f().ret + 2; // use name, always worked std::cout << f() + 2; // omit name, now works Postconditions can freely refer to the named return value(s) without having to add special syntax to the postcondition grammar as Cpp1 is doing, because with the generalized named return value solution the names are just in scope and normally available TODO: Still need to make postconditions evaluate before the explicit/implicit return (including before move from definite last use, not after) - if this int were a string, it would be moved-from-last-use and currently the postcondition would inspect an empty string, so just need to evaluate the postcondition right before returning
1 parent d74b2ff commit 13f765b

10 files changed

+64
-54
lines changed

regression-tests/pure2-bugfix-for-name-lookup-and-value-decoration.cpp2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ vals: () -> (i : int) = {
55

66
main: () -> int = {
77
v := vals();
8-
v.i;
8+
_ = v;
99
}

regression-tests/pure2-look-up-parameter-across-unnamed-function.cpp2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@ g: () -> (ri : int) = {
1515
}
1616

1717
main: ()->int = {
18-
std::cout << f().ri + g().ri << "\n";
18+
std::cout << f() + g() << "\n";
1919
}

regression-tests/pure2-ufcs-member-access-and-chaining.cpp2

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ main: () -> int = {
33
_ = i.ufcs();
44

55
j := fun();
6-
_ = j.i.ufcs();
6+
_ = j.ufcs();
77

8-
_ = fun().i.ufcs();
8+
_ = fun().ufcs();
99

10-
k := fun().i;
10+
k := fun();
1111
_ = k.ufcs();
1212

1313
_ = get_i(j).ufcs();
@@ -16,7 +16,7 @@ main: () -> int = {
1616

1717
res := (42).ufcs();
1818

19-
_ = (j.i).ufcs();
19+
_ = (j).ufcs();
2020

2121
42.no_return();
2222

@@ -35,7 +35,7 @@ fun: () -> (i:int) = {
3535
}
3636

3737
get_i: (r:_) -> int = {
38-
return r.i;
38+
return r;
3939
}
4040

4141
// And a test for non-local UFCS, which shouldn't do a [&] capture
Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +0,0 @@
1-
pure2-bugfix-for-name-lookup-and-value-decoration.cpp2:8:18: warning: expression result unused [-Wunused-value]
2-
std::move(v).i;
3-
~~~~~~~~~~~~ ^
4-
1 warning generated.

regression-tests/test-results/pure2-bugfix-for-name-lookup-and-value-decoration.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@
1313

1414
#line 1 "pure2-bugfix-for-name-lookup-and-value-decoration.cpp2"
1515

16-
struct vals_ret { int i;
17-
operator auto() const { return i; }};
18-
16+
using vals_ret = int;
1917
[[nodiscard]] auto vals() -> vals_ret;
2018

2119
#line 6 "pure2-bugfix-for-name-lookup-and-value-decoration.cpp2"
@@ -28,11 +26,11 @@ operator auto() const { return i; }};
2826
cpp2::deferred_init<int> i;
2927
#line 2 "pure2-bugfix-for-name-lookup-and-value-decoration.cpp2"
3028
i.construct(42);
31-
return { std::move(i.value()) };
29+
return std::move(i.value());
3230
}
3331

3432
[[nodiscard]] auto main() -> int{
3533
auto v {vals()};
36-
std::move(v).i;
34+
static_cast<void>(std::move(v));
3735
}
3836

regression-tests/test-results/pure2-look-up-parameter-across-unnamed-function.cpp

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,10 @@
1313

1414
#line 1 "pure2-look-up-parameter-across-unnamed-function.cpp2"
1515

16-
struct f_ret { int ri;
17-
operator auto() const { return ri; }};
18-
16+
using f_ret = int;
1917
#line 2 "pure2-look-up-parameter-across-unnamed-function.cpp2"
2018
[[nodiscard]] auto f() -> f_ret;
21-
struct g_ret { int ri;
22-
operator auto() const { return ri; }};
23-
19+
using g_ret = int;
2420

2521

2622
#line 9 "pure2-look-up-parameter-across-unnamed-function.cpp2"
@@ -40,7 +36,7 @@ operator auto() const { return ri; }};
4036
auto pred {[](auto const& e) -> auto { return e == 1; }};
4137
ri = 42;
4238
std::move(pred)(ri);
43-
return { std::move(ri) }; // "return;" is implicit"
39+
return std::move(ri); // "return;" is implicit"
4440
}
4541

4642
[[nodiscard]] auto g() -> g_ret{
@@ -50,10 +46,10 @@ operator auto() const { return ri; }};
5046
auto pred {[](auto const& e) -> auto { return e == 1; }};
5147
ri.value() = 42;
5248
std::move(pred)(ri.value());
53-
return { std::move(ri.value()) };
49+
return std::move(ri.value());
5450
}
5551

5652
[[nodiscard]] auto main() -> int{
57-
std::cout << f().ri + g().ri << "\n";
53+
std::cout << f() + g() << "\n";
5854
}
5955

regression-tests/test-results/pure2-ufcs-member-access-and-chaining.cpp

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@
1818
auto no_return([[maybe_unused]] auto const& unnamed_param_1) -> void;
1919

2020
[[nodiscard]] auto ufcs(cpp2::in<int> i) -> int;
21-
struct fun_ret { int i;
22-
operator auto() const { return i; }};
23-
21+
using fun_ret = int;
2422

2523

2624
#line 32 "pure2-ufcs-member-access-and-chaining.cpp2"
@@ -43,11 +41,11 @@ extern int y;
4341
static_cast<void>(CPP2_UFCS_0(ufcs, std::move(i)));
4442

4543
auto j {fun()};
46-
static_cast<void>(CPP2_UFCS_0(ufcs, j.i));
44+
static_cast<void>(CPP2_UFCS_0(ufcs, j));
4745

48-
static_cast<void>(CPP2_UFCS_0(ufcs, fun().i));
46+
static_cast<void>(CPP2_UFCS_0(ufcs, fun()));
4947

50-
auto k {fun().i};
48+
auto k {fun()};
5149
static_cast<void>(CPP2_UFCS_0(ufcs, std::move(k)));
5250

5351
static_cast<void>(CPP2_UFCS_0(ufcs, get_i(j)));
@@ -56,7 +54,7 @@ extern int y;
5654

5755
auto res {CPP2_UFCS_0(ufcs, (42))};
5856

59-
static_cast<void>(CPP2_UFCS_0(ufcs, (std::move(j).i)));
57+
static_cast<void>(CPP2_UFCS_0(ufcs, (std::move(j))));
6058

6159
CPP2_UFCS_0(no_return, 42);
6260

@@ -73,11 +71,11 @@ auto no_return([[maybe_unused]] auto const& unnamed_param_1) -> void{}
7371
cpp2::deferred_init<int> i;
7472
#line 33 "pure2-ufcs-member-access-and-chaining.cpp2"
7573
i.construct(42);
76-
return { std::move(i.value()) };
74+
return std::move(i.value());
7775
}
7876

7977
[[nodiscard]] auto get_i(auto const& r) -> int{
80-
return r.i;
78+
return r;
8179
}
8280

8381
#line 42 "pure2-ufcs-member-access-and-chaining.cpp2"

regression-tests/test-results/version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
cppfront compiler v0.3.0 Build 8B15:1925
2+
cppfront compiler v0.3.0 Build 8B16:1224
33
Copyright(c) Herb Sutter All rights reserved
44

55
SPDX-License-Identifier: CC-BY-NC-ND-4.0

source/build.info

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
"8B15:1925"
1+
"8B16:1224"

source/to_cpp1.h

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2376,9 +2376,17 @@ class cppfront
23762376
&& function_returns.back().param_list
23772377
)
23782378
{
2379-
//auto stmt = function_return_name + " { "; // we shouldn't need this with { } init
2380-
auto stmt = std::string(" { ");
23812379
auto& parameters = function_returns.back().param_list->parameters;
2380+
2381+
auto stmt = std::string{};
2382+
2383+
// Put braces only around multiple named returns, which are a struct
2384+
// - single named returns are emitted as ordinary returns, and extra
2385+
// { } would be legal but generate a noisy warning on some compilers
2386+
if (std::ssize(parameters) > 1) {
2387+
stmt += std::string(" { ");
2388+
}
2389+
23822390
for (bool first = true; auto& param : parameters) {
23832391
if (!first) {
23842392
stmt += ", ";
@@ -2390,7 +2398,11 @@ class cppfront
23902398
emit(*param->declaration->identifier, true);
23912399
printer.emit_to_string();
23922400
}
2393-
stmt += " }";
2401+
2402+
if (std::ssize(parameters) > 1) {
2403+
stmt += std::string(" }");
2404+
}
2405+
23942406
printer.print_cpp2(stmt, n.position());
23952407
}
23962408

@@ -4242,8 +4254,7 @@ class cppfront
42424254
auto emit(
42434255
parameter_declaration_list_node const& n,
42444256
bool is_returns = false,
4245-
bool is_template_parameter = false,
4246-
std::string extra_text = ""
4257+
bool is_template_parameter = false
42474258
)
42484259
-> void
42494260
{
@@ -4281,7 +4292,7 @@ class cppfront
42814292
}
42824293

42834294
if (is_returns) {
4284-
printer.print_extra( extra_text + "};\n" );
4295+
printer.print_extra( "};\n" );
42854296
}
42864297
else {
42874298
// Position heuristic (aka hack): Avoid emitting extra whitespace before )
@@ -5315,23 +5326,34 @@ class cppfront
53155326
auto& func = std::get<declaration_node::a_function>(n.type);
53165327
assert(func);
53175328

5318-
if (func->returns.index() == function_type_node::list) {
5329+
if (func->returns.index() == function_type_node::list)
5330+
{
53195331
auto& r = std::get<function_type_node::list>(func->returns);
53205332
assert(r);
53215333
assert(std::ssize(r->parameters) > 0);
5322-
printer.print_extra( "\nstruct " );
5323-
printer.print_extra( *n.name() );
5324-
printer.print_extra( "_ret " );
53255334

5326-
auto extra = std::string{};
5327-
if (std::ssize(r->parameters) == 1) {
5328-
assert (r->parameters[0]->declaration->name());
5329-
extra += "\noperator auto() const { return "
5330-
+ r->parameters[0]->declaration->name()->to_string()
5331-
+ "; }";
5332-
}
5335+
auto func_name = n.name()->to_string();
53335336

5334-
emit(*r, true, false, extra);
5337+
// If it's a single named value, emit it as an aonymous return value
5338+
if (std::ssize(r->parameters) == 1)
5339+
{
5340+
printer.print_extra(
5341+
"\nusing "
5342+
+ func_name + "_ret = "
5343+
+ r->parameters[0]->declaration->get_object_type()->to_string()
5344+
+ ";"
5345+
);
5346+
}
5347+
// Else just emit it as an ordinary struct
5348+
else
5349+
{
5350+
printer.print_extra(
5351+
"\nstruct "
5352+
+ n.name()->to_string()
5353+
+ "_ret "
5354+
);
5355+
emit(*r, true);
5356+
}
53355357
printer.print_extra( "\n" );
53365358
}
53375359
}

0 commit comments

Comments
 (0)