Skip to content

Commit e28933c

Browse files
JohelEGPzaucy
authored andcommitted
fix(cpp1): emit discard with correct precedence (hsutter#570)
* test: add test case for discard precedence * fix(cpp1): emit discard with correct precedence * refactor: update comment
1 parent cab25c4 commit e28933c

14 files changed

+120
-37
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
quantity: type = {
2+
number: i32;
3+
operator=: (out this, _: std::in_place_t, x: i32) = {
4+
number = x;
5+
_ = _;
6+
}
7+
operator+=: (inout this, that) -> forward quantity = {
8+
_ = number += that.number;
9+
return this;
10+
}
11+
}
12+
13+
main: () = {
14+
x: quantity = (std::in_place, 1729);
15+
_ = x += x;
16+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
clang version 18.0.0 (https://git.uplinklabs.net/mirrors/llvm-project.git c0abd3814564a568dfc607c216e6407eaa314f46)
2+
Target: x86_64-pc-linux-gnu
3+
Thread model: posix
4+
InstalledDir: /home/johel/root/clang-main/bin

regression-tests/test-results/clang-18/pure2-bugfix-for-discard-precedence.cpp.execution

Whitespace-only changes.

regression-tests/test-results/clang-18/pure2-bugfix-for-discard-precedence.cpp.output

Whitespace-only changes.

regression-tests/test-results/mixed-captures-in-expressions-and-postconditions.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,6 @@ auto insert_at(cpp2::in<int> where, cpp2::in<int> val) -> void
4848
cpp2::Default.expects(cpp2::cmp_less_eq(0,where) && cpp2::cmp_less_eq(where,CPP2_UFCS_0(ssize, vec)), "");
4949
auto post_21_5 = cpp2::finally_success([_0 = CPP2_UFCS_0(ssize, vec)]{cpp2::Default.expects(CPP2_UFCS_0(ssize, vec)==_0 + 1, "");} );
5050
#line 23 "mixed-captures-in-expressions-and-postconditions.cpp2"
51-
(void) CPP2_UFCS(insert, vec, CPP2_UFCS_0(begin, vec) + where, val);
51+
static_cast<void>(CPP2_UFCS(insert, vec, CPP2_UFCS_0(begin, vec) + where, val));
5252
}
5353

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
2+
#define CPP2_USE_MODULES Yes
3+
4+
//=== Cpp2 type declarations ====================================================
5+
6+
7+
#include "cpp2util.h"
8+
9+
#line 1 "pure2-bugfix-for-discard-precedence.cpp2"
10+
class quantity;
11+
12+
13+
//=== Cpp2 type definitions and function declarations ===========================
14+
15+
#line 1 "pure2-bugfix-for-discard-precedence.cpp2"
16+
class quantity {
17+
private: cpp2::i32 number;
18+
public: explicit quantity(cpp2::in<std::in_place_t> _, cpp2::in<cpp2::i32> x);
19+
20+
21+
#line 7 "pure2-bugfix-for-discard-precedence.cpp2"
22+
public: [[nodiscard]] auto operator+=(quantity const& that) -> quantity&;
23+
24+
public: quantity(quantity const&) = delete; /* No 'that' constructor, suppress copy */
25+
public: auto operator=(quantity const&) -> void = delete;
26+
27+
28+
#line 11 "pure2-bugfix-for-discard-precedence.cpp2"
29+
};
30+
31+
auto main() -> int;
32+
33+
34+
//=== Cpp2 function definitions =================================================
35+
36+
37+
#line 3 "pure2-bugfix-for-discard-precedence.cpp2"
38+
quantity::quantity(cpp2::in<std::in_place_t> _, cpp2::in<cpp2::i32> x)
39+
: number{ x }
40+
#line 3 "pure2-bugfix-for-discard-precedence.cpp2"
41+
{
42+
43+
static_cast<void>(_);
44+
}
45+
[[nodiscard]] auto quantity::operator+=(quantity const& that) -> quantity&{
46+
static_cast<void>(number += that.number);
47+
return (*this);
48+
}
49+
50+
#line 13 "pure2-bugfix-for-discard-precedence.cpp2"
51+
auto main() -> int{
52+
quantity x {std::in_place, 1729};
53+
static_cast<void>(x += std::move(x));
54+
}
55+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pure2-bugfix-for-discard-precedence.cpp2... ok (all Cpp2, passes safety checks)
2+

regression-tests/test-results/pure2-inspect-expression-in-generic-function-multiple-types.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ auto test_generic(auto const& x, auto const& msg) -> void;
3131
test_generic(a, "any");
3232
test_generic(o, "optional<int>");
3333

34-
(void) CPP2_UFCS_TEMPLATE(emplace, (<0>), v, 1);
34+
static_cast<void>(CPP2_UFCS_TEMPLATE(emplace, (<0>), v, 1));
3535
a = 2;
3636
o = 3;
3737
test_generic(42, "int");

regression-tests/test-results/pure2-stdio-with-raii.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@
2424
[[nodiscard]] auto main() -> int{
2525
std::string s {"Freddy"};
2626
auto myfile {cpp2::fopen("xyzzy", "w")};
27-
(void) CPP2_UFCS(fprintf, std::move(myfile), "Hello %s with UFCS!", CPP2_UFCS_0(c_str, std::move(s)));
27+
static_cast<void>(CPP2_UFCS(fprintf, std::move(myfile), "Hello %s with UFCS!", CPP2_UFCS_0(c_str, std::move(s))));
2828
}
2929

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
[[nodiscard]] auto main() -> int{
2828
std::string s {"Fred"};
2929
auto myfile {fopen("xyzzy", "w")};
30-
(void) CPP2_UFCS(fprintf, myfile, "Hello %s with UFCS!", CPP2_UFCS_0(c_str, std::move(s)));
31-
(void) CPP2_UFCS_0(fclose, std::move(myfile));
30+
static_cast<void>(CPP2_UFCS(fprintf, myfile, "Hello %s with UFCS!", CPP2_UFCS_0(c_str, std::move(s))));
31+
static_cast<void>(CPP2_UFCS_0(fclose, std::move(myfile)));
3232
}
3333

regression-tests/test-results/pure2-type-safety-1.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ auto print(cpp2::in<std::string> msg, cpp2::in<bool> b) -> void;
4242

4343
std::cout << "\n";
4444

45-
(void) CPP2_UFCS_TEMPLATE(emplace, (<1>), v, 1);
45+
static_cast<void>(CPP2_UFCS_TEMPLATE(emplace, (<1>), v, 1));
4646
a = 2;
4747
o = 3;
4848
test_generic(42, "int");

regression-tests/test-results/pure2-type-safety-2-with-inspect-expression.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ auto test_generic(auto const& x, auto const& msg) -> void;
3131
test_generic(a, "any");
3232
test_generic(o, "optional<int>");
3333

34-
(void) CPP2_UFCS_TEMPLATE(emplace, (<2>), v, 1);
34+
static_cast<void>(CPP2_UFCS_TEMPLATE(emplace, (<2>), v, 1));
3535
a = 2;
3636
o = 3;
3737
test_generic(42, "int");

regression-tests/test-results/pure2-ufcs-member-access-and-chaining.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,23 +40,23 @@ extern int y;
4040
#line 1 "pure2-ufcs-member-access-and-chaining.cpp2"
4141
[[nodiscard]] auto main() -> int{
4242
auto i {42};
43-
(void) CPP2_UFCS_0(ufcs, std::move(i));
43+
static_cast<void>(CPP2_UFCS_0(ufcs, std::move(i)));
4444

4545
auto j {fun()};
46-
(void) CPP2_UFCS_0(ufcs, j.i);
46+
static_cast<void>(CPP2_UFCS_0(ufcs, j.i));
4747

48-
(void) CPP2_UFCS_0(ufcs, fun().i);
48+
static_cast<void>(CPP2_UFCS_0(ufcs, fun().i));
4949

5050
auto k {fun().i};
51-
(void) CPP2_UFCS_0(ufcs, std::move(k));
51+
static_cast<void>(CPP2_UFCS_0(ufcs, std::move(k)));
5252

53-
(void) CPP2_UFCS_0(ufcs, get_i(j));
53+
static_cast<void>(CPP2_UFCS_0(ufcs, get_i(j)));
5454

55-
(void) CPP2_UFCS_0(ufcs, get_i(fun()));
55+
static_cast<void>(CPP2_UFCS_0(ufcs, get_i(fun())));
5656

5757
auto res {CPP2_UFCS_0(ufcs, (42))};
5858

59-
(void) CPP2_UFCS_0(ufcs, (std::move(j).i));
59+
static_cast<void>(CPP2_UFCS_0(ufcs, (std::move(j).i)));
6060

6161
CPP2_UFCS_0(no_return, 42);
6262
}

source/cppfront.cpp

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ class positional_printer
197197
std::vector<comment> const* pcomments = {}; // Cpp2 comments data
198198
source const* psource = {};
199199
parser const* pparser = {};
200-
200+
201201
source_position curr_pos = {}; // current (line,col) in output
202202
lineno_t generated_pos_line = {}; // current line in generated output
203203
int last_line_indentation = {};
@@ -1229,7 +1229,7 @@ class cppfront
12291229

12301230
//---------------------------------------------------------------------
12311231
// Do lowered file prolog
1232-
//
1232+
//
12331233
// Only emit extra lines if we actually have Cpp2, because
12341234
// we want pure-Cpp1 files to pass through with zero changes
12351235
if (source.has_cpp2())
@@ -1287,7 +1287,7 @@ class cppfront
12871287
}
12881288
}
12891289

