From 86064d24e50e1c3e27bf2854c2a88ec96763c20f Mon Sep 17 00:00:00 2001 From: Max Sagebaum Date: Tue, 16 Jan 2024 22:57:29 +0100 Subject: [PATCH] Bugfix for missing semaphore in typed template parameters. (#918) * Bugfix for missing semaphore in typed template parameters. * Output of unnamed type param name for typed template arguments. * Name clash for unamed template arguments. * Missing name generation of unamed template types in tempalte parameter list. * Update of test results. * Update for failing tests. --------- Signed-off-by: Herb Sutter Co-authored-by: Herb Sutter --- regression-tests/pure2-variadics.cpp2 | 23 +++++++ .../pure2-variadics.cpp.execution | 3 +- .../gcc-10/pure2-variadics.cpp.execution | 3 +- .../gcc-13/pure2-variadics.cpp.execution | 3 +- .../mixed-bugfix-for-ufcs-non-local.cpp | 10 +-- .../pure2-bugfix-for-ufcs-arguments.cpp | 32 ++++------ .../test-results/pure2-variadics.cpp | 61 ++++++++++++++++++- source/lex.h | 9 +++ source/to_cpp1.h | 25 ++++++-- 9 files changed, 133 insertions(+), 36 deletions(-) diff --git a/regression-tests/pure2-variadics.cpp2 b/regression-tests/pure2-variadics.cpp2 index eed386f521..2ea49bb2ff 100644 --- a/regression-tests/pure2-variadics.cpp2 +++ b/regression-tests/pure2-variadics.cpp2 @@ -6,6 +6,27 @@ x: type = { func: () = {} } +// int pack expansion +y: type = { + + func: () ( 0 + ... + Ts); +} + +// Discard type name pack expansion +t0: @struct <_...> type = { + f: <_: int> () -> i32 = 0; +} + +// Discard template type pack expansion +t1: @struct type = { + f: <_: int> () -> i32 = 0; +} + +// Discard typename and template type pack expansion +t2: @struct <_...: _> type = { + f: <_: int> () -> i32 = 0; +} + left_fold_print: (inout out: std::ostream, args...: Args) = { // Binary left fold expression (out << ... << args); @@ -31,4 +52,6 @@ main: () std::cout << "\nfirst all() returned (all(true, true, true, false))$"; std::cout << "\nsecond all() returned " << all(true, true, true, true) as std::string; + + std::cout << "\nsum of (1, 2, 3, 100) is: " << y<1,2,3,100>().func() as std::string; } diff --git a/regression-tests/test-results/apple-clang-14/pure2-variadics.cpp.execution b/regression-tests/test-results/apple-clang-14/pure2-variadics.cpp.execution index 680b09a6da..f4791e7aef 100644 --- a/regression-tests/test-results/apple-clang-14/pure2-variadics.cpp.execution +++ b/regression-tests/test-results/apple-clang-14/pure2-variadics.cpp.execution @@ -3,4 +3,5 @@ plu abr 3.14word-1500 first all() returned false -second all() returned true \ No newline at end of file +second all() returned true +sum of (1, 2, 3, 100) is: 106 diff --git a/regression-tests/test-results/gcc-10/pure2-variadics.cpp.execution b/regression-tests/test-results/gcc-10/pure2-variadics.cpp.execution index 680b09a6da..f4791e7aef 100644 --- a/regression-tests/test-results/gcc-10/pure2-variadics.cpp.execution +++ b/regression-tests/test-results/gcc-10/pure2-variadics.cpp.execution @@ -3,4 +3,5 @@ plu abr 3.14word-1500 first all() returned false -second all() returned true \ No newline at end of file +second all() returned true +sum of (1, 2, 3, 100) is: 106 diff --git a/regression-tests/test-results/gcc-13/pure2-variadics.cpp.execution b/regression-tests/test-results/gcc-13/pure2-variadics.cpp.execution index 680b09a6da..53bc692f96 100644 --- a/regression-tests/test-results/gcc-13/pure2-variadics.cpp.execution +++ b/regression-tests/test-results/gcc-13/pure2-variadics.cpp.execution @@ -3,4 +3,5 @@ plu abr 3.14word-1500 first all() returned false -second all() returned true \ No newline at end of file +second all() returned true +sum of (1, 2, 3, 100) is: 106 \ No newline at end of file diff --git a/regression-tests/test-results/mixed-bugfix-for-ufcs-non-local.cpp b/regression-tests/test-results/mixed-bugfix-for-ufcs-non-local.cpp index a76eb04aa2..5a0bc4d682 100644 --- a/regression-tests/test-results/mixed-bugfix-for-ufcs-non-local.cpp +++ b/regression-tests/test-results/mixed-bugfix-for-ufcs-non-local.cpp @@ -34,7 +34,7 @@ namespace ns { // Variables. -template _> bool inline constexpr v0 = false;// Fails on GCC ([GCC109781][]) and Clang 12 (a lambda expression cannot appear in this context) +template UnnamedTypeParam1_13_6> bool inline constexpr v0 = false;// Fails on GCC ([GCC109781][]) and Clang 12 (a lambda expression cannot appear in this context) t inline constexpr v1 = t();// Fails on Clang 12 (lambda in unevaluated context). @@ -42,7 +42,7 @@ bool inline constexpr v2 = CPP2_UFCS_NONLOCAL(f)(o); // Functions. -template _> auto g() -> void; +template UnnamedTypeParam1_21_5> auto g() -> void; auto g([[maybe_unused]] cpp2::in> unnamed_param_1) -> void; @@ -52,9 +52,9 @@ auto g() -> void; // Aliases. -template _> using a = bool;// Fails on GCC ([GCC109781][]) and Clang 12 (a lambda expression cannot appear in this context) +template UnnamedTypeParam1_31_5> using a = bool;// Fails on GCC ([GCC109781][]) and Clang 12 (a lambda expression cannot appear in this context) -template _> auto inline constexpr b = false;// Fails on GCC ([GCC109781][]). +template UnnamedTypeParam1_33_5> auto inline constexpr b = false;// Fails on GCC ([GCC109781][]). using c = t;// Fails on Clang 12 (lambda in unevaluated context) and Clang 12 (a lambda expression cannot appear in this context) @@ -81,7 +81,7 @@ auto main() -> int; namespace ns { #line 21 "mixed-bugfix-for-ufcs-non-local.cpp2" -template _> auto g() -> void{}// Fails on GCC ([GCC109781][]) and Clang 12 (a lambda expression cannot appear in this context) +template UnnamedTypeParam1_21_5> auto g() -> void{}// Fails on GCC ([GCC109781][]) and Clang 12 (a lambda expression cannot appear in this context) #line 23 "mixed-bugfix-for-ufcs-non-local.cpp2" auto g([[maybe_unused]] cpp2::in> unnamed_param_1) -> void{}// Fails on Clang 12 (lambda in unevaluated context). diff --git a/regression-tests/test-results/pure2-bugfix-for-ufcs-arguments.cpp b/regression-tests/test-results/pure2-bugfix-for-ufcs-arguments.cpp index c74636bac9..8663b7d2b1 100644 --- a/regression-tests/test-results/pure2-bugfix-for-ufcs-arguments.cpp +++ b/regression-tests/test-results/pure2-bugfix-for-ufcs-arguments.cpp @@ -35,20 +35,20 @@ class B; class t { public: [[nodiscard]] auto f() & -> cpp2::i32; public: [[nodiscard]] auto f([[maybe_unused]] auto const& unnamed_param_2) & -> cpp2::i32; - public: template [[nodiscard]] auto f() & -> cpp2::i32; - public: template [[nodiscard]] auto f([[maybe_unused]] auto const& unnamed_param_2) & -> cpp2::i32; - public: template [[nodiscard]] auto f([[maybe_unused]] auto const& unnamed_param_2, [[maybe_unused]] auto const& unnamed_param_3) & -> cpp2::i32; + public: template [[nodiscard]] auto f() & -> cpp2::i32; + public: template [[nodiscard]] auto f([[maybe_unused]] auto const& unnamed_param_2) & -> cpp2::i32; + public: template [[nodiscard]] auto f([[maybe_unused]] auto const& unnamed_param_2, [[maybe_unused]] auto const& unnamed_param_3) & -> cpp2::i32; }; [[nodiscard]] auto f([[maybe_unused]] cpp2::in unnamed_param_1) -> cpp2::i32; [[nodiscard]] auto f([[maybe_unused]] cpp2::in unnamed_param_1, [[maybe_unused]] auto const& unnamed_param_2) -> cpp2::i32; -template [[nodiscard]] auto f([[maybe_unused]] cpp2::in unnamed_param_1) -> cpp2::i32; -template [[nodiscard]] auto f([[maybe_unused]] cpp2::in unnamed_param_1, [[maybe_unused]] auto const& unnamed_param_2) -> cpp2::i32; -template [[nodiscard]] auto f([[maybe_unused]] cpp2::in unnamed_param_1, [[maybe_unused]] auto const& unnamed_param_2, [[maybe_unused]] auto const& unnamed_param_3) -> cpp2::i32; +template [[nodiscard]] auto f([[maybe_unused]] cpp2::in unnamed_param_1) -> cpp2::i32; +template [[nodiscard]] auto f([[maybe_unused]] cpp2::in unnamed_param_1, [[maybe_unused]] auto const& unnamed_param_2) -> cpp2::i32; +template [[nodiscard]] auto f([[maybe_unused]] cpp2::in unnamed_param_1, [[maybe_unused]] auto const& unnamed_param_2, [[maybe_unused]] auto const& unnamed_param_3) -> cpp2::i32; extern t m; extern t const n; -template auto inline constexpr a = n; +template auto inline constexpr a = n; extern cpp2::i32 auto_1; extern cpp2::i32 auto_2; @@ -98,23 +98,17 @@ class B { [[nodiscard]] auto t::f() & -> cpp2::i32 { return print_res(0); } #line 9 "pure2-bugfix-for-ufcs-arguments.cpp2" [[nodiscard]] auto t::f([[maybe_unused]] auto const& unnamed_param_2) & -> cpp2::i32 { return print_res(1); } -#line 10 "pure2-bugfix-for-ufcs-arguments.cpp2" - template [[nodiscard]] auto t::f() & -> cpp2::i32 { return print_res(2); } -#line 11 "pure2-bugfix-for-ufcs-arguments.cpp2" - template [[nodiscard]] auto t::f([[maybe_unused]] auto const& unnamed_param_2) & -> cpp2::i32 { return print_res(3); } -#line 12 "pure2-bugfix-for-ufcs-arguments.cpp2" - template [[nodiscard]] auto t::f([[maybe_unused]] auto const& unnamed_param_2, [[maybe_unused]] auto const& unnamed_param_3) & -> cpp2::i32 { return print_res(4); } + template [[nodiscard]] auto t::f() & -> cpp2::i32 { return print_res(2); } + template [[nodiscard]] auto t::f([[maybe_unused]] auto const& unnamed_param_2) & -> cpp2::i32 { return print_res(3); } + template [[nodiscard]] auto t::f([[maybe_unused]] auto const& unnamed_param_2, [[maybe_unused]] auto const& unnamed_param_3) & -> cpp2::i32 { return print_res(4); } #line 15 "pure2-bugfix-for-ufcs-arguments.cpp2" [[nodiscard]] auto f([[maybe_unused]] cpp2::in unnamed_param_1) -> cpp2::i32 { return print_res(5); } #line 16 "pure2-bugfix-for-ufcs-arguments.cpp2" [[nodiscard]] auto f([[maybe_unused]] cpp2::in unnamed_param_1, [[maybe_unused]] auto const& unnamed_param_2) -> cpp2::i32 { return print_res(6); } -#line 17 "pure2-bugfix-for-ufcs-arguments.cpp2" -template [[nodiscard]] auto f([[maybe_unused]] cpp2::in unnamed_param_1) -> cpp2::i32 { return print_res(7); } -#line 18 "pure2-bugfix-for-ufcs-arguments.cpp2" -template [[nodiscard]] auto f([[maybe_unused]] cpp2::in unnamed_param_1, [[maybe_unused]] auto const& unnamed_param_2) -> cpp2::i32 { return print_res(8); } -#line 19 "pure2-bugfix-for-ufcs-arguments.cpp2" -template [[nodiscard]] auto f([[maybe_unused]] cpp2::in unnamed_param_1, [[maybe_unused]] auto const& unnamed_param_2, [[maybe_unused]] auto const& unnamed_param_3) -> cpp2::i32 { return print_res(9); } +template [[nodiscard]] auto f([[maybe_unused]] cpp2::in unnamed_param_1) -> cpp2::i32 { return print_res(7); } +template [[nodiscard]] auto f([[maybe_unused]] cpp2::in unnamed_param_1, [[maybe_unused]] auto const& unnamed_param_2) -> cpp2::i32 { return print_res(8); } +template [[nodiscard]] auto f([[maybe_unused]] cpp2::in unnamed_param_1, [[maybe_unused]] auto const& unnamed_param_2, [[maybe_unused]] auto const& unnamed_param_3) -> cpp2::i32 { return print_res(9); } t m {}; t const n {}; diff --git a/regression-tests/test-results/pure2-variadics.cpp b/regression-tests/test-results/pure2-variadics.cpp index e7902da9d7..56b10a3b63 100644 --- a/regression-tests/test-results/pure2-variadics.cpp +++ b/regression-tests/test-results/pure2-variadics.cpp @@ -12,6 +12,21 @@ template class x; +#line 10 "pure2-variadics.cpp2" +template class y; + +#line 16 "pure2-variadics.cpp2" +template class t0; + + +#line 21 "pure2-variadics.cpp2" +template class t1; + + +#line 26 "pure2-variadics.cpp2" +template class t2; + + //=== Cpp2 type definitions and function declarations =========================== #line 1 "pure2-variadics.cpp2" @@ -29,12 +44,38 @@ template class x { #line 7 "pure2-variadics.cpp2" }; +// int pack expansion +template class y { + + public: [[nodiscard]] static auto func() -> auto; + public: y() = default; + public: y(y const&) = delete; /* No 'that' constructor, suppress copy */ + public: auto operator=(y const&) -> void = delete; + +#line 13 "pure2-variadics.cpp2" +}; + +// Discard type name pack expansion +template class t0 { + public: template [[nodiscard]] static auto f() -> cpp2::i32; +}; + +// Discard template type pack expansion +template class t1 { + public: template [[nodiscard]] static auto f() -> cpp2::i32; +}; + +// Discard typename and template type pack expansion +template class t2 { + public: template [[nodiscard]] static auto f() -> cpp2::i32; +}; + template auto left_fold_print(std::ostream& out, Args const& ...args) -> void; -#line 14 "pure2-variadics.cpp2" +#line 35 "pure2-variadics.cpp2" template [[nodiscard]] auto all(Args const& ...args) -> bool; -#line 18 "pure2-variadics.cpp2" +#line 39 "pure2-variadics.cpp2" template [[nodiscard]] auto make_string(Args&& ...args) -> auto; template [[nodiscard]] auto make(Args&& ...args) -> auto; @@ -48,7 +89,19 @@ auto main() -> int; #line 6 "pure2-variadics.cpp2" template auto x::func() -> void{} -#line 9 "pure2-variadics.cpp2" +#line 12 "pure2-variadics.cpp2" + template [[nodiscard]] auto y::func() -> auto { return (0 + ... + Ts); } + +#line 17 "pure2-variadics.cpp2" + template template [[nodiscard]] auto t0::f() -> cpp2::i32 { return 0; } + +#line 22 "pure2-variadics.cpp2" + template template [[nodiscard]] auto t1::f() -> cpp2::i32 { return 0; } + +#line 27 "pure2-variadics.cpp2" + template template [[nodiscard]] auto t2::f() -> cpp2::i32 { return 0; } + +#line 30 "pure2-variadics.cpp2" template auto left_fold_print(std::ostream& out, Args const& ...args) -> void{ // Binary left fold expression (out << ... << args); @@ -78,5 +131,7 @@ auto main() -> int std::cout << ("\nfirst all() returned " + cpp2::to_string(all(true, true, true, false))); std::cout << "\nsecond all() returned " << cpp2::as_(all(true, true, true, true)); + + std::cout << "\nsum of (1, 2, 3, 100) is: " << cpp2::as_(CPP2_UFCS(func)(y<1,2,3,100>())); } diff --git a/source/lex.h b/source/lex.h index 034cc2d8e3..b6ca22c5e0 100644 --- a/source/lex.h +++ b/source/lex.h @@ -336,6 +336,15 @@ auto labelized_position(token const* t) return labels[t].text; } +auto unnamed_type_param_name(int ordinal, token const* t) + -> std::string +{ + return "UnnamedTypeParam" + + std::to_string(ordinal) + + "_" + + labelized_position(t); +} + //----------------------------------------------------------------------- // diff --git a/source/to_cpp1.h b/source/to_cpp1.h index 9747eb10b3..28c3983a99 100644 --- a/source/to_cpp1.h +++ b/source/to_cpp1.h @@ -4277,9 +4277,8 @@ class cppfront //----------------------------------------------------------------------- // Handle type parameters - if (n.declaration->is_type()) { - assert( is_template_parameter ); - printer.print_cpp2("typename ", identifier_pos); + // Common template naming + auto emit_template_name = [&]() { if (n.declaration->is_variadic) { printer.print_cpp2( "...", @@ -4288,12 +4287,18 @@ class cppfront } if (identifier == "_") { - printer.print_cpp2( "UnnamedTypeParam" + std::to_string(n.ordinal), identifier_pos ); + printer.print_cpp2( unnamed_type_param_name(n.ordinal, n.declaration->identifier->get_token()), + identifier_pos ); } else { printer.print_cpp2( identifier, identifier_pos ); } + }; + if (n.declaration->is_type()) { + assert( is_template_parameter ); + printer.print_cpp2("typename ", identifier_pos); + emit_template_name(); return; } @@ -4306,7 +4311,8 @@ class cppfront if (is_template_parameter) { emit( type_id ); printer.print_cpp2(" ", type_id.position()); - printer.print_cpp2( identifier, identifier_pos ); + + emit_template_name(); return; } @@ -4945,7 +4951,14 @@ class cppfront auto separator = std::string{"<"}; for (auto& tparam : parent->template_parameters->parameters) { assert (tparam->has_name()); - list += separator + tparam->name()->to_string(); + list += separator; + if ("_" == tparam->name()->to_string()) { + list += unnamed_type_param_name(tparam->ordinal, + tparam->declaration->identifier->get_token()); + } + else { + list += tparam->name()->to_string(); + } if(tparam->declaration->is_variadic) { list += "..."; }