Skip to content

Commit 07e00c8

Browse files
iprtelIngo PrötelIngo Prötelhsutter
authored
Ensure valid type name for operators with multiple returns. (#796)
* Ensure valid type name for operators with multiple returns. * Added parent and bracket operator. * Added test * Tweak the implementation and run regressions * Use unused parameter to make tests compile cleanly --------- Co-authored-by: Ingo Prötel <[email protected]> Co-authored-by: Ingo Prötel <[email protected]> Co-authored-by: Herb Sutter <[email protected]>
1 parent 06f3173 commit 07e00c8

13 files changed

+179
-20
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,4 @@
2626
*.bin
2727
*.exe
2828
source/gen_version.bat
29+
build*/
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
2+
A : type = {
3+
operator() : (this) -> (x: int, y: int) = {
4+
x = 12;
5+
y = 34;
6+
return;
7+
}
8+
operator* : (this) -> (x: int, y: int) = {
9+
x = 23;
10+
y = 45;
11+
return;
12+
}
13+
operator[] : (this, idx: int) -> (x: int, y: int) = {
14+
x = 34 * (idx+1);
15+
y = 56 * (idx+1);
16+
return;
17+
}
18+
}
19+
20+
21+
main : () = {
22+
23+
a : A = ();
24+
25+
t1 := a();
26+
std::cout << t1.x << " , " << t1.y << "\n";
27+
28+
t2 := a*;
29+
std::cout << t2.x << " , " << t2.y << "\n";
30+
31+
t3 := a[0];
32+
std::cout << t3.x << " , " << t3.y << "\n";
33+
34+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
12 , 34
2+
23 , 45
3+
34 , 56

regression-tests/test-results/clang-12/pure2-return-tuple-operator.cpp.output

Whitespace-only changes.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
12 , 34
2+
23 , 45
3+
34 , 56

regression-tests/test-results/gcc-10/pure2-return-tuple-operator.cpp.output

Whitespace-only changes.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
12 , 34
2+
23 , 45
3+
34 , 56

regression-tests/test-results/gcc-13/pure2-return-tuple-operator.cpp.output

Whitespace-only changes.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
12 , 34
2+
23 , 45
3+
34 , 56
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pure2-return-tuple-operator.cpp
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
2+
#define CPP2_IMPORT_STD Yes
3+
4+
//=== Cpp2 type declarations ====================================================
5+
6+
7+
#include "cpp2util.h"
8+
9+
#line 1 "pure2-return-tuple-operator.cpp2"
10+
11+
#line 2 "pure2-return-tuple-operator.cpp2"
12+
class A;
13+
14+
15+
//=== Cpp2 type definitions and function declarations ===========================
16+
17+
#line 1 "pure2-return-tuple-operator.cpp2"
18+
19+
#line 2 "pure2-return-tuple-operator.cpp2"
20+
class A {
21+
struct operator_call_ret { int x; int y; };
22+
23+
24+
#line 3 "pure2-return-tuple-operator.cpp2"
25+
public: [[nodiscard]] auto operator()() const& -> operator_call_ret;
26+
struct operator_dereference_ret { int x; int y; };
27+
28+
29+
30+
#line 8 "pure2-return-tuple-operator.cpp2"
31+
public: [[nodiscard]] auto operator*() const& -> operator_dereference_ret;
32+
struct operator_subscript_ret { int x; int y; };
33+
34+
35+
36+
#line 13 "pure2-return-tuple-operator.cpp2"
37+
public: [[nodiscard]] auto operator[](cpp2::in<int> idx) const& -> operator_subscript_ret;
38+
public: A() = default;
39+
public: A(A const&) = delete; /* No 'that' constructor, suppress copy */
40+
public: auto operator=(A const&) -> void = delete;
41+
42+
43+
#line 18 "pure2-return-tuple-operator.cpp2"
44+
};
45+
46+
#line 21 "pure2-return-tuple-operator.cpp2"
47+
auto main() -> int;
48+
49+
//=== Cpp2 function definitions =================================================
50+
51+
#line 1 "pure2-return-tuple-operator.cpp2"
52+
53+
#line 3 "pure2-return-tuple-operator.cpp2"
54+
[[nodiscard]] auto A::operator()() const& -> operator_call_ret{
55+
cpp2::deferred_init<int> x;
56+
cpp2::deferred_init<int> y;
57+
#line 4 "pure2-return-tuple-operator.cpp2"
58+
x.construct(12);
59+
y.construct(34);
60+
return { std::move(x.value()), std::move(y.value()) };
61+
}
62+
[[nodiscard]] auto A::operator*() const& -> operator_dereference_ret{
63+
cpp2::deferred_init<int> x;
64+
cpp2::deferred_init<int> y;
65+
#line 9 "pure2-return-tuple-operator.cpp2"
66+
x.construct(23);
67+
y.construct(45);
68+
return { std::move(x.value()), std::move(y.value()) };
69+
}
70+
[[nodiscard]] auto A::operator[](cpp2::in<int> idx) const& -> operator_subscript_ret{
71+
cpp2::deferred_init<int> x;
72+
cpp2::deferred_init<int> y;
73+
#line 14 "pure2-return-tuple-operator.cpp2"
74+
x.construct(34 * (idx + 1));
75+
y.construct(56 * (idx + 1));
76+
return { std::move(x.value()), std::move(y.value()) };
77+
}
78+
79+
#line 21 "pure2-return-tuple-operator.cpp2"
80+
auto main() -> int{
81+
82+
A a {};
83+
84+
auto t1 {a()};
85+
std::cout << t1.x << " , " << std::move(t1).y << "\n";
86+
87+
auto t2 {*cpp2::assert_not_null(a)};
88+
std::cout << t2.x << " , " << std::move(t2).y << "\n";
89+
90+
auto t3 {CPP2_ASSERT_IN_BOUNDS(std::move(a), 0)};
91+
std::cout << t3.x << " , " << std::move(t3).y << "\n";
92+
93+
}
94+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pure2-return-tuple-operator.cpp2... ok (all Cpp2, passes safety checks)
2+

source/to_cpp1.h

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,32 @@ auto pad(int padding)
5656
};
5757
}
5858