1290-
1290+
12911291
//---------------------------------------------------------------------
12921292
// Do phase1_type_defs_func_decls
12931293
//
@@ -1644,7 +1644,7 @@ class cppfront
16441644
{
16451645
add_move = false;
16461646
}
1647-
1647+
16481648
if (
16491649
emitting_move_that_function
16501650
&& *n.identifier == "that"
@@ -2261,7 +2261,7 @@ class cppfront
22612261
return;
22622262
} else if (
22632263
is_literal(tok->type()) || n.expression->expr->is_result_a_temporary_variable()
2264-
)
2264+
)
22652265
{
22662266
errors.emplace_back(
22672267
n.position(),
@@ -2557,7 +2557,7 @@ class cppfront
25572557
)
25582558
-> bool
25592559
{
2560-
if (!fun_node) {
2560+
if (!fun_node) {
25612561
return false;
25622562
}
25632563
if (addr_cnt > deref_cnt) {
@@ -2584,11 +2584,11 @@ class cppfront
25842584
)
25852585
-> bool
25862586
{
2587-
if (!type_id_node) {
2587+
if (!type_id_node) {
25882588
return false;
25892589
}
25902590
if (addr_cnt > deref_cnt) {
2591-
return true;
2591+
return true;
25922592
}
25932593

25942594
if ( type_id_node->dereference_of ) {
@@ -2765,7 +2765,7 @@ class cppfront
27652765
{
27662766
auto& unqual = std::get<id_expression_node::unqualified>(id->id);
27672767
assert(unqual);
2768-
// TODO: Generalize this:
2768+
// TODO: Generalize this:
27692769
// - we don't recognize pointer types from Cpp1
27702770
// - we don't deduce pointer types from parameter_declaration_list_node
27712771
if ( is_pointer_declaration(unqual->identifier) ) {
@@ -3452,8 +3452,8 @@ class cppfront
34523452
{
34533453
suppress_move_from_last_use = true;
34543454
}
3455-
// If it's "_ =" then emit (void)
3456-
bool suppress_operator = false;
3455+
// If it's "_ =" then emit static_cast<void>()
3456+
bool emit_discard = false;
34573457
if (
34583458
!n.terms.empty()
34593459
&& n.terms.front().op->type() == lexeme::Assignment
@@ -3462,8 +3462,8 @@ class cppfront
34623462
&& *n.expr->get_postfix_expression_node()->get_first_token_ignoring_this() == "_"
34633463
)
34643464
{
3465-
printer.print_cpp2( "(void)", n.position() );
3466-
suppress_operator = true;
3465+
printer.print_cpp2( "static_cast<void>(", n.position() );
3466+
emit_discard = true;
34673467
}
34683468
else
34693469
{
@@ -3514,6 +3514,7 @@ class cppfront
35143514
}
35153515
}
35163516

3517+
auto first = true;
35173518
for (auto const& x : n.terms) {
35183519
assert(x.op);
35193520
assert(x.expr);
@@ -3533,17 +3534,16 @@ class cppfront
35333534
else
35343535
{
35353536
// For the first operator only, if we are emitting a "_ =" discard
3536-
// then we've already emitted the cast to void and don't need the =
3537-
if (suppress_operator) {
3538-
assert( x.op->type() == lexeme::Assignment );
3539-
suppress_operator = false;
3540-
}
3541-
else {
3537+
// then we don't need the =
3538+
if (
3539+
!emit_discard
3540+
|| !first
3541+
) {
35423542
printer.print_cpp2(" ", n.position());
35433543
emit(*x.op);
3544+
printer.print_cpp2(" ", n.position());
35443545
}
3545-
printer.print_cpp2(" ", n.position());
3546-
3546+
35473547
// When assigning a single expression-list, we can
35483548
// take over direct control of emitting it without needing to
35493549
// go through the whole grammar, and surround it with braces
@@ -3561,6 +3561,12 @@ class cppfront
35613561
emit(*x.expr);
35623562
}
35633563
}
3564+
3565+
first = false;
3566+
}
3567+
// Finish emitting the "_ =" discard.
3568+
if (emit_discard) {
3569+
printer.print_cpp2( ")", n.position() );
35643570
}
35653571
}
35663572

@@ -4868,7 +4874,7 @@ class cppfront
48684874
}
48694875

48704876
// If this is a generated declaration (negative source line number),
4871-
// add a line break before
4877+
// add a line break before
48724878
if (
48734879
printer.get_phase() == printer.phase2_func_defs
48744880
&& n.position().lineno < 1
@@ -5504,7 +5510,7 @@ class cppfront
55045510
// A2) This is '(out this, move that)'
55055511
// and no '(inout this, move that)' was written by the user
55065512
// (*) and no '(inout this, that)' was written by the user (*)
5507-
//
5513+
//
55085514
// (*) This third test is to tie-break M2 and A2 in favor of M2. Both M2 and A2
55095515
// can generate a missing '(inout this, move that)', and if we have both
55105516
// options then we should prefer to use M2 (generate move assignment from

0 commit comments

Comments
 (0)