Skip to content

Commit c584b43

Browse files
committed
Generate memberwise constructor for @struct
Closes #1146 Also make pretty-print emit `_` for objects of deduced type, and not worry about extra trailing commas in parameter lists now that Cpp2 supports those
1 parent cced142 commit c584b43

File tree

4 files changed

+66
-41
lines changed

4 files changed

+66
-41
lines changed

regression-tests/test-results/gcc-14-c++2b/gcc-version.output

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
g++ (GCC) 14.1.1 20240607 (Red Hat 14.1.1-5)
1+
g++ (GCC) 14.1.1 20240701 (Red Hat 14.1.1-7)
22
Copyright (C) 2024 Free Software Foundation, Inc.
33
This is free software; see the source for copying conditions. There is NO
44
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

source/parse.h

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5111,11 +5111,8 @@ auto pretty_print_visualize(parameter_declaration_list_node const& n, int indent
51115111
space += std::string{"\n"} + pre(indent+1);
51125112
}
51135113

5114-
for (auto i = 0; auto& param : n.parameters) {
5115-
ret += space + pretty_print_visualize(*param, indent+1, is_template_param_list);
5116-
if (++i < std::ssize(n.parameters)) {
5117-
ret += ", ";
5118-
}
5114+
for (auto& param : n.parameters) {
5115+
ret += space + pretty_print_visualize(*param, indent+1, is_template_param_list) + ", ";
51195116
}
51205117

51215118
if (std::ssize(n.parameters) > 1) {
@@ -5296,11 +5293,9 @@ auto pretty_print_visualize(declaration_node const& n, int indent, bool include_
52965293
auto& type_id = std::get<declaration_node::an_object>(n.type);
52975294
assert(type_id);
52985295
ret += metafunctions
5299-
+ template_params;
5300-
if (!n.has_wildcard_type()) {
5301-
ret += " " + pretty_print_visualize(*type_id, indent);
5302-
}
5303-
ret += requires_clause
5296+
+ template_params
5297+
+ " " + pretty_print_visualize(*type_id, indent)
5298+
+ requires_clause
53045299
+ initializer;
53055300
}
53065301
else if (n.is_type()) {

source/reflect.h

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ class type_declaration;
3636
#line 592 "reflect.h2"
3737
class alias_declaration;
3838

39-
#line 965 "reflect.h2"
39+
#line 976 "reflect.h2"
4040
class value_member_info;
4141

42-
#line 1483 "reflect.h2"
42+
#line 1494 "reflect.h2"
4343
}
4444

4545
}
@@ -674,7 +674,7 @@ auto cpp1_rule_of_zero(meta::type_declaration& t) -> void;
674674
//
675675
auto cpp2_struct(meta::type_declaration& t) -> void;
676676

677-
#line 948 "reflect.h2"
677+
#line 959 "reflect.h2"
678678
//-----------------------------------------------------------------------
679679
//
680680
// "C enumerations constitute a curiously half-baked concept. ...
@@ -696,6 +696,9 @@ class value_member_info {
696696
public: std::string name;
697697
public: std::string type;
698698
public: std::string value;
699+
public: explicit value_member_info(auto const& name_, auto const& type_, auto const& value_);
700+
701+
#line 980 "reflect.h2"
699702
};
700703

701704
auto basic_enum(
@@ -704,7 +707,7 @@ auto basic_enum(
704707
cpp2::impl::in<bool> bitwise
705708
) -> void;
706709

707-
#line 1155 "reflect.h2"
710+
#line 1166 "reflect.h2"
708711
//-----------------------------------------------------------------------
709712
//
710713
// "An enum[...] is a totally ordered value type that stores a
@@ -716,7 +719,7 @@ auto basic_enum(
716719
//
717720
auto cpp2_enum(meta::type_declaration& t) -> void;
718721

719-
#line 1181 "reflect.h2"
722+
#line 1192 "reflect.h2"
720723
//-----------------------------------------------------------------------
721724
//
722725
// "flag_enum expresses an enumeration that stores values
@@ -729,7 +732,7 @@ auto cpp2_enum(meta::type_declaration& t) -> void;
729732
//
730733
auto flag_enum(meta::type_declaration& t) -> void;
731734

732-
#line 1213 "reflect.h2"
735+
#line 1224 "reflect.h2"
733736
//-----------------------------------------------------------------------
734737
//
735738
// "As with void*, programmers should know that unions [...] are
@@ -756,14 +759,14 @@ auto flag_enum(meta::type_declaration& t) -> void;
756759

757760
auto cpp2_union(meta::type_declaration& t) -> void;
758761

759-
#line 1366 "reflect.h2"
762+
#line 1377 "reflect.h2"
760763
//-----------------------------------------------------------------------
761764
//
762765
// print - output a pretty-printed visualization of t
763766
//
764767
auto print(cpp2::impl::in<meta::type_declaration> t) -> void;
765768

766-
#line 1376 "reflect.h2"
769+
#line 1387 "reflect.h2"
767770
//-----------------------------------------------------------------------
768771
//
769772
// apply_metafunctions
@@ -774,7 +777,7 @@ auto print(cpp2::impl::in<meta::type_declaration> t) -> void;
774777
auto const& error
775778
) -> bool;
776779

777-
#line 1483 "reflect.h2"
780+
#line 1494 "reflect.h2"
778781
}
779782

780783
}
@@ -1597,6 +1600,9 @@ auto cpp1_rule_of_zero(meta::type_declaration& t) -> void
15971600
#line 930 "reflect.h2"
15981601
auto cpp2_struct(meta::type_declaration& t) -> void
15991602
{
1603+
std::string ctor_params {};
1604+
std::string ctor_inits {};
1605+
16001606
for ( auto& m : CPP2_UFCS(get_members)(t) )
16011607
{
16021608
CPP2_UFCS(require)(m, CPP2_UFCS(make_public)(m),
@@ -1608,11 +1614,24 @@ auto cpp2_struct(meta::type_declaration& t) -> void
16081614
CPP2_UFCS(require)(t, !(CPP2_UFCS(has_name)(cpp2::move(mf), "operator=")),
16091615
"a struct may not have a user-defined operator=");
16101616
}
1617+
else {if (CPP2_UFCS(is_object)(m)) {
1618+
ctor_params += (cpp2::to_string(CPP2_UFCS(name)(m)) + "_, ");
1619+
ctor_inits += (cpp2::to_string(CPP2_UFCS(name)(m)) + " = " + cpp2::to_string(CPP2_UFCS(name)(m)) + "_; ");
1620+
}}
16111621
}
16121622
CPP2_UFCS(cpp1_rule_of_zero)(t);
1623+
1624+
// However, to enable construction from values requires a
1625+
// constructor... an exception to the rule of zero
1626+
CPP2_UFCS(add_member)(t, (" operator=: (out this, " + cpp2::to_string(cpp2::move(ctor_params)) + ") = { " + cpp2::to_string(cpp2::move(ctor_inits)) + " }"));
16131627
}
16141628

