Skip to content

Commit ca42e2c

Browse files
committed
Emit non-member binary streaming and arithmetic as friends
These must be non-member friends: - Streaming operators `<<` and `>>` (not as bit shift) need `this` to be a non-first parameter - Arithmetic binary operators are typically non-members to get symmetry (conversions on both arguments) and cannot be static Note: It's a known limitation that these won't yet work right on templated types. I will likely add that sometime in the future, and will require doing the dance Cpp1 requires to emit friend template specializations, and to handle dependent types more fully in `cpp2::in<>` for cases like `cpp2::in<mytype<T>>`. And ban unsafe/now-unnecessary overloaded operators: - Reject non-member comparison overloaded operators. These used to be the same as arithmetic operators, until C++20 standardized the design from Cpp2 which is symmetric and so there is no longer any reason to write them as non-members - Reject non-member bitwise binary overloaded operators. ISTM these shouldn't be non-members... argument conversions seem actively undesirable, unlike with arithmetic binary operators - Reject all `&&`, `||`, and ',' (comma) overloaded operators, we already teach that these should not be overloaded
1 parent b589f5d commit ca42e2c

File tree

7 files changed

+190
-44
lines changed

7 files changed

+190
-44
lines changed

regression-tests/test-results/pure2-types-down-upcast.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ class B: public A {
3737
#line 11 "pure2-types-down-upcast.cpp2"
3838
};
3939

40-
auto func_mut(A& a) -> void;
41-
auto func_mut(B& b) -> void;
40+
auto func_mut(A& a) -> void;
41+
auto func_mut(B& b) -> void;
4242
auto func_const(cpp2::in<A> a) -> void;
4343
auto func_const(cpp2::in<B> b) -> void;
4444

@@ -69,8 +69,8 @@ auto test_down() -> void;
6969
auto A::mut_foo() & -> void{std::cout << "foo \n"; }
7070

7171
#line 13 "pure2-types-down-upcast.cpp2"
72-
auto func_mut(A& a) -> void {std::cout << "Call A mut: " + cpp2::to_string(a.i) << std::endl;}
73-
auto func_mut(B& b) -> void {std::cout << "Call B mut: " + cpp2::to_string(b.d) << std::endl;}
72+
auto func_mut(A& a) -> void {std::cout << "Call A mut: " + cpp2::to_string(a.i) << std::endl;}
73+
auto func_mut(B& b) -> void {std::cout << "Call B mut: " + cpp2::to_string(b.d) << std::endl;}
7474
auto func_const(cpp2::in<A> a) -> void{std::cout << "Call A const: " + cpp2::to_string(a.i) << std::endl;}
7575
auto func_const(cpp2::in<B> b) -> void{std::cout << "Call B const: " + cpp2::to_string(b.d) << std::endl;}
7676

regression-tests/test-results/version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
cppfront compiler v0.2.1 Build 8921:1228
2+
cppfront compiler v0.2.1 Build 8922:0931
33
Copyright(c) Herb Sutter All rights reserved
44

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

source/build.info

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
"8921:1228"
1+
"8922:0931"

source/cppfront.cpp

