Skip to content

Commit

Permalink
Ensure valid type name for operators with multiple returns. (#796)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
4 people authored Dec 28, 2023
1 parent 06f3173 commit 07e00c8
Show file tree
Hide file tree
Showing 13 changed files with 179 additions and 20 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@
*.bin
*.exe
source/gen_version.bat
build*/
34 changes: 34 additions & 0 deletions regression-tests/pure2-return-tuple-operator.cpp2
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

A : type = {
operator() : (this) -> (x: int, y: int) = {
x = 12;
y = 34;
return;
}
operator* : (this) -> (x: int, y: int) = {
x = 23;
y = 45;
return;
}
operator[] : (this, idx: int) -> (x: int, y: int) = {
x = 34 * (idx+1);
y = 56 * (idx+1);
return;
}
}


main : () = {

a : A = ();

t1 := a();
std::cout << t1.x << " , " << t1.y << "\n";

t2 := a*;
std::cout << t2.x << " , " << t2.y << "\n";

t3 := a[0];
std::cout << t3.x << " , " << t3.y << "\n";

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
12 , 34
23 , 45
34 , 56
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
12 , 34
23 , 45
34 , 56
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
12 , 34
23 , 45
34 , 56
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
12 , 34
23 , 45
34 , 56
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pure2-return-tuple-operator.cpp
94 changes: 94 additions & 0 deletions regression-tests/test-results/pure2-return-tuple-operator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@

#define CPP2_IMPORT_STD Yes

//=== Cpp2 type declarations ====================================================


#include "cpp2util.h"

#line 1 "pure2-return-tuple-operator.cpp2"

#line 2 "pure2-return-tuple-operator.cpp2"
class A;


//=== Cpp2 type definitions and function declarations ===========================

#line 1 "pure2-return-tuple-operator.cpp2"

#line 2 "pure2-return-tuple-operator.cpp2"
class A {
struct operator_call_ret { int x; int y; };


#line 3 "pure2-return-tuple-operator.cpp2"
public: [[nodiscard]] auto operator()() const& -> operator_call_ret;
struct operator_dereference_ret { int x; int y; };



#line 8 "pure2-return-tuple-operator.cpp2"
public: [[nodiscard]] auto operator*() const& -> operator_dereference_ret;
struct operator_subscript_ret { int x; int y; };



#line 13 "pure2-return-tuple-operator.cpp2"
public: [[nodiscard]] auto operator[](cpp2::in<int> idx) const& -> operator_subscript_ret;
public: A() = default;
public: A(A const&) = delete; /* No 'that' constructor, suppress copy */
public: auto operator=(A const&) -> void = delete;


#line 18 "pure2-return-tuple-operator.cpp2"
};

#line 21 "pure2-return-tuple-operator.cpp2"
auto main() -> int;

//=== Cpp2 function definitions =================================================

#line 1 "pure2-return-tuple-operator.cpp2"

#line 3 "pure2-return-tuple-operator.cpp2"
[[nodiscard]] auto A::operator()() const& -> operator_call_ret{
cpp2::deferred_init<int> x;
cpp2::deferred_init<int> y;
#line 4 "pure2-return-tuple-operator.cpp2"
x.construct(12);
y.construct(34);
return { std::move(x.value()), std::move(y.value()) };
}
[[nodiscard]] auto A::operator*() const& -> operator_dereference_ret{
cpp2::deferred_init<int> x;
cpp2::deferred_init<int> y;
#line 9 "pure2-return-tuple-operator.cpp2"
x.construct(23);
y.construct(45);
return { std::move(x.value()), std::move(y.value()) };
}
[[nodiscard]] auto A::operator[](cpp2::in<int> idx) const& -> operator_subscript_ret{
cpp2::deferred_init<int> x;
cpp2::deferred_init<int> y;
#line 14 "pure2-return-tuple-operator.cpp2"
x.construct(34 * (idx + 1));
y.construct(56 * (idx + 1));
return { std::move(x.value()), std::move(y.value()) };
}

#line 21 "pure2-return-tuple-operator.cpp2"
auto main() -> int{

A a {};

auto t1 {a()};
std::cout << t1.x << " , " << std::move(t1).y << "\n";

auto t2 {*cpp2::assert_not_null(a)};
std::cout << t2.x << " , " << std::move(t2).y << "\n";

auto t3 {CPP2_ASSERT_IN_BOUNDS(std::move(a), 0)};
std::cout << t3.x << " , " << std::move(t3).y << "\n";

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pure2-return-tuple-operator.cpp2... ok (all Cpp2, passes safety checks)

55 changes: 35 additions & 20 deletions source/to_cpp1.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,32 @@ auto pad(int padding)
};
}

auto multi_return_type_name(declaration_node const& n)
-> std::string
{
// When generating a multi-return struct, also enable multi-return
// from a (), [], or * operator. We can expand this in the future,
// but with care because most operators should 'do as the ints do'
// (e.g., it doesn't seem sensible for == to return multiple values)
constexpr std::pair<std::string_view, std::string_view> canonized_names[] = {
{ "operator()", "operator_call" },
{ "operator[]", "operator_subscript" },
{ "operator*", "operator_dereference" }
};

assert (n.is_function() && n.name());
auto ret = n.name()->to_string();
for (auto [op, canon] : canonized_names) {
if (ret == op) {
ret = canon;
break;
}
}
ret += "_ret";

return ret;
}


//-----------------------------------------------------------------------
//
Expand Down Expand Up @@ -1127,7 +1153,6 @@ class cppfront
bool in_definite_init = false;
bool in_parameter_list = false;

std::string function_return_name;
struct function_return {
parameter_declaration_list_node* param_list;
passing_style pass;
Expand Down Expand Up @@ -4629,7 +4654,6 @@ class cppfront
//
auto emit(
function_type_node const& n,
token const* ident,
bool is_main = false,
bool is_ctor_or_dtor = false,
std::string suffix1 = {},
Expand Down Expand Up @@ -4758,13 +4782,8 @@ class cppfront
// Otherwise, handle multiple/named returns
else {
printer.print_cpp2( " -> ", n.position() );
function_return_name = {};
printer.emit_to_string(&function_return_name);
assert(ident);
printer.print_cpp2( *ident, ident->position() );
printer.print_cpp2( "_ret", ident->position() );
printer.emit_to_string();
printer.print_cpp2( function_return_name, ident->position() );
assert (n.my_decl);
printer.print_cpp2( multi_return_type_name(*n.my_decl), n.position());
}
}

Expand Down Expand Up @@ -5261,7 +5280,7 @@ class cppfront
printer.print_cpp2( prefix, n.position() );
printer.print_cpp2( type_qualification_if_any_for(n), n.position() );
printer.print_cpp2( print_to_string( *n.parent_declaration->name() ), n.position() );
emit( *func, n.name(), false, true );
emit( *func, false, true );
}
// For an assignment operator, similar to emitting an ordinary function
else
Expand All @@ -5270,7 +5289,7 @@ class cppfront
current_functions.back().epilog.push_back( "return *this;");
printer.print_cpp2( prefix, n.position() );
printer.print_cpp2( "auto " + type_qualification_if_any_for(n) + print_to_string( *n.name() ), n.position());
emit( *func, n.name() );
emit( *func );
}
}