1615-
#line 971 "reflect.h2"
1629+
value_member_info::value_member_info(auto const& name_, auto const& type_, auto const& value_)
1630+
: name{ name_ }
1631+
, type{ type_ }
1632+
, value{ value_ }{}
1633+
1634+
#line 982 "reflect.h2"
16161635
auto basic_enum(
16171636
meta::type_declaration& t,
16181637
auto const& nextval,
@@ -1637,7 +1656,7 @@ auto basic_enum(
16371656
{
16381657
std::string value{"-1"};
16391658

1640-
#line 994 "reflect.h2"
1659+
#line 1005 "reflect.h2"
16411660
for (
16421661
auto const& m : CPP2_UFCS(get_members)(t) )
16431662
if ( CPP2_UFCS(is_member_object)(m))
@@ -1676,7 +1695,7 @@ std::string value{"-1"};
16761695
}
16771696
}
16781697

1679-
#line 1031 "reflect.h2"
1698+
#line 1042 "reflect.h2"
16801699
if ((CPP2_UFCS(empty)(enumerators))) {
16811700
CPP2_UFCS(error)(t, "an enumeration must contain at least one enumerator value");
16821701
return ;
@@ -1722,7 +1741,7 @@ std::string value{"-1"};
17221741
}
17231742
}
17241743