+34-10
Original file line numberDiff line numberDiff line change
@@ -4033,7 +4033,7 @@ class cppfront
40334033
&& n.pass == passing_style::in
40344034
)
40354035
{
4036-
printer.print_cpp2( print_to_string(type_id), n.position() );
4036+
printer.print_cpp2( param_type, n.position() );
40374037
}
40384038
else if (
40394039
type_id.is_wildcard()
@@ -4045,6 +4045,7 @@ class cppfront
40454045
if (is_dependent_parameter_type) {
40464046
name = param_type;
40474047
}
4048+
40484049
switch (n.pass) {
40494050
break;case passing_style::in : printer.print_cpp2( name+" const&", n.position() );
40504051
break;case passing_style::copy : printer.print_cpp2( name, n.position() );
@@ -4071,19 +4072,16 @@ class cppfront
40714072
auto req = std::string{ "std::is_same_v<CPP2_TYPEOF(" };
40724073
req += *name;
40734074
req += "), ";
4074-
printer.emit_to_string(&req);
4075-
emit( type_id );
4076-
printer.emit_to_string();
4075+
req += param_type;
40774076
req += ">";
40784077
function_requires_conditions.push_back(req);
40794078
}
40804079
else {
4081-
auto type_name = print_to_string( type_id );
40824080
if (is_returns) {
4083-
printer.print_extra( type_name );
4081+
printer.print_extra( param_type );
40844082
}
40854083
else {
4086-
printer.print_cpp2( type_name, type_id.position() );
4084+
printer.print_cpp2( param_type, type_id.position() );
40874085
}
40884086
}
40894087

@@ -4362,12 +4360,15 @@ class cppfront
43624360
printer.print_cpp2( " -> ", n.position() );
43634361
auto& r = std::get<function_type_node::id>(n.returns);
43644362
assert(r.type);
4363+
4364+
auto return_type = print_to_string(*r.type);
4365+
43654366
if (r.pass == passing_style::forward) {
43664367
if (r.type->is_wildcard()) {
43674368
printer.print_cpp2( "auto&&", n.position() );
43684369
}
43694370
else {
4370-
emit(*r.type);
4371+
printer.print_cpp2( return_type, n.position() );
43714372
if (is_type_scope_function_with_in_this) {
43724373
printer.print_cpp2( " const&", n.position() );
43734374
}
@@ -4377,7 +4378,7 @@ class cppfront
43774378
}
43784379
}
43794380
else {
4380-
emit(*r.type);
4381+
printer.print_cpp2( return_type, n.position() );
43814382
}
43824383
}
43834384

@@ -5511,7 +5512,30 @@ class cppfront
55115512
)
55125513
)
55135514
{
5514-
auto emit_as_friend = n.name() && n.name()->as_string_view().starts_with("operator<<");
5515+
auto is_streaming_operator = [](std::string_view sv) {
5516+
return
5517+
sv == "operator<<"
5518+
|| sv == "operator>>"
5519+
;
5520+
};
5521+
5522+
auto is_binary_arithmetic_operator = [](std::string_view sv) {
5523+
return
5524+
sv == "operator+"
5525+
|| sv == "operator-"
5526+
|| sv == "operator*"
5527+
|| sv == "operator/"
5528+
|| sv == "operator%"
5529+
;
5530+
};
5531+
5532+
auto emit_as_friend =
5533+
n.name()
5534+
&& (
5535+
is_streaming_operator( n.name()->as_string_view() )
5536+
|| (!n.is_function_with_this() && is_binary_arithmetic_operator( n.name()->as_string_view() ))
5537+
)
5538+
;
55155539

55165540
// Start fresh (there may be one spurious leftover
55175541
// requires-condition created during the declarations pass)

source/parse.h

+49
Original file line numberDiff line numberDiff line change
@@ -2197,6 +2197,9 @@ struct function_type_node
21972197
auto is_constructor_with_move_that() const
21982198
-> bool;
21992199

2200+
auto is_comparison() const
2201+
-> bool;
2202+
22002203
auto is_compound_assignment() const
22012204
-> bool;
22022205

@@ -2252,6 +2255,12 @@ struct function_type_node
22522255
return returns.index() != empty;
22532256
}
22542257

2258+
auto parameter_count() const
2259+
-> int
2260+
{
2261+
return std::ssize(parameters->parameters);
2262+
}
2263+
22552264
auto index_of_parameter_named(std::string_view s) const
22562265
-> int
22572266
{
@@ -2662,6 +2671,15 @@ struct declaration_node
26622671
return initializer != nullptr;
26632672
}
26642673

2674+
auto parameter_count() const
2675+
-> int
2676+
{
2677+
if (!is_function()) {
2678+
return -1;
2679+
}
2680+
return std::get<a_function>(type)->parameter_count();
2681+
}
2682+
26652683
auto index_of_parameter_named(std::string_view s) const
26662684
-> int
26672685
{
@@ -3084,6 +3102,16 @@ struct declaration_node
30843102
return false;
30853103
}
30863104

