From 76c2941b29e1e17f8086d3581df03d0bb12bc793 Mon Sep 17 00:00:00 2001 From: Herb Sutter Date: Fri, 10 Nov 2023 13:55:45 -1000 Subject: [PATCH] Support `_` unnamed type parameters - closes #812 Also require an `operator=` second parameter of the same type to be named `that` - see #475 discussion thread --- .../mixed-bounds-safety-with-assert-2.cpp | 2 +- .../test-results/mixed-forwarding.cpp | 8 ++-- .../mixed-parameter-passing-with-forward.cpp | 12 +++--- .../test-results/mixed-parameter-passing.cpp | 12 +++--- ...d-postfix-expression-custom-formatting.cpp | 4 +- ...-bugfix-for-memberwise-base-assignment.cpp | 8 ++-- regression-tests/test-results/pure2-print.cpp | 10 ++--- .../test-results/pure2-types-down-upcast.cpp | 8 ++-- .../test-results/pure2-types-inheritance.cpp | 4 +- .../pure2-ufcs-member-access-and-chaining.cpp | 8 ++-- regression-tests/test-results/version | 2 +- source/build.info | 2 +- source/sema.h | 28 ++++++++++++ source/to_cpp1.h | 43 ++++++++++++------- 14 files changed, 95 insertions(+), 56 deletions(-) diff --git a/regression-tests/test-results/mixed-bounds-safety-with-assert-2.cpp b/regression-tests/test-results/mixed-bounds-safety-with-assert-2.cpp index 2535f01a6d..c44d3a7612 100644 --- a/regression-tests/test-results/mixed-bounds-safety-with-assert-2.cpp +++ b/regression-tests/test-results/mixed-bounds-safety-with-assert-2.cpp @@ -43,7 +43,7 @@ auto add_42_to_subrange(auto& rng, cpp2::in start, cpp2::in end) -> vo auto count {0}; for ( - auto& i : rng ) { do + auto& i : rng ) { do if ([_0 = start, _1 = count, _2 = end]{ return cpp2::cmp_less_eq(_0,_1) && cpp2::cmp_less_eq(_1,_2); }()) { i += 42; } while (false); ++count; } diff --git a/regression-tests/test-results/mixed-forwarding.cpp b/regression-tests/test-results/mixed-forwarding.cpp index 5777940a22..7fa66ced31 100644 --- a/regression-tests/test-results/mixed-forwarding.cpp +++ b/regression-tests/test-results/mixed-forwarding.cpp @@ -20,9 +20,9 @@ struct X { }; #line 11 "mixed-forwarding.cpp2" -auto copy_from([[maybe_unused]] auto param1) -> void; +auto copy_from([[maybe_unused]] auto unnamed_param_1) -> void; -auto use([[maybe_unused]] auto const& param1) -> void; +auto use([[maybe_unused]] auto const& unnamed_param_1) -> void; // invoking each of these with an rvalue std::pair argument ... auto apply_implicit_forward(auto&& t) -> void @@ -46,9 +46,9 @@ CPP2_REQUIRES (std::is_same_v>) #line 11 "mixed-forwarding.cpp2" -auto copy_from([[maybe_unused]] auto param1) -> void{} +auto copy_from([[maybe_unused]] auto unnamed_param_1) -> void{} -auto use([[maybe_unused]] auto const& param1) -> void{} +auto use([[maybe_unused]] auto const& unnamed_param_1) -> void{} #line 16 "mixed-forwarding.cpp2" auto apply_implicit_forward(auto&& t) -> void diff --git a/regression-tests/test-results/mixed-parameter-passing-with-forward.cpp b/regression-tests/test-results/mixed-parameter-passing-with-forward.cpp index 558eada56a..e532d7cd20 100644 --- a/regression-tests/test-results/mixed-parameter-passing-with-forward.cpp +++ b/regression-tests/test-results/mixed-parameter-passing-with-forward.cpp @@ -15,12 +15,12 @@ #include #line 6 "mixed-parameter-passing-with-forward.cpp2" -auto copy_from([[maybe_unused]] auto param1) -> void; +auto copy_from([[maybe_unused]] auto unnamed_param_1) -> void; auto parameter_styles( - [[maybe_unused]] cpp2::in param1, // "in" is default + [[maybe_unused]] cpp2::in unnamed_param_1, // "in" is default std::string b, - [[maybe_unused]] std::string& param3, + [[maybe_unused]] std::string& unnamed_param_3, std::string&& d, auto&& e ) -> void @@ -36,12 +36,12 @@ CPP2_REQUIRES (std::is_same_v) #line 6 "mixed-parameter-passing-with-forward.cpp2" -auto copy_from([[maybe_unused]] auto param1) -> void{} +auto copy_from([[maybe_unused]] auto unnamed_param_1) -> void{} auto parameter_styles( - [[maybe_unused]] cpp2::in param1, + [[maybe_unused]] cpp2::in unnamed_param_1, std::string b, - [[maybe_unused]] std::string& param3, + [[maybe_unused]] std::string& unnamed_param_3, std::string&& d, auto&& e ) -> void diff --git a/regression-tests/test-results/mixed-parameter-passing.cpp b/regression-tests/test-results/mixed-parameter-passing.cpp index 16fd614495..081dd8063a 100644 --- a/regression-tests/test-results/mixed-parameter-passing.cpp +++ b/regression-tests/test-results/mixed-parameter-passing.cpp @@ -15,12 +15,12 @@ #include #line 6 "mixed-parameter-passing.cpp2" -auto copy_from([[maybe_unused]] auto param1) -> void; +auto copy_from([[maybe_unused]] auto unnamed_param_1) -> void; auto parameter_styles( - [[maybe_unused]] cpp2::in param1, // "in" is default + [[maybe_unused]] cpp2::in unnamed_param_1, // "in" is default std::string b, - [[maybe_unused]] std::string& param3, + [[maybe_unused]] std::string& unnamed_param_3, std::string&& d ) -> void; @@ -32,12 +32,12 @@ auto parameter_styles( #line 6 "mixed-parameter-passing.cpp2" -auto copy_from([[maybe_unused]] auto param1) -> void{} +auto copy_from([[maybe_unused]] auto unnamed_param_1) -> void{} auto parameter_styles( - [[maybe_unused]] cpp2::in param1, + [[maybe_unused]] cpp2::in unnamed_param_1, std::string b, - [[maybe_unused]] std::string& param3, + [[maybe_unused]] std::string& unnamed_param_3, std::string&& d ) -> void { diff --git a/regression-tests/test-results/mixed-postfix-expression-custom-formatting.cpp b/regression-tests/test-results/mixed-postfix-expression-custom-formatting.cpp index 81738a3b5f..08e7df8c2e 100644 --- a/regression-tests/test-results/mixed-postfix-expression-custom-formatting.cpp +++ b/regression-tests/test-results/mixed-postfix-expression-custom-formatting.cpp @@ -11,7 +11,7 @@ #line 2 "mixed-postfix-expression-custom-formatting.cpp2" -auto call([[maybe_unused]] auto const& param1, [[maybe_unused]] auto const& param2, [[maybe_unused]] auto const& param3, [[maybe_unused]] auto const& param4, [[maybe_unused]] auto const& param5) -> void; +auto call([[maybe_unused]] auto const& unnamed_param_1, [[maybe_unused]] auto const& unnamed_param_2, [[maybe_unused]] auto const& unnamed_param_3, [[maybe_unused]] auto const& unnamed_param_4, [[maybe_unused]] auto const& unnamed_param_5) -> void; [[nodiscard]] auto test(auto const& a) -> std::string; @@ -24,7 +24,7 @@ auto call([[maybe_unused]] auto const& param1, [[maybe_unused]] auto const& para #line 2 "mixed-postfix-expression-custom-formatting.cpp2" -auto call([[maybe_unused]] auto const& param1, [[maybe_unused]] auto const& param2, [[maybe_unused]] auto const& param3, [[maybe_unused]] auto const& param4, [[maybe_unused]] auto const& param5) -> void{} +auto call([[maybe_unused]] auto const& unnamed_param_1, [[maybe_unused]] auto const& unnamed_param_2, [[maybe_unused]] auto const& unnamed_param_3, [[maybe_unused]] auto const& unnamed_param_4, [[maybe_unused]] auto const& unnamed_param_5) -> void{} [[nodiscard]] auto test(auto const& a) -> std::string{ return call(a, diff --git a/regression-tests/test-results/pure2-bugfix-for-memberwise-base-assignment.cpp b/regression-tests/test-results/pure2-bugfix-for-memberwise-base-assignment.cpp index ea628be889..4b909c66db 100644 --- a/regression-tests/test-results/pure2-bugfix-for-memberwise-base-assignment.cpp +++ b/regression-tests/test-results/pure2-bugfix-for-memberwise-base-assignment.cpp @@ -27,9 +27,9 @@ class Base { #line 3 "pure2-bugfix-for-memberwise-base-assignment.cpp2" public: auto operator=([[maybe_unused]] Base&& that) noexcept -> Base& ; - public: Base([[maybe_unused]] auto const& param2); + public: Base([[maybe_unused]] auto const& unnamed_param_2); #line 4 "pure2-bugfix-for-memberwise-base-assignment.cpp2" - public: auto operator=([[maybe_unused]] auto const& param2) -> Base& ; + public: auto operator=([[maybe_unused]] auto const& unnamed_param_2) -> Base& ; }; class Derived: public Base { @@ -60,9 +60,9 @@ auto main() -> int; return *this; #line 3 "pure2-bugfix-for-memberwise-base-assignment.cpp2" } - Base::Base([[maybe_unused]] auto const& param2) { std::cout << "(implicit out this, _)\n"; } + Base::Base([[maybe_unused]] auto const& unnamed_param_2) { std::cout << "(implicit out this, _)\n"; } #line 4 "pure2-bugfix-for-memberwise-base-assignment.cpp2" - auto Base::operator=([[maybe_unused]] auto const& param2) -> Base& { std::cout << "(implicit out this, _)\n"; + auto Base::operator=([[maybe_unused]] auto const& unnamed_param_2) -> Base& { std::cout << "(implicit out this, _)\n"; return *this; #line 4 "pure2-bugfix-for-memberwise-base-assignment.cpp2" } diff --git a/regression-tests/test-results/pure2-print.cpp b/regression-tests/test-results/pure2-print.cpp index 33cfe32365..2896fb8eeb 100644 --- a/regression-tests/test-results/pure2-print.cpp +++ b/regression-tests/test-results/pure2-print.cpp @@ -38,7 +38,7 @@ CPP2_REQUIRES_ (true) #line 54 "pure2-print.cpp2" - public: template [[nodiscard]] auto values([[maybe_unused]] T const& param2) const& -> values_ret; + public: template [[nodiscard]] auto values([[maybe_unused]] T const& unnamed_param_2) const& -> values_ret; #line 59 "pure2-print.cpp2" @@ -46,7 +46,7 @@ CPP2_REQUIRES_ (true) public: mytype([[maybe_unused]] mytype const& that); - public: mytype([[maybe_unused]] cpp2::in param2); + public: mytype([[maybe_unused]] cpp2::in unnamed_param_2); public: static auto variadic(auto const& ...x) -> void CPP2_REQUIRES_ ((std::is_convertible_v && ...)) @@ -133,7 +133,7 @@ requires (true) do {} while ( CPP2_UFCS_0(empty, s) && [&]{ b() ; return true; }() ); - for ( [[maybe_unused]] auto const& param1 : m ) { + for ( [[maybe_unused]] auto const& unnamed_param_1 : m ) { #line 43 "pure2-print.cpp2" { do {goto CONTINUE_43_13; } while (false); c(); } CPP2_CONTINUE_BREAK(43_13) } @@ -147,7 +147,7 @@ requires (true) return [_0 = (s + cpp2::assert_in_bounds(m, 0))]() -> std::string { return _0; }(); } - template [[nodiscard]] auto outer::mytype::values([[maybe_unused]] T const& param2) const& -> values_ret{ + template [[nodiscard]] auto outer::mytype::values([[maybe_unused]] T const& unnamed_param_2) const& -> values_ret{ cpp2::deferred_init offset; cpp2::deferred_init name; #line 55 "pure2-print.cpp2" @@ -159,7 +159,7 @@ requires (true) outer::mytype::mytype([[maybe_unused]] mytype const& that){} - outer::mytype::mytype([[maybe_unused]] cpp2::in param2){} + outer::mytype::mytype([[maybe_unused]] cpp2::in unnamed_param_2){} auto outer::mytype::variadic(auto const& ...x) -> void requires ((std::is_convertible_v && ...)) diff --git a/regression-tests/test-results/pure2-types-down-upcast.cpp b/regression-tests/test-results/pure2-types-down-upcast.cpp index 88f2e294b0..6540c10ecc 100644 --- a/regression-tests/test-results/pure2-types-down-upcast.cpp +++ b/regression-tests/test-results/pure2-types-down-upcast.cpp @@ -37,8 +37,8 @@ class B: public A { #line 11 "pure2-types-down-upcast.cpp2" }; -auto func_mut(A& a) -> void; -auto func_mut(B& b) -> void; +auto func_mut(A& a) -> void; +auto func_mut(B& b) -> void; auto func_const(cpp2::in a) -> void; auto func_const(cpp2::in b) -> void; @@ -69,8 +69,8 @@ auto test_down() -> void; auto A::mut_foo() & -> void{std::cout << "foo \n"; } #line 13 "pure2-types-down-upcast.cpp2" -auto func_mut(A& a) -> void {std::cout << "Call A mut: " + cpp2::to_string(a.i) << std::endl;} -auto func_mut(B& b) -> void {std::cout << "Call B mut: " + cpp2::to_string(b.d) << std::endl;} +auto func_mut(A& a) -> void {std::cout << "Call A mut: " + cpp2::to_string(a.i) << std::endl;} +auto func_mut(B& b) -> void {std::cout << "Call B mut: " + cpp2::to_string(b.d) << std::endl;} auto func_const(cpp2::in a) -> void{std::cout << "Call A const: " + cpp2::to_string(a.i) << std::endl;} auto func_const(cpp2::in b) -> void{std::cout << "Call B const: " + cpp2::to_string(b.d) << std::endl;} diff --git a/regression-tests/test-results/pure2-types-inheritance.cpp b/regression-tests/test-results/pure2-types-inheritance.cpp index a49493bea6..625453a113 100644 --- a/regression-tests/test-results/pure2-types-inheritance.cpp +++ b/regression-tests/test-results/pure2-types-inheritance.cpp @@ -39,7 +39,7 @@ public: virtual ~Human() noexcept; namespace N { template class Machine { - public: explicit Machine([[maybe_unused]] cpp2::in param2); + public: explicit Machine([[maybe_unused]] cpp2::in unnamed_param_2); public: virtual auto work() const -> void = 0; public: virtual ~Machine() noexcept; @@ -97,7 +97,7 @@ auto main() -> int; #line 6 "pure2-types-inheritance.cpp2" namespace N { - template Machine::Machine([[maybe_unused]] cpp2::in param2){} + template Machine::Machine([[maybe_unused]] cpp2::in unnamed_param_2){} template Machine::~Machine() noexcept{} diff --git a/regression-tests/test-results/pure2-ufcs-member-access-and-chaining.cpp b/regression-tests/test-results/pure2-ufcs-member-access-and-chaining.cpp index 182fcb455e..042170d30e 100644 --- a/regression-tests/test-results/pure2-ufcs-member-access-and-chaining.cpp +++ b/regression-tests/test-results/pure2-ufcs-member-access-and-chaining.cpp @@ -14,7 +14,7 @@ #line 24 "pure2-ufcs-member-access-and-chaining.cpp2" -auto no_return([[maybe_unused]] auto const& param1) -> void; +auto no_return([[maybe_unused]] auto const& unnamed_param_1) -> void; [[nodiscard]] auto ufcs(cpp2::in i) -> int; struct fun_ret { int i; }; @@ -31,7 +31,7 @@ auto no_return([[maybe_unused]] auto const& param1) -> void; #line 39 "pure2-ufcs-member-access-and-chaining.cpp2" // And a test for non-local UFCS, which shouldn't do a [&] capture -[[nodiscard]] auto f([[maybe_unused]] auto const& param1) -> int; +[[nodiscard]] auto f([[maybe_unused]] auto const& unnamed_param_1) -> int; extern int y; //=== Cpp2 function definitions ================================================= @@ -59,7 +59,7 @@ extern int y; CPP2_UFCS_0(no_return, 42); } -auto no_return([[maybe_unused]] auto const& param1) -> void{} +auto no_return([[maybe_unused]] auto const& unnamed_param_1) -> void{} [[nodiscard]] auto ufcs(cpp2::in i) -> int{ return i + 2; @@ -77,6 +77,6 @@ auto no_return([[maybe_unused]] auto const& param1) -> void{} } #line 40 "pure2-ufcs-member-access-and-chaining.cpp2" -[[nodiscard]] auto f([[maybe_unused]] auto const& param1) -> int { return 0; } +[[nodiscard]] auto f([[maybe_unused]] auto const& unnamed_param_1) -> int { return 0; } int y {CPP2_UFCS_0_NONLOCAL(f, 0)}; diff --git a/regression-tests/test-results/version b/regression-tests/test-results/version index 900f8ffd05..63bd94b254 100644 --- a/regression-tests/test-results/version +++ b/regression-tests/test-results/version @@ -1,5 +1,5 @@ -cppfront compiler v0.3.0 Build 8B07:1638 +cppfront compiler v0.3.0 Build 8B09:1419 Copyright(c) Herb Sutter All rights reserved SPDX-License-Identifier: CC-BY-NC-ND-4.0 diff --git a/source/build.info b/source/build.info index 2def373b0a..7498d68e66 100644 --- a/source/build.info +++ b/source/build.info @@ -1 +1 @@ -"8B07:1638" \ No newline at end of file +"8B09:1419" \ No newline at end of file diff --git a/source/sema.h b/source/sema.h index 21973839f2..12c456e14d 100644 --- a/source/sema.h +++ b/source/sema.h @@ -1000,6 +1000,34 @@ class sema } + auto check(parameter_declaration_node const& n) + -> bool + { + auto type_name = std::string{}; + if (n.declaration->has_declared_return_type()) { + type_name = n.declaration->get_object_type()->to_string(); + } + + if ( + n.ordinal == 2 + && !n.has_name("that") + && n.declaration->parent_declaration + && n.declaration->parent_declaration->has_name("operator=") + && n.declaration->parent_declaration->parent_declaration + && n.declaration->parent_declaration->parent_declaration->name() + && type_name == *n.declaration->parent_declaration->parent_declaration->name() + ) + { + errors.emplace_back( + n.position(), + "if an 'operator=' second parameter is of the same type (here '" + type_name + "'), it must be named 'that'" + ); + return false; + } + + return true; + } + auto check(declaration_node const& n) -> bool { diff --git a/source/to_cpp1.h b/source/to_cpp1.h index aa8cfcfc01..127a8e85f9 100644 --- a/source/to_cpp1.h +++ b/source/to_cpp1.h @@ -25,7 +25,7 @@ namespace cpp2 { -// Defined out of line here just to avoid bringing into the headers, +// Defined out of line here just to avoid bringing in before this, // so that we can't accidentally start depending on iostreams in earlier phases auto cmdline_processor::print(std::string_view s, int width) -> void @@ -3896,6 +3896,10 @@ class cppfront ) -> void { + if (!sema.check(n)) { + return; + } + // Can't declare functions as parameters -- only pointers to functions which are objects assert( n.declaration ); assert( !n.declaration->is_function() ); @@ -3904,6 +3908,10 @@ class cppfront return; } + assert( n.declaration->identifier ); + auto identifier = print_to_string( *n.declaration->identifier ); + auto identifier_pos = n.position(); + if (n.mod == parameter_declaration_node::modifier::implicit) { assert(!current_functions.empty()); @@ -3975,15 +3983,22 @@ class cppfront // Handle type parameters if (n.declaration->is_type()) { - printer.print_cpp2("typename ", n.declaration->identifier->position()); + assert( is_template_parameter ); + printer.print_cpp2("typename ", identifier_pos); if (n.declaration->is_variadic) { printer.print_cpp2( "...", - n.declaration->identifier->position() + identifier_pos ); } - assert (n.declaration->identifier); - emit(*n.declaration->identifier); + + if (identifier == "_") { + printer.print_cpp2( "UnnamedTypeParam" + std::to_string(n.ordinal), identifier_pos ); + } + else { + printer.print_cpp2( identifier, identifier_pos ); + } + return; } @@ -3996,8 +4011,7 @@ class cppfront if (is_template_parameter) { emit( type_id ); printer.print_cpp2(" ", type_id.position()); - assert (n.declaration->identifier); - emit(*n.declaration->identifier); + printer.print_cpp2( identifier, identifier_pos ); return; } @@ -4051,14 +4065,11 @@ class cppfront ) ; - assert( n.declaration->identifier ); - auto identifier = print_to_string( *n.declaration->identifier ); - // First any prefix if (identifier == "_") { - printer.print_cpp2( "[[maybe_unused]] ", n.position() ); - identifier = "param" + std::to_string(n.ordinal); + printer.print_cpp2( "[[maybe_unused]] ", identifier_pos ); + identifier = "unnamed_param_" + std::to_string(n.ordinal); } if ( @@ -4173,10 +4184,10 @@ class cppfront } if (is_returns) { - printer.print_extra( " " + identifier); + printer.print_extra( " " + identifier ); } else { - printer.print_cpp2( " ", n.declaration->identifier->position()); + printer.print_cpp2( " ", identifier_pos ); if (n.declaration->is_variadic) { if (n.direction() == passing_style::out) { @@ -4189,10 +4200,10 @@ class cppfront printer.print_cpp2( "...", - n.declaration->identifier->position() + identifier_pos ); } - printer.print_cpp2( identifier, n.declaration->identifier->position()); + printer.print_cpp2( identifier, identifier_pos ); } if (