1725-
#line 1077 "reflect.h2"
1744+
#line 1088 "reflect.h2"
17261745
// 2. Replace: Erase the contents and replace with modified contents
17271746
//
17281747
// Note that most values and functions are declared as '==' compile-time values, i.e. Cpp1 'constexpr'
@@ -1770,7 +1789,7 @@ std::string to_string{" to_string: (this) -> std::string = { \n"};
17701789

17711790
// Provide a 'to_string' function to print enumerator name(s)
17721791

1773-
#line 1122 "reflect.h2"
1792+
#line 1133 "reflect.h2"
17741793
{
17751794
if (bitwise) {
17761795
to_string += " _ret : std::string = \"(\";\n";
@@ -1802,10 +1821,10 @@ std::string to_string{" to_string: (this) -> std::string = { \n"};
18021821
CPP2_UFCS(add_member)(t, cpp2::move(to_string));
18031822
}
18041823
}
1805-
#line 1152 "reflect.h2"
1824+
#line 1163 "reflect.h2"
18061825
}
18071826

1808-
#line 1164 "reflect.h2"
1827+
#line 1175 "reflect.h2"
18091828
auto cpp2_enum(meta::type_declaration& t) -> void
18101829
{
18111830
// Let basic_enum do its thing, with an incrementing value generator
@@ -1822,7 +1841,7 @@ auto cpp2_enum(meta::type_declaration& t) -> void
18221841
);
18231842
}
18241843

1825-
#line 1191 "reflect.h2"
1844+
#line 1202 "reflect.h2"
18261845
auto flag_enum(meta::type_declaration& t) -> void
18271846
{
18281847
// Let basic_enum do its thing, with a power-of-two value generator
@@ -1844,7 +1863,7 @@ auto flag_enum(meta::type_declaration& t) -> void
18441863
);
18451864
}
18461865

1847-
#line 1237 "reflect.h2"
1866+
#line 1248 "reflect.h2"
18481867
auto cpp2_union(meta::type_declaration& t) -> void
18491868
{
18501869
std::vector<value_member_info> alternatives {};
@@ -1853,7 +1872,7 @@ auto value{0};
18531872

18541873
// 1. Gather: All the user-written members, and find/compute the max size
18551874

1856-
#line 1244 "reflect.h2"
1875+
#line 1255 "reflect.h2"
18571876
for (
18581877

18591878
auto const& m : CPP2_UFCS(get_members)(t) ) { do
@@ -1879,7 +1898,7 @@ auto value{0};
18791898
} while (false); ++value; }
18801899
}
18811900

1882-
#line 1268 "reflect.h2"
1901+
#line 1279 "reflect.h2"
18831902
std::string discriminator_type {};
18841903
if (cpp2::impl::cmp_less(CPP2_UFCS(ssize)(alternatives),std::numeric_limits<cpp2::i8>::max())) {
18851904
discriminator_type = "i8";
@@ -1894,7 +1913,7 @@ auto value{0};
18941913
discriminator_type = "i64";
18951914
}}}
18961915

1897-
#line 1283 "reflect.h2"
1916+
#line 1294 "reflect.h2"
18981917
// 2. Replace: Erase the contents and replace with modified contents
18991918

19001919
CPP2_UFCS(remove_marked_members)(t);
@@ -1903,7 +1922,7 @@ std::string storage{" _storage: cpp2::aligned_storage<cpp2::max( "};
19031922

19041923
// Provide storage
19051924