3105+
auto is_comparison() const
3106+
-> bool
3107+
{
3108+
if (auto func = std::get_if<a_function>(&type)) {
3109+
return (*func)->is_comparison();
3110+
}
3111+
// else
3112+
return false;
3113+
}
3114+
30873115
auto is_compound_assignment() const
30883116
-> bool
30893117
{
@@ -3550,6 +3578,27 @@ auto function_type_node::is_constructor_with_move_that() const
35503578
}
35513579

35523580

3581+
auto function_type_node::is_comparison() const
3582+
-> bool
3583+
{
3584+
if (
3585+
(
3586+
my_decl->has_name("operator==")
3587+
|| my_decl->has_name("operator!=")
3588+
|| my_decl->has_name("operator<")
3589+
|| my_decl->has_name("operator<=")
3590+
|| my_decl->has_name("operator>")
3591+
|| my_decl->has_name("operator>=")
3592+
|| my_decl->has_name("operator<=>")
3593+
)
3594+
)
3595+
{
3596+
return true;
3597+
}
3598+
return false;
3599+
}
3600+
3601+
35533602
auto function_type_node::is_compound_assignment() const
35543603
-> bool
35553604
{

source/reflect.h

+27-28
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,11 @@ class compiler_services
104104
protected: [[nodiscard]] auto parse_statement(
105105

106106
std::string_view source
107-
) & ->
108-
std::unique_ptr<statement_node>;
107+
) & -> std::unique_ptr<statement_node>;
109108

110109
#line 113 "reflect.h2"
111-
public: [[nodiscard]] virtual auto position() const& ->
112-
source_position;
110+
public: [[nodiscard]] virtual auto position() const& -> source_position;
111+
113112

114113
#line 119 "reflect.h2"
115114
public: auto require(
@@ -367,24 +366,24 @@ class type_declaration
367366
public: [[nodiscard]] auto is_final() const& -> bool;
368367
public: [[nodiscard]] auto make_final() & -> bool;
369368

370-
public: [[nodiscard]] auto get_member_functions() const& ->
371-
std::vector<function_declaration>;
369+
public: [[nodiscard]] auto get_member_functions() const& -> std::vector<function_declaration>;
370+
372371

373372
#line 397 "reflect.h2"
374-
public: [[nodiscard]] auto get_member_objects() const& ->
375-
std::vector<object_declaration>;
373+
public: [[nodiscard]] auto get_member_objects() const& -> std::vector<object_declaration>;
374+
376375

377376
#line 407 "reflect.h2"
378-
public: [[nodiscard]] auto get_member_types() const& ->
379-
std::vector<type_declaration>;
377+
public: [[nodiscard]] auto get_member_types() const& -> std::vector<type_declaration>;
378+
380379

381380
#line 417 "reflect.h2"
382-
public: [[nodiscard]] auto get_member_aliases() const& ->
383-
std::vector<alias_declaration>;
381+
public: [[nodiscard]] auto get_member_aliases() const& -> std::vector<alias_declaration>;
382+
384383

385384
#line 427 "reflect.h2"
386-
public: [[nodiscard]] auto get_members() const& ->
387-
std::vector<declaration>; struct query_declared_value_set_functions__ret { bool out_this_in_that; bool out_this_move_that; bool inout_this_in_that; bool inout_this_move_that; };
385+
public: [[nodiscard]] auto get_members() const& -> std::vector<declaration>;
386+
struct query_declared_value_set_functions__ret { bool out_this_in_that; bool out_this_move_that; bool inout_this_in_that; bool inout_this_move_that; };
388387

389388

390389

@@ -828,8 +827,8 @@ namespace meta {
828827
[[nodiscard]] auto compiler_services::parse_statement(
829828

830829
std::string_view source
831-
) & ->
832-
std::unique_ptr<statement_node>
830+
) & -> std::unique_ptr<statement_node>
831+
833832
{
834833
CPP2_UFCS(push_back, generated_lines, std::vector<source_line>());
835834
auto lines {&CPP2_UFCS_0(back, generated_lines)};
@@ -878,8 +877,8 @@ auto newline_pos = CPP2_UFCS(find, source, '\n');
878877
);
879878
}
880879

