Skip to content

Commit 08806e3

Browse files
JohelEGPMaxSagebaumhsutter
authored
fix(cpp1): emit requires clause in forward declaration (#486)
* fix(cpp1): emit requires clause in forward declaration * refactor: prevent warning on token-eating macro Co-authored-by: Max Sagebaum <[email protected]> Signed-off-by: Johel Ernesto Guerrero Peña <[email protected]> * test: add `test-results/gcc-13` * Delete gcc-version.output Signed-off-by: Herb Sutter <[email protected]> --------- Signed-off-by: Johel Ernesto Guerrero Peña <[email protected]> Signed-off-by: Herb Sutter <[email protected]> Co-authored-by: Max Sagebaum <[email protected]> Co-authored-by: Herb Sutter <[email protected]>
1 parent 8351bd5 commit 08806e3

11 files changed

+128
-54
lines changed

include/cpp2util.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1771,5 +1771,12 @@ inline constexpr auto as_() -> decltype(auto)
17711771

17721772
using cpp2::cpp2_new;
17731773

1774+
// Workaround GCC 10 not supporting requires in forward declarations in some cases.
1775+
// See commit 5a0d77f8e297902c0b9712c5aafb6208cfa4c139.
1776+
#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ == 10
1777+
#define CPP2_REQUIRES(...) /* empty */
1778+
#else
1779+
#define CPP2_REQUIRES(...) requires (__VA_ARGS__)
1780+
#endif
17741781

17751782
#endif
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
element: type = {
2+
name: std::string;
3+
operator=: (out this, forward n: std::string) = { name = n; }
4+
}
5+
main: () = { }

regression-tests/test-results/gcc-13/pure2-bugfix-for-requires-clause-in-forward-declaration.cpp.execution

Whitespace-only changes.

regression-tests/test-results/gcc-13/pure2-bugfix-for-requires-clause-in-forward-declaration.cpp.output

Whitespace-only changes.

regression-tests/test-results/mixed-forwarding.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,17 @@ auto copy_from(auto x) -> void;
2525
auto use(auto const& x) -> void;
2626

2727
// invoking each of these with an rvalue std::pair argument ...
28-
auto apply_implicit_forward(auto&& t) -> void;
28+
auto apply_implicit_forward(auto&& t) -> void
29+
CPP2_REQUIRES (std::is_same_v<CPP2_TYPEOF(t), std::pair<X,X>>)
30+
#line 16 "mixed-forwarding.cpp2"
31+
;
2932

3033

3134
#line 20 "mixed-forwarding.cpp2"
32-
auto apply_explicit_forward(auto&& t) -> void;
35+
auto apply_explicit_forward(auto&& t) -> void
36+
CPP2_REQUIRES (std::is_same_v<CPP2_TYPEOF(t), std::pair<X,X>>)
37+
#line 20 "mixed-forwarding.cpp2"
38+
;
3339

3440

3541
#line 25 "mixed-forwarding.cpp2"

regression-tests/test-results/mixed-parameter-passing-with-forward.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ auto parameter_styles(
2323
std::string& c,
2424
std::string&& d,
2525
auto&& e
26-
) -> void;
26+
) -> void
27+
CPP2_REQUIRES (std::is_same_v<CPP2_TYPEOF(e), std::string>)
28+
#line 8 "mixed-parameter-passing-with-forward.cpp2"
29+
;
2730