Expand Down Expand Up @@ -5617,11 +5636,7 @@ class cppfront
// Else just emit it as an ordinary struct
else
{
printer.print_extra(
"\nstruct "
+ n.name()->to_string()
+ "_ret "
);
printer.print_extra( "\nstruct " + multi_return_type_name(n) + " ");
emit(*r, true);
}
printer.print_extra( "\n" );
Expand Down Expand Up @@ -6028,9 +6043,9 @@ class cppfront
// so print the provided intro instead, which will be a Cpp1 lambda-introducer
if (capture_intro != "")
{
assert (!n.identifier);
assert (!n.identifier && !is_main);
printer.print_cpp2(capture_intro, n.position());
emit( *func, nullptr, is_main);
emit( *func );
}

// Else start introducing a normal function
Expand Down Expand Up @@ -6275,7 +6290,7 @@ class cppfront
+ "~" + print_to_string(*n.parent_declaration->name()),
n.position()
);
emit( *func, n.name(), false, true);
emit( *func, false, true);
printer.print_cpp2( suffix2, n.position() );
}

Expand All @@ -6297,7 +6312,7 @@ class cppfront
}

emit( *n.name() );
emit( *func, n.name(), is_main, false, suffix1, generating_postfix_inc_dec_from != nullptr );
emit( *func, is_main, false, suffix1, generating_postfix_inc_dec_from != nullptr );
printer.print_cpp2( suffix2, n.position() );

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

0 comments on commit 07e00c8

Please sign in to comment.