1906-
#line 1289 "reflect.h2"
1925+
#line 1300 "reflect.h2"
19071926
{
19081927
for (
19091928
auto const& e : alternatives ) {
@@ -1923,7 +1942,7 @@ std::string storage{" _storage: cpp2::aligned_storage<cpp2::max( "};
19231942
}
19241943

19251944
// Provide discriminator
1926-
#line 1307 "reflect.h2"
1945+
#line 1318 "reflect.h2"
19271946
CPP2_UFCS(add_member)(t, (" _discriminator: " + cpp2::to_string(cpp2::move(discriminator_type)) + " = -1;\n"));
19281947

19291948
// Add the alternatives: is_alternative, get_alternative, and set_alternative
@@ -1945,7 +1964,7 @@ std::string destroy{" private _destroy: (inout this) = {\n"};
19451964

19461965
// Add destroy
19471966

1948-
#line 1326 "reflect.h2"
1967+
#line 1337 "reflect.h2"
19491968
{
19501969
for (
19511970
auto const& a : alternatives ) {
@@ -1959,7 +1978,7 @@ std::string destroy{" private _destroy: (inout this) = {\n"};
19591978
}
19601979

19611980
// Add the destructor
1962-
#line 1338 "reflect.h2"
1981+
#line 1349 "reflect.h2"
19631982
CPP2_UFCS(add_member)(t, " operator=: (move this) = { _destroy(); _ = this; }");
19641983

19651984
// Add default constructor
@@ -1969,7 +1988,7 @@ std::string value_set{""};
19691988

19701989
// Add copy/move construction and assignment
19711990

1972-
#line 1345 "reflect.h2"
1991+
#line 1356 "reflect.h2"
19731992
{
19741993
for (
19751994
auto const& a : cpp2::move(alternatives) ) {
@@ -1989,16 +2008,16 @@ std::string value_set{""};
19892008
);
19902009
}
19912010
}
1992-
#line 1363 "reflect.h2"
2011+
#line 1374 "reflect.h2"
19932012
}
19942013

1995-
#line 1370 "reflect.h2"
2014+
#line 1381 "reflect.h2"
19962015
auto print(cpp2::impl::in<meta::type_declaration> t) -> void
19972016
{
19982017
std::cout << CPP2_UFCS(print)(t) << "\n";
19992018
}
20002019

2001-
#line 1380 "reflect.h2"
2020+
#line 1391 "reflect.h2"
20022021
[[nodiscard]] auto apply_metafunctions(
20032022
declaration_node& n,
20042023
type_declaration& rtype,
@@ -2101,7 +2120,7 @@ auto print(cpp2::impl::in<meta::type_declaration> t) -> void
21012120
return true;
21022121
}
21032122

2104-
#line 1483 "reflect.h2"
2123+
#line 1494 "reflect.h2"
21052124
}
21062125

21072126
}

source/reflect.h2

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -929,6 +929,9 @@ cpp1_rule_of_zero: (inout t: meta::type_declaration) =
929929
//
930930
struct: (inout t: meta::type_declaration) =
931931
{
932+
ctor_params: std::string = ();
933+
ctor_inits : std::string = ();
934+
932935
for t.get_members() do (inout m)
933936
{
934937
m.require( m.make_public(),
@@ -940,8 +943,16 @@ struct: (inout t: meta::type_declaration) =
940943
t.require( !mf.has_name("operator="),
941944
"a struct may not have a user-defined operator=");
942945
}
946+
else if m.is_object() {
947+
ctor_params += "(m.name())$_, ";
948+
ctor_inits += "(m.name())$ = (m.name())$_; ";
949+
}
943950
}
944951
t.cpp1_rule_of_zero();
952+
953+
// However, to enable construction from values requires a
954+
// constructor... an exception to the rule of zero
955+
t.add_member(" operator=: (out this, (ctor_params)$) = { (ctor_inits)$ }");
945956
}
946957

947958

0 commit comments

Comments
 (0)