2831
#line 42 "mixed-parameter-passing-with-forward.cpp2"
2932
[[nodiscard]] auto main() -> int;
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-requires-clause-in-forward-declaration.cpp2"
10+
class element;
11+
12+
13+
//=== Cpp2 type definitions and function declarations ===========================
14+
15+
#line 1 "pure2-bugfix-for-requires-clause-in-forward-declaration.cpp2"
16+
class element {
17+
private: std::string name;
18+
public: explicit element(auto&& n)
19+
CPP2_REQUIRES (std::is_same_v<CPP2_TYPEOF(n), std::string>)
20+
#line 3 "pure2-bugfix-for-requires-clause-in-forward-declaration.cpp2"
21+
;
22+
#line 3 "pure2-bugfix-for-requires-clause-in-forward-declaration.cpp2"
23+
public: auto operator=(auto&& n) -> element&
24+
CPP2_REQUIRES (std::is_same_v<CPP2_TYPEOF(n), std::string>)
25+
#line 3 "pure2-bugfix-for-requires-clause-in-forward-declaration.cpp2"
26+
;
27+
28+
public: element(element const&) = delete; /* No 'that' constructor, suppress copy */
29+
public: auto operator=(element const&) -> void = delete;
30+
#line 4 "pure2-bugfix-for-requires-clause-in-forward-declaration.cpp2"
31+
};
32+
auto main() -> int;
33+
34+
35+
//=== Cpp2 function definitions =================================================
36+
37+
38+
#line 3 "pure2-bugfix-for-requires-clause-in-forward-declaration.cpp2"
39+
element::element(auto&& n)
40+
requires (std::is_same_v<CPP2_TYPEOF(n), std::string>)
41+
: name{ CPP2_FORWARD(n) }
42+
#line 3 "pure2-bugfix-for-requires-clause-in-forward-declaration.cpp2"
43+
{}
44+
#line 3 "pure2-bugfix-for-requires-clause-in-forward-declaration.cpp2"
45+
auto element::operator=(auto&& n) -> element&
46+
requires (std::is_same_v<CPP2_TYPEOF(n), std::string>)
47+
#line 3 "pure2-bugfix-for-requires-clause-in-forward-declaration.cpp2"
48+
{
49+
name = CPP2_FORWARD(n);
50+
return *this;
51+
#line 3 "pure2-bugfix-for-requires-clause-in-forward-declaration.cpp2"
52+
}
53+
54+
auto main() -> int{}
55+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pure2-bugfix-for-requires-clause-in-forward-declaration.cpp2... ok (all Cpp2, passes safety checks)
2+

regression-tests/test-results/pure2-function-multiple-forward-arguments.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
//=== Cpp2 type definitions and function declarations ===========================
1212

1313
#line 1 "pure2-function-multiple-forward-arguments.cpp2"
14-
auto fun(auto&& s1, auto&& s2, auto&& s3) -> void;
14+
auto fun(auto&& s1, auto&& s2, auto&& s3) -> void
15+
CPP2_REQUIRES (std::is_same_v<CPP2_TYPEOF(s1), std::string> && std::is_same_v<CPP2_TYPEOF(s2), std::string> && std::is_same_v<CPP2_TYPEOF(s3), std::string>)
16+
#line 1 "pure2-function-multiple-forward-arguments.cpp2"
17+
;
1518

1619

1720
#line 5 "pure2-function-multiple-forward-arguments.cpp2"

regression-tests/test-results/pure2-requires-clauses.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ class X {
3131
};
3232

3333
template<typename T, typename U> [[nodiscard]] auto f
34-
(auto&& a, auto&& b) -> int;
34+
(auto&& a, auto&& b) -> int
35+
CPP2_REQUIRES (std::is_same_v<T,int> && std::is_same_v<U,int> && std::is_same_v<CPP2_TYPEOF(a), int> && std::is_same_v<CPP2_TYPEOF(b), int>)
36+
#line 10 "pure2-requires-clauses.cpp2"
37+
;
38+
3539

3640
#line 18 "pure2-requires-clauses.cpp2"
3741
auto main() -> int;

source/cppfront.cpp

Lines changed: 38 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5545,11 +5545,47 @@ class cppfront
55455545
}
55465546
}
55475547