881-
[[nodiscard]] auto compiler_services::position() const& ->
882-
source_position
880+
[[nodiscard]] auto compiler_services::position() const& -> source_position
881+
883882
{
884883
return { };
885884
}
@@ -1103,8 +1102,8 @@ declaration::declaration(declaration const& that)
11031102
[[nodiscard]] auto type_declaration::is_final() const& -> bool { return CPP2_UFCS_0(is_type_final, (*cpp2::assert_not_null(n))); }
11041103
[[nodiscard]] auto type_declaration::make_final() & -> bool { return CPP2_UFCS_0(make_type_final, (*cpp2::assert_not_null(n))); }
11051104

1106-
[[nodiscard]] auto type_declaration::get_member_functions() const& ->
1107-
std::vector<function_declaration>
1105+
[[nodiscard]] auto type_declaration::get_member_functions() const& -> std::vector<function_declaration>
1106+
11081107
{
11091108
std::vector<function_declaration> ret {};
11101109
for ( auto const& d : CPP2_UFCS(get_type_scope_declarations, (*cpp2::assert_not_null(n)), declaration_node::functions) ) {
@@ -1113,8 +1112,8 @@ declaration::declaration(declaration const& that)
11131112
return ret;
11141113
}
11151114

1116-
[[nodiscard]] auto type_declaration::get_member_objects() const& ->
1117-
std::vector<object_declaration>
1115+
[[nodiscard]] auto type_declaration::get_member_objects() const& -> std::vector<object_declaration>
1116+
11181117
{
11191118
std::vector<object_declaration> ret {};
11201119
for ( auto const& d : CPP2_UFCS(get_type_scope_declarations, (*cpp2::assert_not_null(n)), declaration_node::objects) ) {
@@ -1123,8 +1122,8 @@ declaration::declaration(declaration const& that)
11231122
return ret;
11241123
}
11251124

1126-
[[nodiscard]] auto type_declaration::get_member_types() const& ->
1127-
std::vector<type_declaration>
1125+
[[nodiscard]] auto type_declaration::get_member_types() const& -> std::vector<type_declaration>
1126+
11281127
{
11291128
std::vector<type_declaration> ret {};
11301129
for ( auto const& d : CPP2_UFCS(get_type_scope_declarations, (*cpp2::assert_not_null(n)), declaration_node::types) ) {
@@ -1133,8 +1132,8 @@ declaration::declaration(declaration const& that)
11331132
return ret;
11341133
}
11351134

1136-
[[nodiscard]] auto type_declaration::get_member_aliases() const& ->
1137-
std::vector<alias_declaration>
1135+
[[nodiscard]] auto type_declaration::get_member_aliases() const& -> std::vector<alias_declaration>
1136+
11381137
{
11391138
std::vector<alias_declaration> ret {};
11401139
for ( auto const& d : CPP2_UFCS(get_type_scope_declarations, (*cpp2::assert_not_null(n)), declaration_node::aliases) ) {
@@ -1143,8 +1142,8 @@ declaration::declaration(declaration const& that)
11431142
return ret;
11441143
}
11451144

1146-
[[nodiscard]] auto type_declaration::get_members() const& ->
1147-
std::vector<declaration>
1145+
[[nodiscard]] auto type_declaration::get_members() const& -> std::vector<declaration>
1146+
11481147
{
11491148
std::vector<declaration> ret {};
11501149
for ( auto const& d : CPP2_UFCS(get_type_scope_declarations, (*cpp2::assert_not_null(n)), declaration_node::all) ) {

0 commit comments

Comments
 (0)