59+
auto multi_return_type_name(declaration_node const& n)
60+
-> std::string
61+
{
62+
// When generating a multi-return struct, also enable multi-return
63+
// from a (), [], or * operator. We can expand this in the future,
64+
// but with care because most operators should 'do as the ints do'
65+
// (e.g., it doesn't seem sensible for == to return multiple values)
66+
constexpr std::pair<std::string_view, std::string_view> canonized_names[] = {
67+
{ "operator()", "operator_call" },
68+
{ "operator[]", "operator_subscript" },
69+
{ "operator*", "operator_dereference" }
70+
};
71+
72+
assert (n.is_function() && n.name());
73+
auto ret = n.name()->to_string();
74+
for (auto [op, canon] : canonized_names) {
75+
if (ret == op) {
76+
ret = canon;
77+
break;
78+
}
79+
}
80+
ret += "_ret";
81+
82+
return ret;
83+
}
84+
5985

6086
//-----------------------------------------------------------------------
6187
//
@@ -1127,7 +1153,6 @@ class cppfront
11271153
bool in_definite_init = false;
11281154
bool in_parameter_list = false;
11291155

1130-
std::string function_return_name;
11311156
struct function_return {
11321157
parameter_declaration_list_node* param_list;
11331158
passing_style pass;
@@ -4629,7 +4654,6 @@ class cppfront
46294654
//
46304655
auto emit(
46314656
function_type_node const& n,
4632-
token const* ident,
46334657
bool is_main = false,
46344658
bool is_ctor_or_dtor = false,
46354659
std::string suffix1 = {},
@@ -4758,13 +4782,8 @@ class cppfront
47584782
// Otherwise, handle multiple/named returns
47594783
else {
47604784
printer.print_cpp2( " -> ", n.position() );
4761-
function_return_name = {};
4762-
printer.emit_to_string(&function_return_name);
4763-
assert(ident);
4764-
printer.print_cpp2( *ident, ident->position() );
4765-
printer.print_cpp2( "_ret", ident->position() );
4766-
printer.emit_to_string();
4767-
printer.print_cpp2( function_return_name, ident->position() );
4785+
assert (n.my_decl);
4786+
printer.print_cpp2( multi_return_type_name(*n.my_decl), n.position());
47684787
}
47694788
}
47704789

@@ -5261,7 +5280,7 @@ class cppfront
52615280
printer.print_cpp2( prefix, n.position() );
52625281
printer.print_cpp2( type_qualification_if_any_for(n), n.position() );
52635282
printer.print_cpp2( print_to_string( *n.parent_declaration->name() ), n.position() );
5264-
emit( *func, n.name(), false, true );
5283+
emit( *func, false, true );
52655284
}
52665285
// For an assignment operator, similar to emitting an ordinary function
52675286
else
@@ -5270,7 +5289,7 @@ class cppfront
52705289
current_functions.back().epilog.push_back( "return *this;");
52715290
printer.print_cpp2( prefix, n.position() );
52725291
printer.print_cpp2( "auto " + type_qualification_if_any_for(n) + print_to_string( *n.name() ), n.position());
5273-
emit( *func, n.name() );
5292+
emit( *func );
52745293
}
52755294
}
52765295

@@ -5617,11 +5636,7 @@ class cppfront
56175636
// Else just emit it as an ordinary struct
56185637
else
56195638
{
5620-
printer.print_extra(
5621-
"\nstruct "
5622-
+ n.name()->to_string()
5623-
+ "_ret "
5624-
);
5639+
printer.print_extra( "\nstruct " + multi_return_type_name(n) + " ");
56255640
emit(*r, true);
56265641
}
56275642
printer.print_extra( "\n" );
@@ -6028,9 +6043,9 @@ class cppfront
60286043
// so print the provided intro instead, which will be a Cpp1 lambda-introducer
60296044
if (capture_intro != "")
60306045
{
6031-
assert (!n.identifier);
6046+
assert (!n.identifier && !is_main);
60326047
printer.print_cpp2(capture_intro, n.position());
6033-
emit( *func, nullptr, is_main);
6048+
emit( *func );
60346049
}
60356050

60366051
// Else start introducing a normal function
@@ -6275,7 +6290,7 @@ class cppfront
62756290
+ "~" + print_to_string(*n.parent_declaration->name()),
62766291
n.position()
62776292
);
6278-
emit( *func, n.name(), false, true);
6293+
emit( *func, false, true);
62796294
printer.print_cpp2( suffix2, n.position() );
62806295
}
62816296

@@ -6297,7 +6312,7 @@ class cppfront
62976312
}
62986313

62996314
emit( *n.name() );
6300-
emit( *func, n.name(), is_main, false, suffix1, generating_postfix_inc_dec_from != nullptr );
6315+
emit( *func, is_main, false, suffix1, generating_postfix_inc_dec_from != nullptr );
63016316
printer.print_cpp2( suffix2, n.position() );
63026317

63036318
// If this is ++ or --, also generate a Cpp1 postfix version of the operator

0 commit comments

Comments
 (0)