5548-
// *** LOCATION (A) -- SEE NOTE REGARDING (A) BELOW
5548+
auto const emit_requires_clause = [&]() {
5549+
if (
5550+
n.requires_clause_expression
5551+
|| !function_requires_conditions.empty()
5552+
)
5553+
{
5554+
printer.print_extra("\n");
5555+
printer.ignore_alignment( true, n.position().colno + 4 );
5556+
if (printer.get_phase() == printer.phase1_type_defs_func_decls) {
5557+
// Workaround GCC 10 not supporting requires in forward declarations in some cases.
5558+
// See commit 5a0d77f8e297902c0b9712c5aafb6208cfa4c139.
5559+
printer.print_extra("CPP2_REQUIRES (");
5560+
}
5561+
else {
5562+
printer.print_extra("requires (");
5563+
}
5564+
5565+
if (n.requires_clause_expression) {
5566+
emit(*n.requires_clause_expression);
5567+
if (!function_requires_conditions.empty()) {
5568+
printer.print_extra(" && ");
5569+
}
5570+
}
5571+
5572+
if (!function_requires_conditions.empty()) {
5573+
printer.print_extra(function_requires_conditions.front());
5574+
for (auto it = std::cbegin(function_requires_conditions)+1; it != std::cend(function_requires_conditions); ++it) {
5575+
printer.print_extra(" && " + *it);
5576+
}
5577+
}
5578+
5579+
printer.print_extra(")");
5580+
function_requires_conditions = {};
5581+
printer.ignore_alignment( false );
5582+
}
5583+
};
55495584

55505585
// If we're only emitting declarations, end the function declaration
55515586
if (printer.get_phase() == printer.phase1_type_defs_func_decls)
55525587
{
5588+
emit_requires_clause();
55535589
printer.print_cpp2( ";\n", n.position() );
55545590
// Note: Not just early "return;" here because we may need to
55555591
// recurse to emit the generated operator= declarations too,
@@ -5639,54 +5675,7 @@ class cppfront
56395675

56405676
printer.preempt_position_push( n.equal_sign );
56415677

5642-
// *** NOTE =====================================================
5643-
//
5644-
// This branch to emit the requires-clause should maybe be
5645-
// moved to location (A) above, so that it's also emitted
5646-
// on the function declaration. But moving it to (A) triggers
5647-
// a bug in GCC 10.x (that was fixed in 11.x), where it would
5648-
// break using a 'forward' parameter of a concrete type and
5649-
// also explicitly user-written requires-clauses that do
5650-
// similar decltype tests.
5651-
//
5652-
// I don't want to neednessly break compatibility with a
5653-
// decently conforming C++20 compiler that works well for
5654-
// everything else that Cpp2 needs from C++20. If the
5655-
// 'requires' down here doesn't cause a problem, I'll keep
5656-
// it here for now... if we do encounter a reason it needs to
5657-
// also be on the declaration, move this code to (A).
5658-
//
5659-
// Handle requires clause - an explicit one the user wrote,
5660-
// and/or any conditions we generated while processing the
5661-
// parameters (i.e., forwarding a concrete type)
5662-
if (
5663-
n.requires_clause_expression
5664-
|| !function_requires_conditions.empty()
5665-
)
5666-
{
5667-
printer.print_extra("\n");
5668-
printer.ignore_alignment( true, n.position().colno + 4 );
5669-
printer.print_extra("requires (");
5670-
5671-
if (n.requires_clause_expression) {
5672-
emit(*n.requires_clause_expression);
5673-
if (!function_requires_conditions.empty()) {
5674-
printer.print_extra(" && ");
5675-
}
5676-
}
5677-
5678-
if (!function_requires_conditions.empty()) {
5679-
printer.print_extra(function_requires_conditions.front());
5680-
for (auto it = std::cbegin(function_requires_conditions)+1; it != std::cend(function_requires_conditions); ++it) {
5681-
printer.print_extra(" && " + *it);
5682-
}
5683-
}
5684-
5685-
printer.print_extra(")");
5686-
function_requires_conditions = {};
5687-
printer.ignore_alignment( false );
5688-
}
5689-
// *** END NOTE =================================================
5678+
emit_requires_clause();
56905679

56915680
emit(
56925681
*n.initializer,

0 commit comments

Comments
 (0)