Skip to content

Commit 3fbe27e

Browse files
committed
Let metafunctions replace specific members, and apply to basic_enum
Before, `basic_enum` was just removing all the statements in a type's body, not just the object declarations it was replacing. This has two problems: - It masked programmer errors that would normally have been diagnosed in sema, such as writing an assignment statement by accident (e.g., `wrong: @enum type = { oops = assignment; /* intended to write := here, but the errant statement was just silently removed */ }` - It disabled the ability for programmers to do things like write member functions of enumeration types Now that `basic_enum` removes only the data members that it processes, any other code inside the body will be diagnosed or allowed, as appropriate.
1 parent 7ae6b5a commit 3fbe27e

File tree

11 files changed

+276
-195
lines changed

11 files changed

+276
-195
lines changed

regression-tests/pure2-enum.cpp2

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,19 @@ skat_game: @enum type = {
88
null := 23;
99
}
1010

11-
rgb: @enum type = {
12-
red; // 0
13-
green; // 1
14-
blue; // 2
11+
duality: @enum type = {
12+
first;
13+
second;
14+
15+
flip: (inout this, val: duality) = {
16+
if val == first {
17+
value__ = second.value__;
18+
}
19+
else {
20+
[[assert: value__ == second.value__]]
21+
value__ = first.value__;
22+
}
23+
}
1524
}
1625

1726
file_attributes: @flag_enum<u8> type = {
@@ -22,6 +31,11 @@ file_attributes: @flag_enum<u8> type = {
2231
}
2332

2433
main: () = {
34+
janus := duality::second;
35+
std::cout << "janus is initially (janus.to_string())$\n";
36+
janus.flip( janus );
37+
std::cout << "janus is flipped to (janus.to_string())$\n";
38+
2539
// x : skat_game = 9; // error, can't construct skat_game from integer
2640

2741
x: skat_game = skat_game::clubs;

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
janus is initially second
2+
janus is flipped to first
13
x.to_string() is clubs
24
x2.to_string() is clubs
35
using << prints clubs

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
janus is initially second
2+
janus is flipped to first
13
x.to_string() is clubs
24
x2.to_string() is clubs
35
using << prints clubs

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
janus is initially second
2+
janus is flipped to first
13
x.to_string() is clubs
24
x2.to_string() is clubs
35
using << prints clubs

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
janus is initially second
2+
janus is flipped to first
13
x.to_string() is clubs
24
x2.to_string() is clubs
35
using << prints clubs

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

Lines changed: 55 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ class skat_game;
1212

1313

1414
#line 11 "pure2-enum.cpp2"
15-
class rgb;
15+
class duality;
1616

1717

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

2121

@@ -51,28 +51,27 @@ public: friend auto operator<<(std::ostream& o, cpp2::in<skat_game> val) -> std:
5151
#line 9 "pure2-enum.cpp2"
5252
};
5353

54-
class rgb {
55-
public: static const cpp2::i8 enumeration_count;
56-
private: cpp2::i8 value__; private: constexpr rgb(auto const& val);
54+
class duality {
55+
56+
#line 15 "pure2-enum.cpp2"
57+
public: auto flip(cpp2::in<duality> val) & -> void;
58+
59+
public: static const cpp2::i8 enumeration_count;
60+
private: cpp2::i8 value__; private: constexpr duality(auto const& val);
5761

58-
private: constexpr auto operator=(auto const& val) -> rgb& ;
62+
private: constexpr auto operator=(auto const& val) -> duality& ;
5963
public: [[nodiscard]] constexpr auto get_raw_value() const& -> cpp2::i8;
60-
public: constexpr rgb(rgb const& that);
61-
public: constexpr auto operator=(rgb const& that) -> rgb& ;
62-
public: constexpr rgb(rgb&& that) noexcept;
63-
public: constexpr auto operator=(rgb&& that) noexcept -> rgb& ;
64-
public: [[nodiscard]] auto operator<=>(rgb const& that) const& -> std::strong_ordering = default;
65-
public: static const rgb red;
66-
public: static const rgb green;
67-
public: static const rgb blue;
64+
public: constexpr duality(duality const& that);
65+
public: constexpr auto operator=(duality const& that) -> duality& ;
66+
public: constexpr duality(duality&& that) noexcept;
67+
public: constexpr auto operator=(duality&& that) noexcept -> duality& ;
68+
public: [[nodiscard]] auto operator<=>(duality const& that) const& -> std::strong_ordering = default;
69+
public: static const duality first;
70+
public: static const duality second;
6871
public: [[nodiscard]] auto to_string() const& -> std::string;
69-
public: friend auto operator<<(std::ostream& o, cpp2::in<rgb> val) -> std::ostream&;
72+
public: friend auto operator<<(std::ostream& o, cpp2::in<duality> val) -> std::ostream&;
7073

71-
#line 12 "pure2-enum.cpp2"
72-
// 0
73-
// 1
74-
// 2
75-
#line 15 "pure2-enum.cpp2"
74+
#line 24 "pure2-enum.cpp2"
7675
};
7776

7877
class file_attributes {
@@ -103,12 +102,12 @@ public: static const file_attributes none;
103102
public: [[nodiscard]] auto to_string() const& -> std::string;
104103
public: friend auto operator<<(std::ostream& o, cpp2::in<file_attributes> val) -> std::ostream&;
105104

106-
#line 18 "pure2-enum.cpp2"
105+
#line 27 "pure2-enum.cpp2"
107106
// 1
108107
// 2
109108
// 4
110109

111-
#line 22 "pure2-enum.cpp2"
110+
#line 31 "pure2-enum.cpp2"
112111
};
113112

114113
auto main() -> int;
@@ -159,38 +158,48 @@ inline constexpr skat_game skat_game::null = 23;
159158
}
160159

161160
[[nodiscard]] auto operator<<(std::ostream& o, cpp2::in<skat_game> val) -> std::ostream&{o << CPP2_UFCS_0(to_string, val);return o; }
162-
inline constexpr cpp2::i8 rgb::enumeration_count = 3;
161+
#line 15 "pure2-enum.cpp2"
162+
auto duality::flip(cpp2::in<duality> val) & -> void{
163+
if (val == first) {
164+
value__ = second.value__;
165+
}
166+
else {
167+
cpp2::Default.expects(value__ == second.value__, "");
168+
value__ = first.value__;
169+
}
170+
}
163171

164-
constexpr rgb::rgb(auto const& val)
172+
inline constexpr cpp2::i8 duality::enumeration_count = 2;
173+
174+
175+
constexpr duality::duality(auto const& val)
165176
: value__{ cpp2::unsafe_narrow<cpp2::i8>(val) } { }
166-
constexpr auto rgb::operator=(auto const& val) -> rgb& {
177+
178+
constexpr auto duality::operator=(auto const& val) -> duality& {
167179
value__ = cpp2::unsafe_narrow<cpp2::i8>(val);
168180
return *this; }
169-
[[nodiscard]] constexpr auto rgb::get_raw_value() const& -> cpp2::i8 { return value__; }
170-
constexpr rgb::rgb(rgb const& that)
181+
[[nodiscard]] constexpr auto duality::get_raw_value() const& -> cpp2::i8 { return value__; }
182+
constexpr duality::duality(duality const& that)
171183
: value__{ that.value__ }{}
172-
constexpr auto rgb::operator=(rgb const& that) -> rgb& {
184+
constexpr auto duality::operator=(duality const& that) -> duality& {
173185
value__ = that.value__;
174186
return *this;}
175-
constexpr rgb::rgb(rgb&& that) noexcept
187+
constexpr duality::duality(duality&& that) noexcept
176188
: value__{ std::move(that).value__ }{}
177-
constexpr auto rgb::operator=(rgb&& that) noexcept -> rgb& {
189+
constexpr auto duality::operator=(duality&& that) noexcept -> duality& {
178190
value__ = std::move(that).value__;
179191
return *this;}
180-
inline constexpr rgb rgb::red = 0;
192+
inline constexpr duality duality::first = 0;
181193

182-
inline constexpr rgb rgb::green = 1;
194+
inline constexpr duality duality::second = 1;
183195

184-
inline constexpr rgb rgb::blue = 2;
185-
186-
[[nodiscard]] auto rgb::to_string() const& -> std::string{
187-
if ((*this) == red) {return "red"; }
188-
if ((*this) == green) {return "green"; }
189-
if ((*this) == blue) {return "blue"; }
190-
return "invalid rgb value";
196+
[[nodiscard]] auto duality::to_string() const& -> std::string{
197+
if ((*this) == first) {return "first"; }
198+
if ((*this) == second) {return "second"; }
199+
return "invalid duality value";
191200
}
192201

193-
[[nodiscard]] auto operator<<(std::ostream& o, cpp2::in<rgb> val) -> std::ostream&{o << CPP2_UFCS_0(to_string, val);return o; }
202+
[[nodiscard]] auto operator<<(std::ostream& o, cpp2::in<duality> val) -> std::ostream&{o << CPP2_UFCS_0(to_string, val);return o; }
194203
inline constexpr cpp2::u8 file_attributes::enumeration_count = 4;
195204

196205
constexpr file_attributes::file_attributes(auto const& val)
@@ -242,8 +251,13 @@ inline constexpr file_attributes file_attributes::none = 0;
242251
}
243252

244253
[[nodiscard]] auto operator<<(std::ostream& o, cpp2::in<file_attributes> val) -> std::ostream&{o << CPP2_UFCS_0(to_string, val);return o; }
245-
#line 24 "pure2-enum.cpp2"
254+
#line 33 "pure2-enum.cpp2"
246255
auto main() -> int{
256+
auto janus {duality::second};
257+
std::cout << "janus is initially " + cpp2::to_string(CPP2_UFCS_0(to_string, janus)) + "\n";
258+
CPP2_UFCS(flip, janus, janus);
259+
std::cout << "janus is flipped to " + cpp2::to_string(CPP2_UFCS_0(to_string, std::move(janus))) + "\n";
260+
247261
// x : skat_game = 9; // error, can't construct skat_game from integer
248262

249263
skat_game x {skat_game::clubs};

regression-tests/test-results/version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
cppfront compiler v0.2.1 Build 8923:1137
2+
cppfront compiler v0.2.1 Build 8923:1630
33
Copyright(c) Herb Sutter All rights reserved
44

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

source/build.info

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
"8923:1137"
1+
"8923:1630"

source/parse.h

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2546,19 +2546,39 @@ struct declaration_node
25462546
return false;
25472547
}
25482548

2549+
auto type_remove_marked_members()
2550+
-> void
2551+
{
2552+
assert (is_type() && initializer && initializer->is_compound());
2553+
auto compound_stmt = initializer->get_if<compound_statement_node>();
2554+
assert (compound_stmt);
2555+
2556+
// Note: This loop is a careful use of the brittle STL "erase" idiom. Do not change this
2557+
// loop without carefully ensuring it remains safe against iterator invalidation.
2558+
// (Especially don't change this to a for loop with a "++i" iteration-expression.)
2559+
auto i = compound_stmt->statements.begin();
2560+
while (i != compound_stmt->statements.end())
2561+
{
2562+
if ((*i)->marked_for_removal) {
2563+
i = compound_stmt->statements.erase(i); // these two branches ...
2564+
}
2565+
else {
2566+
++i; // ... must stay together
2567+
}
2568+
}
2569+
}
2570+
25492571
auto type_remove_all_members()
25502572
-> void
25512573
{
2552-
assert (is_type() && initializer->is_compound());
2574+
assert (is_type() && initializer && initializer->is_compound());
25532575
auto body = initializer->get_if<compound_statement_node>();
25542576
assert (body);
25552577

2556-
// Drop all statements in the body
2578+
// Drop all statements in the body, which should self-deregister all our 'captures'
2579+
// - (only) statements in the body should have been able to refer to 'captures'
25572580
body->statements.clear();
2558-
2559-
// Then also drop captures - (only) statements in
2560-
// the body should have been able to refer to it
2561-
captures = {};
2581+
assert(captures.members.empty());
25622582
}
25632583

25642584
auto type_disable_member_function_generation()

0 commit comments

Comments
 (0)