Skip to content

Commit ecd3726

Browse files
committed
Fix bugs in generating flag enum string representations
1 parent 43822ae commit ecd3726

File tree

11 files changed

+246
-33
lines changed

11 files changed

+246
-33
lines changed

include/cpp2util.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ using __uchar = unsigned char; // normally use u8 instead
286286
//-----------------------------------------------------------------------
287287
//
288288

289-
auto max(auto... values) {
289+
constexpr auto max(auto... values) {
290290
return std::max( { values... } );
291291
}
292292

regression-tests/pure2-enum.cpp2

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

2-
32
skat_game: @enum type = {
43
diamonds := 9;
54
hearts; // 10
@@ -71,6 +70,14 @@ main: () = {
7170

7271
f2 := file_attributes::cached;
7372

73+
std::cout << "f is " << f << "\n";
74+
std::cout << "f2 is " << f2 << "\n";
75+
76+
f2.clear( f2 );
77+
std::cout << "f2 is " << f2 << "\n";
78+
f2.set(file_attributes::cached);
79+
std::cout << "f2 is " << f2 << "\n";
80+
7481
std::cout << "f as int is (f as int )$\n";
7582
std::cout << "f2 as int is (f2 as int )$\n";
7683

regression-tests/test-results/clang-12/pure2-enum.cpp.execution

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ using << prints clubs
44
with if else: clubs
55
with inspect: clubs
66

7+
f is (cached)
8+
f2 is (cached)
9+
f2 is (none)
10+
f2 is (cached)
711
f as int is 1
812
f2 as int is 1
913
f is (f2) is 1

regression-tests/test-results/gcc-10/pure2-enum.cpp.execution

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ using << prints clubs
44
with if else: clubs
55
with inspect: clubs
66

7+
f is (cached)
8+
f2 is (cached)
9+
f2 is (none)
10+
f2 is (cached)
711
f as int is 1
812
f2 as int is 1
913
f is (f2) is 1

regression-tests/test-results/gcc-13/pure2-enum.cpp.execution

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ using << prints clubs
44
with if else: clubs
55
with inspect: clubs
66

7+
f is (cached)
8+
f2 is (cached)
9+
f2 is (none)
10+
f2 is (cached)
711
f as int is 1
812
f2 as int is 1
913
f is (f2) is 1

regression-tests/test-results/msvc-2022/pure2-enum.cpp.execution

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ using << prints clubs
44
with if else: clubs
55
with inspect: clubs
66

7+
f is (cached)
8+
f2 is (cached)
9+
f2 is (none)
10+
f2 is (cached)
711
f as int is 1
812
f2 as int is 1
913
f is (f2) is 1

regression-tests/test-results/pure2-enum.cpp

+23-13
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,22 @@
77
#include "cpp2util.h"
88

99

10-
#line 3 "pure2-enum.cpp2"
10+
#line 2 "pure2-enum.cpp2"
1111
class skat_game;
1212

1313

14-
#line 12 "pure2-enum.cpp2"
14+
#line 11 "pure2-enum.cpp2"
1515
class rgb;
1616

1717

18-
#line 18 "pure2-enum.cpp2"
18+
#line 17 "pure2-enum.cpp2"
1919
class file_attributes;
2020

2121

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

2424

25-
#line 3 "pure2-enum.cpp2"
25+
#line 2 "pure2-enum.cpp2"
2626
class skat_game: public cpp2::strict_value<cpp2::i8,skat_game,0> {
2727
public: skat_game(cpp2::in<cpp2::strict_value<cpp2::i8,skat_game,0>> value);
2828
public: auto static constexpr diamonds = cpp2::strict_value<cpp2::i8,skat_game,0>(9);
@@ -42,7 +42,7 @@ public: explicit skat_game();
4242
// 11
4343
// 12
4444

45-
#line 10 "pure2-enum.cpp2"
45+
#line 9 "pure2-enum.cpp2"
4646
};
4747

4848
class rgb: public cpp2::strict_value<cpp2::i8,rgb,0> {
@@ -59,7 +59,7 @@ public: explicit rgb();
5959
// 0
6060
// 1
6161
// 2
62-
#line 16 "pure2-enum.cpp2"
62+
#line 15 "pure2-enum.cpp2"
6363
};
6464

6565
class file_attributes: public cpp2::strict_value<cpp2::u8,file_attributes,1> {
@@ -79,7 +79,7 @@ public: explicit file_attributes();
7979
// 2
8080
// 4
8181

82-
#line 23 "pure2-enum.cpp2"
82+
#line 22 "pure2-enum.cpp2"
8383
};
8484

8585
auto main() -> int;
@@ -142,12 +142,14 @@ file_attributes::file_attributes(cpp2::in<cpp2::strict_value<cpp2::u8,file_attri
142142
[[nodiscard]] auto file_attributes::to_string(cpp2::in<cpp2::strict_value<cpp2::u8,file_attributes,1>> value) -> std::string{
143143

144144
std::string ret {};
145+
146+
std::string comma {};
145147
ret = "(";
146-
if (value & (cached)) {ret += "cached";}
147-
if (value & (current)) {ret += std::string(", ") + "current";}
148-
if (value & (obsolete)) {ret += std::string(", ") + "obsolete";}
149-
if (value & (cached_and_current)) {ret += std::string(", ") + "cached_and_current";}
150-
if (value & (none)) {ret += std::string(", ") + "none";}
148+
if ((value & cached) == cached) {ret += comma + "cached";comma = ", ";}
149+
if ((value & current) == current) {ret += comma + "current";comma = ", ";}
150+
if ((value & obsolete) == obsolete) {ret += comma + "obsolete";comma = ", ";}
151+
if ((value & cached_and_current) == cached_and_current) {ret += comma + "cached_and_current";comma = ", ";}
152+
if (value == none) {ret += comma + "none";comma = ", ";}
151153
if (CPP2_UFCS_0(empty, ret)) {ret = "(invalid file_attributes enumerator value)";}
152154
return ret + ")";
153155
}
@@ -158,7 +160,7 @@ file_attributes::file_attributes(file_attributes const& that)
158160
file_attributes::file_attributes()
159161
: cpp2::strict_value<cpp2::u8,file_attributes,1>{ }{}
160162

161-
#line 25 "pure2-enum.cpp2"
163+
#line 24 "pure2-enum.cpp2"
162164
auto main() -> int{
163165
// x : skat_game = 9; // error, can't construct skat_game from integer
164166

@@ -208,6 +210,14 @@ auto main() -> int{
208210

209211
auto f2 {file_attributes::cached};
210212

213+
std::cout << "f is " << f << "\n";
214+
std::cout << "f2 is " << f2 << "\n";
215+
216+
CPP2_UFCS(clear, f2, f2);
217+
std::cout << "f2 is " << f2 << "\n";
218+
CPP2_UFCS(set, f2, file_attributes::cached);
219+
std::cout << "f2 is " << f2 << "\n";
220+
211221
std::cout << "f as int is " + cpp2::to_string(cpp2::as_<int>(f)) + "\n";
212222
std::cout << "f2 as int is " + cpp2::to_string(cpp2::as_<int>(f2)) + "\n";
213223

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 8910:0856
2+
cppfront compiler v0.2.1 Build 8910:1255
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-
"8910:0856"
1+
"8910:1255"

source/reflect.h

+104-12
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class alias_declaration;
3838
#line 807 "reflect.h2"
3939
class value_member_info;
4040

41-
#line 1030 "reflect.h2"
41+
#line 1115 "reflect.h2"
4242
}
4343
}
4444

@@ -627,7 +627,7 @@ struct basic_enum__ret { std::string underlying_type; std::string strict_underly
627627
cpp2::in<bool> bitwise
628628
) -> basic_enum__ret;
629629

630-
#line 967 "reflect.h2"
630+
#line 974 "reflect.h2"
631631
//-----------------------------------------------------------------------
632632
//
633633
// "An enum[...] is a totally ordered value type that stores a
@@ -639,7 +639,7 @@ struct basic_enum__ret { std::string underlying_type; std::string strict_underly
639639
//
640640
auto cpp2_enum(meta::type_declaration& t) -> void;
641641

642-
#line 992 "reflect.h2"
642+
#line 999 "reflect.h2"
643643
//-----------------------------------------------------------------------
644644
//
645645
// "flag_enum expresses an enumeration that stores values
@@ -652,8 +652,34 @@ auto cpp2_enum(meta::type_declaration& t) -> void;
652652
//
653653
auto flag_enum(meta::type_declaration& t) -> void;
654654

655-
#line 1027 "reflect.h2"
655+
#line 1034 "reflect.h2"
656+
//-----------------------------------------------------------------------
657+
//
658+
// "As with void*, programmers should know that unions [...] are
659+
// inherently dangerous, should be avoided wherever possible,
660+
// and should be handled with special care when actually needed."
661+
//
662+
// -- Stroustrup (The Design and Evolution of C++, 14.3.4.1)
663+
//
664+
// "C++17 needs a type-safe union... The implications of the
665+
// consensus `variant` design are well understood and have been
666+
// explored over several LEWG discussions, over a thousand emails,
667+
// a joint LEWG/EWG session, and not to mention 12 years of
668+
// experience with Boost and other libraries."
669+
//
670+
// -- Axel Naumann, in P0088 (wg21.link/p0088),
671+
// the adopted proposal for C++17 std::variant
672+
//
673+
//-----------------------------------------------------------------------
674+
//
675+
// union
676+
//
677+
// a type that contains exactly one of a fixed set of values at a time
656678
//
679+
680+
auto cpp2_union(meta::type_declaration& t) -> void;
681+
682+
#line 1113 "reflect.h2"
657683
//=======================================================================
658684
// Switch to Cpp1 and close subnamespace meta
659685
}
@@ -722,8 +748,11 @@ auto parser::apply_type_meta_functions( declaration_node& n )
722748
else if (name == "flag_enum") {
723749
flag_enum( rtype );
724750
}
751+
else if (name == "union") {
752+
cpp2_union( rtype );
753+
}
725754
else {
726-
error( "(temporary alpha limitation) unrecognized metafunction name '" + name + "' - currently the supported names are: interface, polymorphic_base, ordered, weakly_ordered, partially_ordered, copyable, basic_value, value, weakly_ordered_value, partially_ordered_value, struct, enum, flag_enum" );
755+
error( "(temporary alpha limitation) unrecognized metafunction name '" + name + "' - currently the supported names are: interface, polymorphic_base, ordered, weakly_ordered, partially_ordered, copyable, basic_value, value, weakly_ordered_value, partially_ordered_value, struct, enum, flag_enum, union" );
727756
return false;
728757
}
729758
}
@@ -1442,16 +1471,23 @@ cpp2::i64 value = -1;
14421471
to_string += " ret: std::string = ();\n";
14431472
auto first {true};
14441473

1474+
if (bitwise) {
1475+
to_string += " comma: std::string = ();\n";
1476+
}
1477+
14451478
for (
14461479

14471480
auto const& e : enumerators ) { do {
14481481
if (bitwise) {
1449-
std::string comma {"std::string(\", \") + "};
14501482
if (first) {
14511483
to_string += " ret = \"(\";\n";
1452-
comma = "";
14531484
}
1454-
to_string += " if value & (" + cpp2::to_string(e.name) + ") { ret += " + cpp2::to_string(comma) + "\"" + cpp2::to_string(e.name) + "\"; }\n";
1485+
if (e.name == "none") { // a "none" flag should match if no bits set
1486+
to_string += " if value == " + cpp2::to_string(e.name) + " { ret += comma + \"" + cpp2::to_string(e.name) + "\"; comma = \", \"; }\n";
1487+
}
1488+
else { // other flags need to be &-ed
1489+
to_string += " if (value & " + cpp2::to_string(e.name) + ") == " + cpp2::to_string(e.name) + " { ret += comma + \"" + cpp2::to_string(e.name) + "\"; comma = \", \"; }\n";
1490+
}
14551491
}
14561492
else {
14571493
std::string else_ {"else "};
@@ -1477,13 +1513,13 @@ cpp2::i64 value = -1;
14771513
CPP2_UFCS(require, t, CPP2_UFCS(add_member, t, " to_string: (this) -> std::string = { return " + cpp2::to_string(CPP2_UFCS_0(name, t)) + "::to_string(this); }"),
14781514
"could not add to_string member function");
14791515

1480-
#line 961 "reflect.h2"
1516+
#line 968 "reflect.h2"
14811517
// 3. A basic_enum is-a value type
14821518

14831519
CPP2_UFCS_0(basic_value, t);
14841520
return { std::move(underlying_type), std::move(strict_underlying_type.value()) }; }
14851521

1486-
#line 976 "reflect.h2"
1522+
#line 983 "reflect.h2"
14871523
auto cpp2_enum(meta::type_declaration& t) -> void
14881524
{
14891525
// Let basic_enum do its thing, with an incrementing value generator
@@ -1499,7 +1535,7 @@ auto cpp2_enum(meta::type_declaration& t) -> void
14991535
));
15001536
}
15011537

1502-
#line 1002 "reflect.h2"
1538+
#line 1009 "reflect.h2"
15031539
auto flag_enum(meta::type_declaration& t) -> void
15041540
{
15051541
// Add "none" member as a regular name to signify "no flags set"
@@ -1524,7 +1560,63 @@ auto flag_enum(meta::type_declaration& t) -> void
15241560
));
15251561
}
15261562

1527-
#line 1030 "reflect.h2"
1563+
#line 1058 "reflect.h2"
1564+
auto cpp2_union(meta::type_declaration& t) -> void
1565+
{
1566+
std::vector<value_member_info> alternatives {};
1567+
1568+
// 1. Gather: All the user-written members, and find/compute the max size
1569+
1570+
//(copy first := true)
1571+
for (
1572+
//next first = false
1573+
auto const& m : CPP2_UFCS_0(get_members, t) )
1574+
{
1575+
CPP2_UFCS(require, m, (CPP2_UFCS_0(is_public, m) || CPP2_UFCS_0(is_default_access, m)) && CPP2_UFCS_0(is_object, m),
1576+
"a union alternative cannot be protected or private");
1577+
1578+
if (CPP2_UFCS_0(is_object, m)) {
1579+
auto mo {CPP2_UFCS_0(as_object, m)};
1580+
1581+
// Adding local variable 'e' to work around a Clang warning
1582+
value_member_info e {cpp2::as_<std::string>(CPP2_UFCS_0(name, mo)), CPP2_UFCS_0(type, mo), cpp2::as_<std::string>(CPP2_UFCS_0(initializer, mo))};
1583+
CPP2_UFCS(push_back, alternatives, e);
1584+
}
1585+
}
1586+
1587+
#line 1082 "reflect.h2"
1588+
// 2. Replace: Erase the contents and replace with modified contents
1589+
1590+
CPP2_UFCS_0(remove_all_members, t);
1591+
1592+
// Compute the size
1593+
std::string Size {"Size :== cpp2::max( "};
1594+
{
1595+
std::string comma = "";
1596+
1597+
#line 1090 "reflect.h2"
1598+
for (
1599+
1600+
auto const& e : alternatives ) { do {
1601+
Size += comma + "sizeof(" + cpp2::to_string(e.type) + ")";
1602+
} while (false); comma = ", "; }
1603+
}
1604+
1605+
#line 1096 "reflect.h2"
1606+
Size += " );\n";
1607+
CPP2_UFCS(require, t, CPP2_UFCS(add_member, t, std::move(Size)),
1608+
"could not add Size");
1609+
1610+
#line 1102 "reflect.h2"
1611+
// TODO
1612+
1613+
#line 1106 "reflect.h2"
1614+
//// 3. A basic_enum is-a value
1615+
1616+
//t.value();
1617+
}
1618+
1619+
#line 1115 "reflect.h2"
15281620
}
15291621
}
15301622

0 commit comments

Comments
 (0)